public void testFinishedGameScoreNoPieces() { // Generate a board which is lost via the 'no pieces remain' rule, and verify // we get the correct score. DoktorChessAIBoard ourboard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); ourboard.addPiece(pieceType.pawn, pieceColour.black, 1, 1); // position is lost for white.. BoardScorer whiteScorer = new BoardScorer(ourboard, pieceColour.white, new scoreModifiers()); Assert.AreEqual(BoardScorer.lowest, whiteScorer.getScore()); // and won for black. BoardScorer blackScorer = new BoardScorer(ourboard, pieceColour.black, new scoreModifiers()); Assert.AreEqual(BoardScorer.highest, blackScorer.getScore()); }
public lineAndScore(move[] newLine, int newFinalScore, BoardScorer scorer) { line = newLine; finalScore = newFinalScore; _scorer = scorer; }
public void testFinishedGameScoreStalemate() { // Generate a board two pawns, deadlocked in front of each other. This should // be a draw via stalemate. Add a third pawn to ensure that stalemate is causing // the '0' board score, not a materian mismatch. DoktorChessAIBoard ourboard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); // Two deadlocked pawns ourboard.addPiece(pieceType.pawn, pieceColour.white, 1, 2); ourboard.addPiece(pieceType.pawn, pieceColour.black, 1, 3); // an outlier pawn ourboard.addPiece(pieceType.pawn, pieceColour.black, 4, 4); Assert.IsTrue(ourboard.getGameStatus(pieceColour.white) == gameStatus.drawn); Assert.IsTrue(ourboard.getGameStatus(pieceColour.black) == gameStatus.drawn); BoardScorer whiteScorer = new BoardScorer(ourboard, pieceColour.white, new scoreModifiers()); Assert.AreEqual(0, whiteScorer.getScore()); BoardScorer blackScorer = new BoardScorer(ourboard, pieceColour.black, new scoreModifiers()); Assert.AreEqual(0, blackScorer.getScore()); }
private void verifyWonForWhite(DoktorChessAIBoard ourBoard, pieceColour wonCol) { pieceColour lostCol = DoktorChessAIBoard.getOtherSide(wonCol); // The position should be won/lost for white/black, respectively Assert.IsTrue(ourBoard.getGameStatus(wonCol) == gameStatus.won); Assert.IsTrue(ourBoard.getGameStatus(lostCol) == gameStatus.lost); // and this should be reflected in the scores BoardScorer whiteScorer = new BoardScorer(ourBoard, wonCol, new scoreModifiers()); Assert.AreEqual(BoardScorer.highest, whiteScorer.getScore()); // and won for black. BoardScorer blackScorer = new BoardScorer(ourBoard, lostCol, new scoreModifiers()); Assert.AreEqual(BoardScorer.lowest, blackScorer.getScore()); }
public void testScoreWithDangling() { DoktorChessAIBoard ourboard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); ourboard.addPiece(pieceType.pawn, pieceColour.black, 3, 3); ourboard.addPiece(pieceType.queen, pieceColour.white, 2, 2); ourboard.addPiece(pieceType.king, pieceColour.black, 7, 7); ourboard.addPiece(pieceType.king, pieceColour.white, 5, 5); BoardScorer whiteScorer = new BoardScorer(ourboard, pieceColour.white, new scoreModifiers()); // White's queen is dangling, as is blacks pawn. int expected = whiteScorer.modifiers.materialModifier * (8 - 1); expected -= whiteScorer.modifiers.danglingModifier * 8; expected += whiteScorer.modifiers.danglingModifier * 1; Assert.AreEqual(expected, whiteScorer.getScore()); }
public void testMaterialAdvantage() { // Generate a boardScorer and present it with a queen (ours), and two pawns // (enemy). Verify the resultant score as 8-2 = 6. DoktorChessAIBoard ourboard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); ourboard.addPiece(pieceType.queen, pieceColour.white, 1, 1); ourboard.addPiece(pieceType.pawn, pieceColour.black, 3, 4); ourboard.addPiece(pieceType.pawn, pieceColour.black, 3, 5); BoardScorer myscorer = new BoardScorer(ourboard, pieceColour.white, new scoreModifiers()); // Check only material advantage myscorer.modifiers.danglingModifier = 0; myscorer.modifiers.materialModifier = 1; Assert.AreEqual(8 - 2, myscorer.getScore()); }
public void testFinishedGameScoreStalemate_example() { // Specific situation that was broken. It's black-to-play stalemate. DoktorChessAIBoard ourboard = DoktorChessAIBoard.makeNormalFromFEN("5B2/6P1/8/1p6/1N6/kP6/2K5/8 b - - 0 0", boardSearchConfig.getDebugConfig()); Assert.IsTrue(ourboard.getGameStatus(pieceColour.white) == gameStatus.drawn); Assert.IsTrue(ourboard.getGameStatus(pieceColour.black) == gameStatus.drawn); BoardScorer whiteScorer = new BoardScorer(ourboard, pieceColour.white, new scoreModifiers()); Assert.AreEqual(0, whiteScorer.getScore()); BoardScorer blackScorer = new BoardScorer(ourboard, pieceColour.black, new scoreModifiers()); Assert.AreEqual(0, blackScorer.getScore()); }
private lineAndScore findBestMove(bool usToPlay, int depthLeft, int min, int max) { if (getGameStatus(colToMove) != gameStatus.inProgress) { // The game is over. Return a score immediately, and no moves. stats.boardsScored++; BoardScorer scorer = new BoardScorer(this, colToMove, _searchConfig.scoreConfig); //return new lineAndScore(new move[] { }, scorer.getScore() - (searchConfig.searchDepth - depthLeft), scorer); int score = scorer.getScore() * -1; return new lineAndScore(new move[] { }, score, scorer); } // Find our best move and its score. Initialise the best score to max or min, // depending if we're searching for the minimum or maximum score. lineAndScore bestLineSoFar; if (usToPlay) bestLineSoFar = new lineAndScore(new move[_searchConfig.searchDepth + 1], int.MinValue, null); else bestLineSoFar = new lineAndScore(new move[_searchConfig.searchDepth + 1], int.MaxValue, null); // Find a list of possible moves.. sizableArray<move> movesToConsider = getMoves(colToMove); if (_searchConfig.checkLots) { if (movesToConsider.Length == 0) { // This should totally and absolutely not happen after we've verified that the // game is still in progress. throw new ArgumentException(); } bool valid = false; foreach (move thisMove in movesToConsider) { if (valid) break; doMove(thisMove); if (!isPlayerInCheck(colToMove)) valid = true; undoMove(thisMove); } // Niether should this. if (!valid) throw new ArgumentException(); } // Move any good (possibly killer) moves to the top of our search prioritizeMoves(movesToConsider, depthLeft); foreach (move consideredMove in movesToConsider) { // If we're checking heavily, we check that the board is restored correctly after we // undo any move. string origThreatMap = null; string origPieces = null; if (_searchConfig.checkLots) { origThreatMap = coverLevel.ToString(); origPieces = ToString(); } pieceColour movingSide = colToMove; doMove(consideredMove); // If this move would leave us in check, we can ignore it // TODO: optimise this. if (isPlayerInCheck(movingSide)) { undoMove(consideredMove); continue; } if (depthLeft == 0) { stats.boardsScored++; BoardScorer scorer = new BoardScorer(this, movingSide, _searchConfig.scoreConfig); int score = scorer.getScore(); if ((usToPlay && (score > bestLineSoFar.finalScore)) || (!usToPlay && (score < bestLineSoFar.finalScore))) { bestLineSoFar.finalScore = score; bestLineSoFar.line[_searchConfig.searchDepth] = consideredMove; bestLineSoFar._scorer = scorer; } } else { lineAndScore thisMove = findBestMove(!usToPlay, depthLeft - 1, min, max); if ((usToPlay && (thisMove.finalScore > bestLineSoFar.finalScore)) || (!usToPlay && (thisMove.finalScore < bestLineSoFar.finalScore))) { bestLineSoFar.finalScore = thisMove.finalScore; bestLineSoFar._scorer = thisMove._scorer; bestLineSoFar.line[_searchConfig.searchDepth - depthLeft] = consideredMove; for (int index = 0; index < thisMove.line.Length; index++) { if (thisMove.line[index] != null) bestLineSoFar.line[index] = thisMove.line[index]; } } } undoMove(consideredMove); // Verify that the board has been restored to its former state correctly. if (_searchConfig.checkLots) { if (origPieces != ToString()) throw new Exception("Board pieces were not restored correctly"); if (origThreatMap != coverLevel.ToString()) { Debug.WriteLine("Move : " + consideredMove.ToString()); Debug.WriteLine("expected"); Debug.WriteLine(origThreatMap); Debug.WriteLine("actual"); Debug.WriteLine(coverLevel.ToString()); throw new Exception("Threat map was not restored correctly"); } } if (_searchConfig.useAlphaBeta) { if (depthLeft > 0) { if (usToPlay) { if (min < bestLineSoFar.finalScore) min = bestLineSoFar.finalScore; if (min >= max) { if (_searchConfig.killerHeuristic) { _killerStore.add(depthLeft, consideredMove); } break; } } else { if (max > bestLineSoFar.finalScore) max = bestLineSoFar.finalScore; if (max <= min) { if (_searchConfig.killerHeuristic) { _killerStore.add(depthLeft, consideredMove); } break; } } } } } return bestLineSoFar; }