Beispiel #1
0
        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);
        }
Beispiel #2
0
 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);
 }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        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);
        }