public static IList <GridPoint> GetRobotPathBetweenMazeStates(MazeState startState, MazeState endState) { int positionIndex = GetPositionThatChangedIndex(startState, endState); var edgeKey = new Tuple <GridPoint, GridPoint>( startState.CurrentPositions[positionIndex], endState.CurrentPositions[positionIndex]); var shortestPath = startState.Maze.ShortestPathsBetweenKeysIgnoringDoors[edgeKey]; //int Heuristic(GridPoint currentCell) //{ // return GridPoint.GetManhattanDistance(currentCell, endState.CurrentPositions[positionIndex]); //} //bool GetCanEnterNode(GridPoint point) //{ // return startState.Maze.GetCanEnterCell(point, startState.KeysCollected); //} //var pathAlongNodes = startState.Maze.MazeGraph.GetShortestPathViaNodes( // start: startState.CurrentPositions[positionIndex], // end: endState.CurrentPositions[positionIndex], // Heuristic: Heuristic, // GetCanEnterNode: GetCanEnterNode); //var shortestPath = startState.Maze.GetRobotPathFromNodePath(pathAlongNodes.Path); return(shortestPath); }
public static int GetPositionThatChangedIndex(MazeState s1, MazeState s2) { for (int positionThatChangedIndex = 0; positionThatChangedIndex < s1.CurrentPositions.Count; positionThatChangedIndex++) { if (!s1.CurrentPositions[positionThatChangedIndex].Equals( s2.CurrentPositions[positionThatChangedIndex])) { return(positionThatChangedIndex); } } return(-1); }
public static int GetDay18Part2Answer() { // After updating your map and using the remote-controlled robots, // what is the fewest steps necessary to collect all of the keys? // Answer: 1538 var mazeDefinition = GetDay18Input(); var maze = new Maze(mazeDefinition, true); var initialMazeState = new MazeState(maze, maze.StartingPositions, new SortedDictionary <string, string>()); initialMazeState.DrawMazeState(); var shortestPath = GetShortestPathToCollectAllKeys(maze); Console.WriteLine($"{MazeState.GetPathString(shortestPath.Path, false)}"); var result = shortestPath.TotalPathCost; return(result); }
public static int GetDay18Part1Answer() { // How many steps is the shortest path that collects all of the keys? // Answer: 3216 var mazeDefinition = GetDay18Input(); var maze = new Maze(mazeDefinition); var initialMazeState = new MazeState(maze, maze.StartingPositions, new SortedDictionary <string, string>()); initialMazeState.DrawMazeState(); var shortestPath = GetShortestPathToCollectAllKeys(maze); Console.WriteLine($"{MazeState.GetPathString(shortestPath.Path, false)}"); var result = shortestPath.TotalPathCost; //var result = 3216; return(result); }
/// <summary> /// Retrieves all neighboring maze states that can be reached by moving /// the given position. /// </summary> /// <param name="positionIndex"></param> /// <returns></returns> private IList <Tuple <MazeState, int, int> > GetNeighboringMazeStatesWithCostsForPosition(int positionIndex) { var result = new List <Tuple <MazeState, int, int> >(); var currentPosition = CurrentPositions[positionIndex]; foreach (var targetKey in Maze.Keys) { if (KeysCollected.ContainsKey(targetKey)) { continue; } var targetKeyCell = Maze.KeyCells[targetKey]; // SIMPLIFYING ASSUMPTION: // The shortest paths between all pairs of keys when ignoring // doors always yields the ultimate shortest path var edgeKey = new Tuple <GridPoint, GridPoint>(currentPosition, targetKeyCell); if (!Maze.ShortestPathsBetweenKeysIgnoringDoors.ContainsKey(edgeKey)) { continue; } bool canReachTarget = true; foreach (var door in Maze.DoorsAlongShortestPathBetweenKeys[edgeKey]) { if (!KeysCollected.ContainsKey(door.ToLower())) { canReachTarget = false; } } if (!canReachTarget) { continue; } var shortestPath = Maze.ShortestPathsBetweenKeysIgnoringDoors[edgeKey]; var totalCost = shortestPath.Count - 1; var keysCollectedAlongPath = Maze.GetKeysAlongPath(shortestPath); //// THIS CODE WORKS IN THE GENERAL CASE WHEN THE SIMPLIFYING ASSUMPTION IS NOT MET //int Heuristic(GridPoint currentCell) //{ // return GridPoint.GetManhattanDistance(currentCell, targetKeyCell); //} //bool GetCanEnterNode(GridPoint point) //{ // return Maze.GetCanEnterCell(point, KeysCollected); //} //var nodePathToTargetKeyCell = Maze.MazeGraph.GetShortestPathViaNodes( // start: currentPosition, // end: targetKeyCell, // Heuristic: Heuristic, // GetCanEnterNode: GetCanEnterNode); //if (nodePathToTargetKeyCell.Path.Count == 0) // continue; //var keysCollectedAlongPath = Maze.GetKeysCollectedAlongNodePath(nodePathToTargetKeyCell.Path); //var shortestPath = Maze.GetRobotPathFromNodePath(nodePathToTargetKeyCell.Path); //var totalCost = shortestPath.Count - 1; var endKeysCollected = new SortedDictionary <string, string>(KeysCollected); foreach (var key in keysCollectedAlongPath) { if (!endKeysCollected.ContainsKey(key)) { endKeysCollected.Add(key, key); } } var finalPositions = CurrentPositions.ToList(); finalPositions[positionIndex] = targetKeyCell; var newMazeState = new MazeState( maze: Maze, currentPositions: finalPositions, keysCollected: endKeysCollected); var resultEntry = new Tuple <MazeState, int, int>( newMazeState, totalCost, positionIndex); result.Add(resultEntry); } return(result); }
public static PathResult <MazeState> GetShortestPathToCollectAllKeys(Maze maze) { var initialMazeState = new MazeState(maze, maze.StartingPositions, new SortedDictionary <string, string>()); var allKeysDictionary = maze.Keys.ToDictionary(k => k, k => k); var finalMazeState = new MazeState(maze, maze.StartingPositions, new SortedDictionary <string, string>(allKeysDictionary)); var edgeCosts = new Dictionary <Tuple <string, string>, int>(); var edgePositionIndexes = new Dictionary <Tuple <string, string>, int>(); int averageManhattanDistanceBetweenKeys = maze.GetAverageManhattanDistanceBetweenKeys(); int sqrtOfTotalKeys = (int)Math.Sqrt(maze.Keys.Count); int Heuristic(MazeState state) { return(state.Maze.Keys.Count - state.KeysCollected.Count); } IList <MazeState> GetNeighbors(MazeState mazeState) { var result = new List <MazeState>(); var neighboringStatesWithRobotPaths = mazeState.GetNeighboringMazeStatesWithCosts(); foreach (var neighboringStateWithCost in neighboringStatesWithRobotPaths) { // Get the new key reached by the position that moved // from the current state to this neighbor var edgeKey = new Tuple <string, string>( mazeState.MazeStateSignature, neighboringStateWithCost.Item1.MazeStateSignature); if (!edgeCosts.ContainsKey(edgeKey)) { edgeCosts.Add(edgeKey, int.MaxValue); } edgeCosts[edgeKey] = neighboringStateWithCost.Item2; if (!edgePositionIndexes.ContainsKey(edgeKey)) { edgePositionIndexes.Add(edgeKey, 0); } edgePositionIndexes[edgeKey] = neighboringStateWithCost.Item3; result.Add(neighboringStateWithCost.Item1); } return(result); } int GetEdgeCost(MazeState s1, MazeState s2) { var edgeKey = new Tuple <string, string>( s1.MazeStateSignature, s2.MazeStateSignature); if (!edgeCosts.ContainsKey(edgeKey)) { throw new Exception("Edge not in edge costs map"); } return(edgeCosts[edgeKey]); } var result = AStar.GetPath <MazeState>( startPoint: initialMazeState, endPoint: finalMazeState, Heuristic: Heuristic, GetNeighbors: GetNeighbors, GetEdgeCost: GetEdgeCost); return(result); }