예제 #1
0
        public static void findKnightMate()
        {
            /*
             * Starting position (White to play)
             +---------------+
             |r k r _ _ _ _ _| 8
             |p p p _ _ p p p| 7
             |_ _ _ _ _ _ _ _| 6
             |_ _ _ _ N _ _ _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ _ _ _ _ _| 3
             |_ _ _ _ _ _ _ _| 2
             |_ _ K _ _ _ _ _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("rkr5/ppp2ppp/8/4N3/8/8/8/2K5 w - - 0 1");

            var moves = board.GetMoves();
            //var minmax = new MinMaxAI();
            //BestMove foundMove = minmax.MinMaxList(board, 1)[0];


            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 1).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            Assert.AreEqual(BoardStateOffset.D7, foundMove.move.targetPosition);
        }
예제 #2
0
        public void keepPlayingEvenWhenLost()
        {
            /*
             * Starting position (Black to play)
             +---------------+
             |B _ _ _ _ _ _ _| 8
             |_ _ _ _ _ P R p| 7
             |_ _ _ _ N _ _ k| 6
             |_ _ _ p _ _ p _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ _ P _ P _| 3
             |P _ _ _ _ _ K _| 2
             |_ _ _ _ _ _ _ _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("B7/5PRp/4N2k/3p2p1/8/4P1P1/P5K1/8 b - - 0 2");

            var moves = board.GetMoves();


            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 5).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            Assert.IsTrue(MoveHelper.isValidMove(foundMove.move));
        }
예제 #3
0
        public void keepPlayingEvenWhenLostSimpler()
        {
            /*
             * Starting position (Black to play)
             +---------------+
             |_ _ _ _ _ _ _ k| 8
             |p R p _ _ _ p _| 7
             |P p P _ _ _ P _| 6
             |_ P _ _ _ _ p _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ _ _ _ _ _| 3
             |_ _ _ _ _ _ _ _| 2
             |_ _ _ _ _ _ _ _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("7k/pRp3p1/PpP3P1/1P4p1/8/8/8/8 b - - 0 1");

            var moves = board.GetMoves();

            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 2).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            Assert.IsTrue(MoveHelper.isValidMove(foundMove.move));
        }
예제 #4
0
        public static void findMateIn2()
        {
            /*
             * Starting position (White to play)
             +---------------+
             |r n b k _ _ r _| 8
             |p p p p _ p B p| 7
             |_ _ _ q _ _ _ _| 6
             |_ _ _ _ _ _ _ _| 5
             |_ _ B _ _ _ Q _| 4
             |_ _ _ _ _ _ _ _| 3
             |P _ _ _ _ _ P P| 2
             |R _ _ _ R _ K _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("rnbk2r1/pppp1pBp/3q4/8/2B3Q1/8/P5PP/R3R1K1 w - - 0 1");

            var moves = board.GetMoves();

            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 3).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            Assert.AreEqual(BoardStateOffset.F6, foundMove.move.targetPosition);
        }
예제 #5
0
        public static void findQueenMate()
        {
            /*
             * Starting position (White to play)
             +---------------+
             |_ k _ _ _ _ _ _| 8
             |p p p p _ p p p| 7
             |_ _ _ _ _ _ _ _| 6
             |_ _ _ _ Q _ _ _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ _ _ _ _ _| 3
             |_ _ _ _ _ _ _ _| 2
             |_ _ K _ _ _ _ _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("1k6/pppp1ppp/8/4Q3/8/8/8/2K5 w - - 0 1");

            var moves    = board.GetMoves();
            var bestMove = moves.FindTargetPosition(BoardStateOffset.E8);

            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 1).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            Assert.AreEqual(bestMove.targetPosition, foundMove.move.targetPosition);
        }
예제 #6
0
        public void slowTest()
        {
            ai = new AIWorkerManager();
            ai.spawnWorkers(1);

            ai.analyzeBoard(slowBoard, 6).GetAwaiter().GetResult();
            ai.killWorkers();
        }
예제 #7
0
        public void solvePositionWorker()
        {
            var ai = new AIWorkerManager();

            ai.spawnWorkers(workers);
            Task.Run(async() => {
                await ai.analyzeBoard(board, depth);
            }).GetAwaiter().GetResult();
            ai.killWorkers();
        }
예제 #8
0
        public static void defendAgainstMate()
        {
            /*
             * Starting position (White to play)
             +---------------+
             |_ _ _ _ _ _ k _| 8
             |_ _ _ _ _ _ _ _| 7
             |_ _ _ _ _ _ _ _| 6
             |_ _ _ r _ _ _ _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ _ p _ p _| 3
             |_ _ _ _ P _ P _| 2
             |_ _ N _ _ _ K _| 1
             +---------------+
             * A B C D E F G H
             * C1 -> D3 (expected line to protect against mate on D1)
             +---------------+
             |_ _ _ _ _ _ k _| 8
             |_ _ _ _ _ _ _ _| 7
             |_ _ _ _ _ _ _ _| 6
             |_ _ _ r _ _ _ _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ N p _ p _| 3
             |_ _ _ _ P _ P _| 2
             |_ _ _ _ _ _ K _| 1
             +---------------+
             * A B C D E F G H
             * D5 -> D3
             +---------------+
             |_ _ _ _ _ _ k _| 8
             |_ _ _ _ _ _ _ _| 7
             |_ _ _ _ _ _ _ _| 6
             |_ _ _ _ _ _ _ _| 5
             |_ _ _ _ _ _ _ _| 4
             |_ _ _ r p _ p _| 3
             |_ _ _ _ P _ P _| 2
             |_ _ _ _ _ _ K _| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("6k1/8/8/3r4/8/4p1p1/4P1P1/2N3K1 w - - 0 1");

            var moves     = board.GetMoves();
            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 3).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            // the rook has to move to e3 to defend against mate(d4->e2)
            Assert.AreEqual(BoardStateOffset.D3, foundMove.move.targetPosition);
        }
예제 #9
0
        public async Task <Move> GetAiMove(int diffculty, ChessGame game)
        {
            var ai = new AIWorkerManager();

            ai.spawnWorkers(chessConfig.Threads);

            await ai.analyzeBoard(game.GetBoard(), diffculty, new Stack <Move>());

            var move = ai.GetBestMove();

            ai.killWorkers();

            return(move.move);
        }
예제 #10
0
        public static async Task MainAsync(string[] args)
        {
            EvalBoard.initThreadStaticVariables();
            var ai = new AIWorkerManager();
            //var history = new Stack<Move>();

            var game = ChessGame.StartGame();

            ai.spawnWorkers(3);

            //var board = BoardFactory.LoadBoardFromFen();
            bool hasCheated = false;
            int  difficulty = 5;
            bool debug      = false;

            do
            {
                Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                List <Move> moves  = game.Moves().Select(move => move.move).ToList();
                Winner      winner = game.Winner();
                if (winner == Winner.WINNER_WHITE)
                {
                    Console.WriteLine("White wins");
                    break;
                }
                else if (winner == Winner.WINNER_BLACK)
                {
                    Console.WriteLine("Black wins");
                    break;
                }
                else if (winner == Winner.DRAW)
                {
                    Console.WriteLine("Its a draw!");
                    break;
                }
                do
                {
                    try {
                        Console.WriteLine("Make a move (example: \"A1 A3)\"");
                        var readLineOriginal = Console.ReadLine();
                        var readLine         = readLineOriginal.ToUpper().Split(" ").ToList();


                        switch (readLine[0])
                        {
                        case "":
                        case "HELP":
                            Console.WriteLine(@"Available commands are:
 - help                     * help
 - Cheat [depth=5]          * uses eval to find best available move(at least according to AI)
 - moves                    * lists all available moves
 - board                    * Draw the board
 - debug [y/n=y]            * enable / disable debugging
 - difficulty [number=5]    * sets difficulty (above 6 is not recommended because it is slow)
 - switch                   * Switch sides
 - botez gambit             * the best gambit
 - fen [fen]                * load Forsyth-Edwards Notation 
 - undo                     * Undo the last move
 - eval                     * get the current evaluation of the board
 - workers [workerCount]    * Specify how many worker threads the computer should use (should be less than the amount of processors you have)
 - workers                  * Read how many workers are currently being used
 - [from=D5]                * list moves for a specific field
 - [from=E2] [to=e4]        * play a move
 - [from=E7] [to=e8] [promotion=Q/R/B/N] * play a move and choose which piece you want to promote to");
                            continue;

                        case "MOVES":
                            Console.WriteLine("All available moves");
                            //var allMoves = game.board.GetMoves().Where(move => game.board.IsLegalMove(move)).ToList();
                            var allMoves = game.Moves().Select(move => move.move).ToList();
                            foreach (var move in allMoves)
                            {
                                Console.WriteLine($" - {MoveHelper.ReadableMove(move)}");
                            }
                            Console.WriteLine(ChessOutput.AsciiBoard(game.board, allMoves, true));
                            continue;

                        case "BOARD":
                            Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                            continue;

                        case "BOTEZ":     // alias fall through
                        case "BOTEZ_GAMBIT":
                            if (botezGambit(game))
                            {
                                Console.WriteLine("Botez gambit found!");
                                Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                                goto switchSides;
                            }
                            else
                            {
                                Console.WriteLine("Botez gambit unavailable");
                                continue;
                            }

                        case "DIFFICULTY":
                            if (readLine.Count() > 1)
                            {
                                difficulty = int.Parse(readLine[1]);
                                Console.WriteLine($"AI will now look {difficulty} moves ahead");
                            }
                            else
                            {
                                Console.WriteLine($"Current difficulty is {difficulty}");
                                continue;
                            }
                            continue;

                        case "SWITCH":
                            goto switchSides;     // the almighty goto to skip current move and the the ai make the next move, which also switches sides as a side effect

                        case "EVAL":
                            var evalMoves = game.board.GetMoves().Where(move => game.board.IsLegalMove(move)).ToList();
                            var score     = EvalBoard.evalBoard(game.board, evalMoves);
                            Console.WriteLine($"current score is: {score}");
                            continue;

                        case "FEN":
                            var fenList = readLineOriginal.Split(" ").ToList();
                            fenList.RemoveAt(0);
                            var fen = String.Join(" ", fenList);
                            //board = BoardFactory.LoadBoardFromFen(fen);
                            game = ChessGame.ContinueFromFEN(fen);
                            Console.WriteLine($"Loaded board {fen}");
                            Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                            continue;

                        case "DEBUG":
                            debug = true;
                            if (readLine.Count() > 1 && readLine[1] == "N")
                            {
                                debug = false;
                                Console.WriteLine("disabled debug");
                            }
                            else
                            {
                                Console.WriteLine("enabled debug");
                            }
                            continue;

                        case "WORKERS":
                            int workerCount = 3;
                            if (readLine.Count() > 1)
                            {
                                workerCount = int.Parse(readLine[1]);
                                ai.killWorkers();
                                ai.spawnWorkers(workerCount);
                            }
                            else
                            {
                                workerCount = ai.CountWorkers();
                            }
                            Console.WriteLine($"Using {workerCount} workers");
                            continue;

                        case "UNDO":
                            hasCheated = true;

                            if (!game.UndoTurn())
                            {
                                Console.WriteLine("There is not history to undo, sorry");
                            }

                            Console.WriteLine("Undo done (cheater :p)");
                            Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                            continue;

                        case "CHEAT":
                            Console.WriteLine("NOTE everything after the best move is probably not accurate");
                            int depth = 5;
                            if (readLine.Count() > 1)
                            {
                                depth = int.Parse(readLine[1]);
                            }

                            hasCheated = true;

                            List <EvaluatedMove> cheatMoves;
                            using (var progressbar = new ProgressBar()) {
                                cheatMoves = await ai.analyzeBoard(game.board, depth, game.moveHistory(), onProgress : (progress) => {
                                    progressbar.Report((double)((double)progress.progress / (double)progress.total));
                                });
                            }

                            foreach (var cheat in cheatMoves)
                            {
                                Console.WriteLine($" - {MoveHelper.ReadableMove(cheat.move)} (score: {cheat.score})");
                            }
                            continue;

                        case "CHEAT2":
                            Console.WriteLine("NOTE everything after the best move is probably not accurate");
                            int depth2 = 5;
                            if (readLine.Count() > 1)
                            {
                                depth2 = int.Parse(readLine[1]);
                            }

                            hasCheated = true;



                            //using (var progressbar = new ProgressBar()) {
                            //    cheatMoves2 = await ai.analyzeBoard(board, depth2, (progress) => {
                            //        progressbar.Report((double)((double)progress.progress / (double)progress.total));
                            //    });
                            //}
                            var minmax = new MinMaxAI();
                            List <EvaluatedMove> cheatMoves2 = minmax.MinMaxList(game.board, depth2);
                            //var cheatMoves = ParallelChess.AI.MinMaxAI.MinMaxList(board, depth);
                            foreach (var cheat in cheatMoves2)
                            {
                                Console.WriteLine($" - {MoveHelper.ReadableMove(cheat.move)} (score: {cheat.score})");
                            }
                            continue;

                        default:
                            break;
                        }

                        var fromPosition = BoardPosition.ArrayPosition(readLine[0]);
                        if (readLine.Count() == 1)
                        {
                            var positionMoves = game.board.GetMovesForPosition(fromPosition);
                            Console.WriteLine(ChessOutput.AsciiBoard(game.board, positionMoves));
                            Console.WriteLine("Legal moves:");
                            foreach (var move in positionMoves)
                            {
                                if (game.board.IsLegalMove(move))
                                {
                                    Console.WriteLine($" - {MoveHelper.ReadableMove(move)}");
                                }
                            }
                            continue;
                        }
                        var toPosition = BoardPosition.ArrayPosition(readLine[1]);
                        var promotion  = Piece.EMPTY;
                        if (readLine.Count() > 2)
                        {
                            switch (readLine[2])
                            {
                            case "Q":
                                promotion = Piece.QUEEN;
                                break;

                            case "R":
                                promotion = Piece.ROOK;
                                break;

                            case "N":
                                promotion = Piece.KNIGHT;
                                break;

                            case "B":
                                promotion = Piece.BISHOP;
                                break;

                            default:
                                Console.WriteLine("You can only promote to Queen(Q), Rook(R), Knight(N) or Bishop(B)");
                                continue;
                            }
                        }
                        var moveMade = game.Move(fromPosition, toPosition, promotion);
                        if (MoveHelper.isValidMove(moveMade.move))
                        {
                            break;
                        }
                        else
                        {
                            Console.WriteLine("invalid Move");
                        }
                    } catch (Exception e) {
                        Console.WriteLine(e.Message);
                    }
                } while(true);

                Console.WriteLine("Moved to");
switchSides:
                Console.WriteLine(ChessOutput.AsciiBoard(game.board));
                //moves = board.GetMoves();
                winner = game.Winner();
                if (winner == Winner.WINNER_WHITE)
                {
                    if (hasCheated)
                    {
                        Console.WriteLine("Cheater :D");
                    }
                    Console.WriteLine("White wins");
                    break;
                }
                else if (winner == Winner.WINNER_BLACK)
                {
                    if (hasCheated)
                    {
                        Console.WriteLine("Cheater :D");
                    }
                    Console.WriteLine("Black wins");
                    break;
                }
                else if (winner == Winner.DRAW)
                {
                    Console.WriteLine("Its a draw!");
                    break;
                }

                Console.WriteLine("AI Finding move...");
                //var bestMove = ParallelChess.AI.MinMaxAI.MinMaxList(board, 5)[0];

                if (debug)
                {
                    await ai.analyzeBoard(game.board, difficulty, game.moveHistory(), onProgress : (progress) => {
                        Console.WriteLine($"[depth {progress.depth}] {progress.progress}/{progress.total} foundScore: {progress.foundScore} on move {MoveHelper.ReadableMove(progress.move.move.move)}, found by worker {progress.move.taskId} {{ duration {progress.move.durationMS}ms }} began from score {progress.move.startFromMin}");
                    });
                }
                else
                {
                    using (var progressbar = new ProgressBar()) {
                        await ai.analyzeBoard(game.board, difficulty, game.moveHistory(), onProgress : (progress) => {
                            progressbar.Report((double)((double)progress.progress / (double)progress.total));
                        });
                    }
                }


                var bestMove = ai.GetBestMove();
                game.Move(bestMove.move);

                Console.WriteLine($"AI found move with score {bestMove.score}");
                Console.WriteLine($"AI will play {MoveHelper.ReadableMove(bestMove.move)}");
                Console.WriteLine($"FEN: {game.FEN}");
            } while (true);


            Console.WriteLine("End of game!");

            Console.ReadKey();
        }
예제 #11
0
        public static void findMateIn3()
        {
            /*
             * Starting position (White to play)
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N p b k| 7
             |_ p _ p _ _ p _| 6
             |p _ _ N p P P p| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ Q K _ _ R| 1
             +---------------+
             * A B C D E F G H
             * D1 -> H5
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N p b k| 7
             |_ p _ p _ _ p _| 6
             |p _ _ N p P P Q| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ _ K _ _ R| 1
             +---------------+
             * A B C D E F G H
             * G6 -> H5
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N p b k| 7
             |_ p _ p _ _ _ _| 6
             |p _ _ N p P P p| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ _ K _ _ R| 1
             +---------------+
             * A B C D E F G H
             * G5 -> G6
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N p b k| 7
             |_ p _ p _ _ P _| 6
             |p _ _ N p P _ p| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ _ K _ _ R| 1
             +---------------+
             * A B C D E F G H
             * F7 -> G6
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N _ b k| 7
             |_ p _ p _ _ p _| 6
             |p _ _ N p P _ p| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ _ K _ _ R| 1
             +---------------+
             * A B C D E F G H
             * F5 -> G6 (Mate)
             +---------------+
             |r _ b _ n _ _ r| 8
             |_ q _ n N _ b k| 7
             |_ p _ p _ _ P _| 6
             |p _ _ N p _ _ p| 5
             |_ _ P _ P _ _ P| 4
             |_ _ _ B B _ _ _| 3
             |P P _ _ _ _ _ _| 2
             |R _ _ _ K _ _ R| 1
             +---------------+
             * A B C D E F G H
             */
            var board = BoardFactory.LoadBoardFromFen("r1b1n2r/1q1nNpbk/1p1p2p1/p2NpPPp/2P1P2P/3BB3/PP6/R2QK2R w - - 0 1");

            var aiWorkers = new AIWorkerManager();

            aiWorkers.spawnWorkers(3);
            aiWorkers.analyzeBoard(board, 5).Wait();
            aiWorkers.killWorkers();
            EvaluatedMove foundMove = aiWorkers.GetBestMove();

            if (!(foundMove.move.targetPosition == BoardStateOffset.H5 || foundMove.move.targetPosition == BoardStateOffset.G6))
            {
                Assert.Fail($"found move {MoveHelper.ReadableMove(foundMove.move)}");
            }
        }