private static void PlayerScoreBlankBoard(IPathLengthFactory pathLengthFactory) { HexBoard hexBoard = new HexBoard(BoardSize); PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard); // blank board int xScore = pathLength.PlayerScore(true); int yScore = pathLength.PlayerScore(false); Assert.AreEqual(xScore, yScore, "x and y score"); // no advantage int equalMoveScore = pathLength.SituationScore(); Assert.AreEqual(equalMoveScore, 0, "equalMoveScore"); // all cells still on the clean path pathLength.PlayerScore(true); List <Location> cleanPathX = pathLength.GetCleanPath(true); pathLength.PlayerScore(false); List <Location> cleanPathY = pathLength.GetCleanPath(false); const int AllCellsCount = BoardSize * BoardSize; Assert.AreEqual(AllCellsCount, cleanPathX.Count, "Clean path x should have all cells"); Assert.AreEqual(AllCellsCount, cleanPathY.Count, "Clean path y should have all cells"); }
private static void PlayerScoreZigZag(IPathLengthFactory pathLengthFactory) { HexBoard hexBoard = new HexBoard(BoardSize); PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard); for (int y = 0; y < hexBoard.Size - 1; y++) { hexBoard.PlayMove(2, y, true); hexBoard.PlayMove(5, hexBoard.Size - (1 + y), true); int xScore = pathLength.PlayerScore(true); Assert.IsTrue(xScore > 0); int yScore = pathLength.PlayerScore(false); Assert.IsTrue(yScore >= hexBoard.Size); if (y > (hexBoard.Size / 2)) { Assert.IsTrue(yScore > xScore); } // some advantage to player 1 int advantageMoveScore = pathLength.SituationScore(); Assert.IsTrue(advantageMoveScore >= y); } }
private static void PlayerScorePartBarricade(IPathLengthFactory pathLengthFactory) { HexBoard hexBoard = new HexBoard(BoardSize); PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard); // partly baricaded board for (int y = 0; y < hexBoard.Size; y++) { if ((y % 2) == 0) { hexBoard.PlayMove(2, y, true); } } int xScore = pathLength.PlayerScore(true); Assert.IsTrue(xScore > 0); int yScore = pathLength.PlayerScore(false); Assert.IsTrue(yScore > xScore); // some advantage to player 1 int advantageMoveScore = pathLength.SituationScore(); Assert.IsTrue(advantageMoveScore > 0); }
/// <summary> /// Initializes a new instance of the HexGame class, with a board size /// </summary> /// <param name="boardSize">size of the board</param> /// ******** public HexGame(int boardSize) { this.board = new HexBoard(boardSize); IPathLengthFactory pathLengthFactory = new PathLengthAStarFactory(); this.xPathLength = pathLengthFactory.CreatePathLength(this.board); this.yPathLength = pathLengthFactory.CreatePathLength(this.board); this.goodMoves = new GoodMoves(); this.goodMoves.DefaultGoodMoves(boardSize, 5); }
private static void PlayerScoreBaricaded(IPathLengthFactory pathLengthFactory) { HexBoard hexBoard = new HexBoard(BoardSize); PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard); // baricaded board for (int y = 0; y < hexBoard.Size; y++) { hexBoard.PlayMove(2, y, true); } int xScore = pathLength.PlayerScore(true); Assert.AreEqual(xScore, 0); int yScore = pathLength.PlayerScore(false); Assert.IsTrue(yScore > hexBoard.Size); // winning advantage to player 1 int winMoveScore = pathLength.SituationScore(); AssertWinner(winMoveScore, Occupied.PlayerX); }
private MinimaxResult MiniMaxAlg(int depth, bool isComputer, HexBoard board) { BoardCache boardCache = new BoardCache(board.Size); MinimaxResult bestResult = null; Location cutOffMove = Location.Null; // az ures cellakat tartalmazza var possibleMoves = candidateMovesFinder.CandidateMoves(board, depth); foreach (Location move in possibleMoves) { if (!move.IsNull()) { // nem az eredetit modositom meg, hanem letrehozok egyet a peldajara HexBoard board1 = new HexBoard(board.Size); board1.CopyStateFrom(board); board1.PlayMove(move, isComputer); // itt szamolja ki az allast PathLengthBase staticAnalysis = this.pathLengthFactory.CreatePathLength(board1); int situationScore = staticAnalysis.SituationScore(); MinimaxResult moveScore = new MinimaxResult(situationScore); if (depth <= 1 || MoveScoreConverter.IsWin(situationScore)) { moveScore = new MinimaxResult(situationScore); } else { if (depth > 1) { // rekurzio moveScore = MiniMaxAlg(depth--, !isComputer, board1); moveScore.MoveWins(); } } moveScore.Move = move; // Itt nezem meg, hogy a minimum kell nekunk, vagy a maximum if (bestResult == null || MoveScoreConverter.MinOrMax(moveScore.Score, bestResult.Score, isComputer)) { bestResult = new MinimaxResult(move, moveScore); } alpha = CheckAlpha(moveScore.Score, isComputer); if (IsAlphaBetaCutoff(isComputer)) { cutOffMove = move; bestResult.Score = alpha; break; } } else { break; } } if (bestResult != null) { GoodMoves.AddGoodMove(depth, bestResult.Move); } if (cutOffMove != Location.Null) { GoodMoves.AddGoodMove(depth, cutOffMove); } return(bestResult); }
/// <summary> /// private recursive worker - does the minimax algorithm /// </summary> /// <param name="lookahead">the current ply, counts down to zero</param> /// <param name="stateBoard">the current board</param> /// <param name="isPlayerX">player X or player Y</param> /// <param name="alpha">alpha value used in alpha-beta pruning</param> /// <param name="beta">beta value used in alpha-beta pruning</param> /// <returns>the score of the board and best move location</returns> private MinimaxResult ScoreBoard( int lookahead, HexBoard stateBoard, bool isPlayerX, int alpha, int beta) { this.CountBoards++; MinimaxResult bestResult = null; Location cutoffMove = Location.Null; var possibleMoves = this.candidateMovesFinder.CandidateMoves(stateBoard, lookahead); foreach (Location move in possibleMoves) { // end on null loc if (move.IsNull()) { break; } if (this.GenerateDebugData) { this.AddDebugDataItem(lookahead, move, isPlayerX, alpha, beta); } // make a speculative board, like the current, but with this cell played HexBoard testBoard = this.boardCache.GetBoard(); testBoard.CopyStateFrom(stateBoard); testBoard.PlayMove(move, isPlayerX); MinimaxResult moveScore; PathLengthBase staticAnalysis = this.pathLengthFactory.CreatePathLength(testBoard); int situationScore = staticAnalysis.SituationScore(); if (lookahead <= 1) { // we have reached the limits of lookahead - return the situation score moveScore = new MinimaxResult(situationScore); } else if (MoveScoreConverter.IsWin(situationScore)) { // stop - someone has won moveScore = new MinimaxResult(situationScore); } else { // recurse moveScore = this.ScoreBoard(lookahead - 1, testBoard, !isPlayerX, beta, alpha); moveScore.MoveWins(); } moveScore.Move = move; this.boardCache.Release(testBoard); // higher scores are good for player x, lower scores for player y if (bestResult == null || MoveScoreConverter.IsBetterFor(moveScore.Score, bestResult.Score, isPlayerX)) { bestResult = new MinimaxResult(move, moveScore); } // do the alpha-beta pruning alpha = CheckAlpha(alpha, moveScore.Score, isPlayerX); if (IsAlphaBetaCutoff(isPlayerX, alpha, beta)) { cutoffMove = move; bestResult.Score = alpha; break; } // end a-b pruning } if (bestResult != null) { GoodMoves.AddGoodMove(lookahead, bestResult.Move); } if (cutoffMove != Location.Null) { GoodMoves.AddGoodMove(lookahead, cutoffMove); } return(bestResult); }