## Описание работы
Схема реализованных классов:

```mermaid
classDiagram
	class TextFileMazeBuilder {
        +buildFromFile(filename): Maze
    }
    class Maze {
        -cells: Cell[] 
        -width: int
        -height: int
        -start: Cell
        -exit: Cell
        +getCell(x,y): Cell
        +getNeighbors(cell): List~Cell~
    }
    
    class Cell {
        -x: int
        -y: int
        -isWall: bool
        -isStart: bool
        -isExit: bool
        -value: int
        +isPassable(): bool
        +getXY(): tuple[int, int]
        +toStr(): str
    }
    
    class MazeBuilder {
        <<interface>>
        +buildFromFile(filename): Maze
    }
    
    class PathFindingStrategy {
        <<interface>>
        +name(): str
        +findPath(maze, start, exit): tuple[list[tuple[int, int]], int]
    }
    
    class BFS {
	    +findPath(maze, start, exit): tuple[list[tuple[int, int]], int]
    }
    class DFS {
	    +findPath(maze, start, exit): tuple[list[tuple[int, int]], int]
    }
    class AStar {
	    +findPath(maze, start, exit): tuple[list[tuple[int, int]], int]
	    +heuristic(a, b): int
    }
    class Dijkstra {
	    +findPath(maze, start, exit): tuple[list[tuple[int, int]], int]
    }
    
    class SearchStats {
        -timeMs: float
        -visitedCells: int
        -pathLength: int
        -path: list~Cell~
    }
    
    class MazeSolver {
        -Maze maze
        -PathFindingStrategy strategy
        -Observer observer
        +strategyName: str
        +setStrategy(strategy)
        +solve(): SearchStats
    }
    
    class Observer {
        <<interface>>
        +update(event)
    }
    
    class ConsoleView {
        +update(event)
        +render(maze, player_position, path)
    }
    
    class Event {
	    -event: str
	    -maze: Maze
	    -player_position: tuple[int,int]
	    -path: list~Cell~
    }
    
    MazeBuilder <|.. TextFileMazeBuilder
    MazeBuilder --> Maze : creates
    PathFindingStrategy <|.. BFS
    PathFindingStrategy <|.. DFS
    PathFindingStrategy <|.. AStar
    PathFindingStrategy <|.. Dijkstra
    MazeSolver --> PathFindingStrategy : uses
    MazeSolver --> Maze : uses
    Maze --> Cell : uses
    MazeSolver --> SearchStats : return
    Observer <|.. ConsoleView
    ConsoleView --> Event : get
    MazeSolver --> Observer : notifies
```
1. Листинги ключевых классов (можно выборочно) или ссылка на репозиторий.
- Классы `Cell` и `Maze` представлены в папке `source/classes/`
- Реализации интерфейса `Builder` и класса `TextFileMazeBuilder` находятся в `source/builder/`
- Реализации интерфейса `Observer` и класса `ConsoleView` находятся в `source/observer/`
- Интерфейс `strategy`, класс `MazeSolver` и реализации алгоритмов BFS, DFS, A*, Дейкстра находятся в папке `source/strategy/`
## Результаты экспериментов
Все результаты находятся в `/data/cvs/banchmark.csv`, тесты запускаются через файл `benchmark.ipynb`. Лабиринты, на которых проходили тесты, находятся в директори `mazes/benchmarks/`
Проведём 10 замеров и отобразим результаты на графиках (пунктиром отмечены среднее значение)
![[10x10.pdf]]
![[50x50.pdf]]
![[100x100.pdf]]
![[empty.pdf]]
![[no_path.pdf]]

Заполним таблицу для количества посещённых клеток для каждого алгоритма:

|    Лабиринт    | BFS  | DFS  | A*   | Дейкстра |
| :------------: | :--: | :--: | :--: | :------: |
|  $10\times10$  |  25  |  24  |  24  |    25    |
|  $50\times50$  | 972  | 920  | 763  |   972    |
| $100\times100$ | 2345 | 2609 | 1194 |   2345   |
|     Пустой     | 5328 | 5328 | 5328 |   5328   |
|   Без выхода   | 1245 | 1245 | 1245 |   1245   

## Анализ результатов
- **DFS** быстрее на большинстве лабиринтов, но путь может быть неоптимальным 
В качестве демонстрации, сравним работу DFS и BFS на небольшом пустом лабиринте:
```
BFS
Путь найден:
#####################################
#S                                  #
#.                                  #
#.                                  #
#.                                  #
#.                                  #
#.                                  #
#.                                  #
#.                                  #
#..................................E#
#####################################
time: 0.8261000002676155 ms
visited cells: 315
path length: 43
```
```
DFS
Путь найден:
#####################################
#S..................................#
#                                  .#
#...................................#
#.                                  #
#...................................#
#                                  .#
#...................................#
#.                                  #
#..................................E#
#####################################
time: 0.6825999989814591 ms
visited cells: 315
path length: 179
```
Как видно по примеру DFS нашёл путь быстрее (0.68 против 0.82 мс), но длина найденного маршрута 179 клеток, в то время как путь, найденный BFS состоит из 43 клеток.
#### A*:
- По таблице видно, что A* проходит меньше всего клеток. Это происходит, так как идея алгоритма в том что он отдаёт приоритет клеткам, которые ближе к цели. 
- На практике медленнее DFS из-за операций с кучей (O(log n) на каждый шаг)

#### Dijkstra:
- По сложности аналогичен BFS для лабиринтов без весов, но медленнее BFS из-за приоритетной очереди.
- Имеет смысл на взвешенных графах

## Выводы
Использование ООП и паттернов дало:
- расширяемость - лёгкость добавления нового алгоритма поиска без изменения текущей структуры и существующих классов 
- гибкость - можно менять алгоритмы поиска, конструкторы лабиринтов и способы отображения так же без изменения уже существующих
- Лёгкость тестирования - можно тестировать каждый элемент независимо
Без этого было бы сложно внедрять новые реализации классов, способы отображения или создания лабиринта или изменять существующие алгоритмы.
Но реализация интерфейсов и унификация классов увеличили объём кода и так же наложили ограничения на обрабатываемые данные.  

По скорости лучшим по большинству тестов стал DFS. Второй по скорости BFS, так же он находит самый короткий путь, но при усложнении лабиринта(увеличении развилок и размера) начинает проигрывать A*. 