namespace Day17; public class Map { private readonly Tile[,] _tiles; private readonly int _width; private readonly int _height; private Func _pathFactory; public Map(Tile[,] tiles, int width, int height) { _tiles = tiles; _width = width; _height = height; _pathFactory = (path, tile, vRun) => new Path(path, tile, vRun); } public void Print() { for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { Console.Write(_tiles[x, y].Display); _tiles[x, y].ClearDisplay(); } Console.WriteLine(); } Console.WriteLine(); } public int ShortestPath() { var goal = _tiles[_width - 1, _height - 1]; var visited = new HashSet(); var queue = new PriorityQueue(); queue.Enqueue(_pathFactory(null, _tiles[0, 0], new Vec(1, 0)), 0); queue.Enqueue(_pathFactory(null, _tiles[0, 0], new Vec(0, 1)), 0); while (queue.Count > 0) { var current = queue.Dequeue(); var curKey = current.GetKey(); if (!visited.Add(curKey)) { continue; } foreach (var v in current.Next()) { var pos = current.Tile.Position.Add(v); if (IsValid(pos)) { var next = _pathFactory(current, Tile(pos), v); if (next.Tile == goal && next.CanStop()) { var cost = Backtrack(next); return cost; } queue.Enqueue(next, next.Cost); } } } return -1; } public void SetUltraPathMode() { _pathFactory = (path, tile, vRun) => new UltraPath(path, tile, vRun); } private int Backtrack(Path path) { var sum = 0; while (path.Prev != null) { sum += path.Tile.Cost; path.Tile.SetDisplay(path.VRun.Arrow()); path = path.Prev; } return sum; } private bool IsValid(Vec position) { return position.X >= 0 && position.X < _width && position.Y >= 0 && position.Y < _height; } private Tile Tile(Vec position) { return _tiles[position.X, position.Y]; } }