public RecursiveDonutSearchNode(DonutGraph graph, string portal, int layer, string target, int cost, RecursiveDonutSearchNode parent = null) : base(cost, parent) { this.graph = graph; this.portal = portal; this.layer = layer; this.target = target; }
private static (Maze <string>, DonutGraph) BuildDonutMaze(string[] input) { IEnumerable <IEnumerable <string> > mazeInput = input.Reverse().Select(s => s.Select(c => c.ToString())); Maze <string> maze = new Maze <string>(mazeInput, " ", new List <string> { "." }, false); //Set up some properties of the maze int thickness = FindDonutThickness(input); int outerLeft = 2; int outerRight = input[0].Length - 3; int outerTop = input.Count() - 3; int outerBot = 2; int innerLeft = outerLeft + thickness; int innerRight = outerRight - thickness; int innerTop = outerTop - thickness; int innerBot = outerBot + thickness; var innerXBorder = new HashSet <int> { innerLeft, innerRight }; var innerYBorder = new HashSet <int> { innerTop, innerBot }; var outerXBorder = new HashSet <int> { outerLeft, outerRight }; var outerYBorder = new HashSet <int> { outerTop, outerBot }; //Locate the portals var floors = maze.FindAllMatchingTiles(".").ToList(); HashSet <string> nonPortalLabels = new HashSet <string> { ".", " ", "#" }; HashSet <string> portals = new HashSet <string>(); foreach ((int x, int y) in floors) { bool isOuterPortal = outerXBorder.Contains(x) || outerYBorder.Contains(y); bool isInnerPortal = (innerXBorder.Contains(x) && y <innerTop && y> innerBot) || (innerYBorder.Contains(y) && x <innerRight && x> innerLeft); if (isInnerPortal || isOuterPortal) { var part1 = maze.GetNeighbours(x, y).Where(kvp => !nonPortalLabels.Contains(kvp.Value)).First(); string portalName; if (part1.Key == Direction.North) { portalName = maze[x, y + 2] + maze[x, y + 1]; maze[x, y + 2] = " "; maze[x, y + 1] = " "; } else if (part1.Key == Direction.East) { portalName = maze[x + 1, y] + maze[x + 2, y]; maze[x + 1, y] = " "; maze[x + 2, y] = " "; } else if (part1.Key == Direction.South) { portalName = maze[x, y - 1] + maze[x, y - 2]; maze[x, y - 2] = " "; maze[x, y - 1] = " "; } else if (part1.Key == Direction.West) { portalName = maze[x - 2, y] + maze[x - 1, y]; maze[x - 1, y] = " "; maze[x - 2, y] = " "; } else { throw new Exception("Shouldn't reach this"); } portals.Add(portalName); maze[x, y] = isInnerPortal ? portalName + ":IN" : portalName + ":OUT"; } } //Create the graph var graph = new DonutGraph(thickness); var existingPortals = maze.GetAllTileTypes().Where(tile => tile.Length > 1).ToHashSet(); foreach (string portal in existingPortals) { graph.AddNode(portal); } foreach (var innerPortal in graph.Nodes().Where(portal => graph.IsInnerPortal(portal))) { var otherSide = graph.GetLabel(innerPortal) + ":OUT"; if (graph.ContainsNode(otherSide)) { graph.AddEdge(innerPortal, otherSide, 1); } } //For every portal set up the reachable locations foreach (string portal in existingPortals) { (int x, int y) = ((int, int))maze.FindFirstMatchingTile(portal); (int _, List <(string tile, int distance)> reachablePortals) = maze.FloodFillDistanceFinder(x, y, existingPortals); foreach ((string reachable, int distance) in reachablePortals) { graph.AddEdge(portal, reachable, distance); } } return(maze, graph); }