public void EqualScoresAreNotBetterForEitherPlayer() { const int Score = 0; Assert.IsFalse(MoveScoreConverter.IsBetterFor(Score, Score, true)); Assert.IsFalse(MoveScoreConverter.IsBetterFor(Score, Score, false)); }
public void LowerScoreIsBetterForPlayerX() { const int PlayerXScore = 1; const int PlayerYScore = -1; Assert.IsFalse(MoveScoreConverter.IsBetterFor(PlayerYScore, PlayerXScore, true)); Assert.IsTrue(MoveScoreConverter.IsBetterFor(PlayerYScore, PlayerXScore, false)); }
public void WinIsBetterForPlayerY() { int winScoreX = MoveScoreConverter.ConvertWin(Occupied.PlayerX, 2); int winScoreY = MoveScoreConverter.ConvertWin(Occupied.PlayerY, 2); Assert.IsTrue(MoveScoreConverter.IsBetterFor(winScoreY, winScoreX, false)); Assert.IsFalse(MoveScoreConverter.IsBetterFor(winScoreY, winScoreX, true)); }
/// <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); }