Пример #1
0
        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());
        }
Пример #2
0
 public lineAndScore(move[] newLine, int newFinalScore, BoardScorer scorer)
 {
     line = newLine;
     finalScore = newFinalScore;
     _scorer = scorer;
 }
Пример #3
0
        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());
        }
Пример #4
0
        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());
        }
Пример #5
0
        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());
        }
Пример #6
0
        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());
        }
Пример #7
0
        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());
        }
Пример #8
0
        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;
        }