public List<Step[]> GetSolution(BoardState state, BoardGoal goal, CancellationToken cancellationToken) { if (state == null) { throw new ArgumentNullException(nameof(state)); } if (goal == null) { throw new ArgumentNullException(nameof(goal)); } if (state.Width != goal.Width || state.Height != goal.Height) { throw new ArgumentException($"The state ({state.Width}x{state.Height}) and the goal ({goal.Width}x{goal.Height}) has different sizes."); } PriorityQueueV1 openSet = new PriorityQueueV1(); openSet.Enqueue(NodeV1.CreateInitialNode(state, goal)); while (true) { NodeV1 current = openSet.Dequeue(); if (current.State.Satisfies(goal)) { return new List<Step[]> { GetPathFrom(current).Reverse().ToArray() }; } foreach (NodeV1 neighbor in current.GetNeighbors(goal)) { openSet.Enqueue(neighbor); } cancellationToken.ThrowIfCancellationRequested(); } }
private NodeV1(NodeV1 parentNode, Step previousStep, BoardState state, int distanceFromInitialNode, int estimatedDistanceToGoal) { this.ParentNode = parentNode; this.PreviousStep = previousStep; this.State = state; this.distanceFromInitialNode = distanceFromInitialNode; this.Cost = distanceFromInitialNode + estimatedDistanceToGoal; }
public List<Step[]> GetSolution(BoardState state, BoardGoal goal, CancellationToken cancellationToken) { if (state == null) { throw new ArgumentNullException(nameof(state)); } if (goal == null) { throw new ArgumentNullException(nameof(goal)); } if (state.Width != goal.Width || state.Height != goal.Height) { throw new ArgumentException($"The state ({state.Width}x{state.Height}) and the goal ({goal.Width}x{goal.Height}) has different sizes."); } List<Step[]> solutions = new List<Step[]>(); int targetCost = int.MaxValue; PriorityQueueV5 openSet = new PriorityQueueV5(); openSet.Enqueue(NodeV5.CreateInitialNode(state, goal)); while (true) { NodeV5 current = openSet.Dequeue(); if (current.Cost > targetCost) { break; } if (current.EstimatedDistanceToGoal == 0) { Step[] solution = GetPathFrom(current).Reverse().ToArray(); solutions.Add(solution); if (solution.Length < targetCost) { targetCost = solution.Length; } continue; } foreach (NodeV5 neighbor in current.GetNeighbors(goal)) { if (!openSet.Contains(neighbor)) { openSet.Enqueue(neighbor); } } cancellationToken.ThrowIfCancellationRequested(); } return solutions; }
public void Test1() { // Arrange BoardState state = new BoardState(3, 3, new[] { 1, 2, 0, 4, 5, 3, 7, 8, 6 }); BoardGoal goal = BoardGoal.CreateCompleted(3, 3); IBoardSolverService solver = new BoardSolverService(); // Act Step[] steps = solver.GetSolution(state, goal, CancellationToken.None)[0]; // Assert CollectionAssert.AreEqual(new[] { Step.Up, Step.Up }, steps); }
public GameService([NotNull] IMessageBus messageBus, [NotNull] IBoardGeneratorService boardGeneratorService) { if (messageBus == null) { throw new ArgumentNullException(nameof(messageBus)); } if (boardGeneratorService == null) { throw new ArgumentNullException(nameof(boardGeneratorService)); } this.messageBus = messageBus; this.boardGeneratorService = boardGeneratorService; this.drill = Drill.CreateNew("Default", BoardTemplate.CreateEmpty(4, 4), BoardGoal.CreateCompleted(4, 4)); this.InitialState = this.boardGeneratorService.Generate(this.drill.Template, this.drill.Goal); this.boardState = this.InitialState; }
public void Scramble() { this.InitialState = this.boardGeneratorService.Generate(this.drill.Template, this.drill.Goal); this.BoardState = this.InitialState; this.messageBus.Publish(new BoardScrambled()); }
private static int GetManhattanDistance(BoardState state, BoardGoal goal) { int width = state.Width; int height = state.Height; int sum = 0; for (int i = 0; i < goal.TileCount; i++) { if (goal[i] == 0) { continue; } for (int j = 0; j < state.TileCount; j++) { if (state[j] == goal[i]) { int x1 = i % width; int y1 = i / height; int x2 = j % width; int y2 = j / height; sum += Math.Abs(x1 - x2) + Math.Abs(y1 - y2); break; } } } return sum; }
public static NodeV1 CreateInitialNode(BoardState state, BoardGoal goal) { return new NodeV1(state, GetManhattanDistance(state, goal)); }
private NodeV1(BoardState state, int estimatedDistanceToGoal) { this.State = state; this.Cost = estimatedDistanceToGoal; }
private NodeV1 CreateNeighbor(Step previousStep, BoardState newState, BoardGoal goal) { return new NodeV1(this, previousStep, newState, this.distanceFromInitialNode + 1, GetManhattanDistance(newState, goal)); }
private void OnSolved(BackgroundJob job, Step[][] solutions) { if (job.CancellationTokenSource.IsCancellationRequested) { return; } this.Status = SolverServiceStatus.Solved; this.Solutions = solutions .OrderBy(solution => string.Join(",", solution)) .Select(solution => solution.Select(step => new SolutionStep(step, SolutionStepStatus.NotSteppedYet)).ToList()) .ToList(); this.SolutionLength = solutions[0].Length; this.nextStepIndex = 0; this.solvedBoardState = job.StateToSolve; this.messageBus.Publish(new SolutionsFound(job.InitialState, job.StateToSolve, solutions)); }
public static SimplifiedBoardState Create(BoardState state, BoardGoal goal) { int[] values = new int[state.TileCount]; int eye = 0; for (int i = 0; i < state.TileCount; i++) { if (state[i] == 0) { eye = i; values[i] = -1; continue; } for (int j = 0; j < goal.TileCount; j++) { if (state[i] == goal[j]) { values[i] = state[i]; break; } } } return new SimplifiedBoardState(state.Width, state.Height, values, eye); }