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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 1)[0]; Assert.AreEqual(bestMove.targetPosition, foundMove.move.targetPosition); }
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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 2)[0]; Assert.IsTrue(MoveHelper.isValidMove(foundMove.move)); }
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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 3)[0]; Assert.AreEqual(BoardStateOffset.F6, foundMove.move.targetPosition); }
public void MinMaxTest() { var board = BoardFactory.LoadBoardFromFen("r1b2rk1/ppq1bppp/2nppn2/8/2B1PP2/1NN1B3/PPP3PP/R2Q1RK1 w - - 0 1"); var minmax = new MinMaxAI(); minmax.MinMaxList(board, 5); }
private static void AiWorker() { while (true) { if (aiWorking) { var ai = new MinMaxAI(); // do actions on virtual board for safety var virtualBoard = game.Copy(); var aiMoves = ai.MinMaxList(virtualBoard.GetBoard(), 5, virtualBoard.AboutToTiePositions()); // trying alternative ways of iteration moves foreach (var move in aiMoves) { Console.WriteLine(game.board.StandardAlgebraicNotation(move.move)); game.Move(move.move); break; } aiWorking = false; } Thread.Sleep(100); } }
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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 3)[0]; // the rook has to move to e3 to defend against mate(d4->e2) Assert.AreEqual(BoardStateOffset.D3, foundMove.move.targetPosition); }
public void Test_XMLWrite() { IArtificialIntelligence _computerIntelligence = new MinMaxAI(); Game game = new Game(_computerIntelligence); game.CreateNewGame(); string path = Path.GetDirectoryName(Path.GetDirectoryName(TestContext.TestDir)) + @"\Reversi.TestProject\Resources\TestGame.xml"; try { XmlSerializer serializer = new XmlSerializer(); serializer.Serialize(game.GetState(), path); } catch (Exception ex) { Assert.IsTrue(false, "Can`t write or load from xml"); } }
public void Test_XmlReadGoodPath() { IArtificialIntelligence _computerIntelligence = new MinMaxAI(); Game game = new Game(_computerIntelligence); game.CreateNewGame(); string path = Path.GetDirectoryName(Path.GetDirectoryName(TestContext.TestDir)) + @"\Reversi.TestProject\Resources\SavedGame.xml"; try { XmlSerializer serializer = new XmlSerializer(); GameState state = serializer.Deserialize(path); game.RestoreState(state); } catch (Exception ex) { Assert.IsTrue(false, "Can`t load from good path"); } }
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(); EvaluatedMove foundMove = minmax.MinMaxList(board, 1)[0]; Assert.AreEqual(BoardStateOffset.D7, foundMove.move.targetPosition); }
public void MinMaxDoesNotChangeAnything() { /* * Starting position (White to play) +---------------+ |r n b q k b n r| 8 |p p p p p p p p| 7 |_ _ _ _ _ _ _ _| 6 |_ _ _ _ _ _ _ _| 5 |_ _ _ _ P _ _ _| 4 |_ _ _ _ _ _ _ _| 3 |P P P P _ P P P| 2 |R N B Q K B N R| 1 +---------------+ * A B C D E F G H */ var board = BoardFactory.LoadBoardFromFen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2"); var original = board.CreateCopy(); var moves = board.GetMoves(); var minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 5)[0]; everyThingIsEqual(original, board); }
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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 5)[0]; Assert.IsTrue(MoveHelper.isValidMove(foundMove.move)); }
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(); }
private IEnumerator handleMinMaxAi() { mmai = new MinMaxAI(redTanks, blueTanks, gs, tankSet1, tankSet2); CoordinateSet aiLocation; CoordinateSet playerLocation; CoordinateSet targetLocation; GameObject blue; GameObject red; targetLocation = mmai.MinMaxTurn(); blue = mmai.getAITank(); red = mmai.getPlayerTank(); aiLocation = new CoordinateSet((int)blue.transform.position.x, (int)blue.transform.position.z); tankClicked = blue; tankClicked2 = red; bool canAt = true; if (!handleAttack(false)) { Tank aiTank = gs.getPlayerTank(PlayerColors.Blue, aiLocation); Vector3 startPos = blue.transform.position; Vector3 endPos = new Vector3(0, 0, 0); Quaternion startRot = blue.transform.rotation; Quaternion endRot = Quaternion.Euler(0f, 0f, 0f); if (aiTank is CannonTank) { endPos = new Vector3(targetLocation.getX(), 1f, targetLocation.getY()); } else { endPos = new Vector3(targetLocation.getX(), 0.8f, targetLocation.getY()); } if (endPos.x > startPos.x) { endRot = Quaternion.Euler(0f, 90f, 0f); } else if (endPos.x < startPos.x) { endRot = Quaternion.Euler(0f, 270f, 0f); } else if (endPos.z > startPos.z) { endRot = Quaternion.Euler(0f, 0f, 0f); } else if (endPos.z < startPos.z) { endRot = Quaternion.Euler(0f, 180f, 0f); } else { endRot = blue.transform.rotation; } float rotStep = tankMoveSpeed * Time.fixedDeltaTime; float rotT = 0; while (rotT <= 1.0f) { rotT += rotStep; blue.transform.rotation = Quaternion.Lerp(startRot, endRot, rotT); yield return(new WaitForFixedUpdate()); } blue.transform.rotation = endRot; float step = (tankMoveSpeed / (startPos - endPos).magnitude) * Time.fixedDeltaTime; float t = 0; while (t <= 1.0f) { t += step; blue.transform.position = Vector3.Lerp(startPos, endPos, t); yield return(new WaitForFixedUpdate()); } blue.transform.position = endPos; rotT = 0; if (aiTank is SniperTank) { while (rotT <= 1.0f) { rotT += rotStep; blue.transform.rotation = Quaternion.Lerp(endRot, startRot, rotT); yield return(new WaitForFixedUpdate()); } } gs.checkValidMove(PlayerColors.Blue, aiLocation, targetLocation, true); canAt = false; } handleAttack(true); if (canAt) { // AI will game 1/5 of the time if it moves System.Random randomNumberGenerator = new System.Random(); int randomNumber = randomNumberGenerator.Next(1, 3); if (randomNumber == 1) { CoordinateSet gambleCoordinates; Tank tempTank = gs.getPlayerTank(PlayerColors.Blue, targetLocation); if (tempTank is EmptyTankSlot) { gambleCoordinates = aiLocation; } else { gambleCoordinates = targetLocation; } string powerup = gs.playerGamble(playerTurn, gambleCoordinates); Debug.Log("Player " + playerTurn + "'s gamble results in: " + powerup); } } changeTurns(); round = Rounds.Move; gs.updatePlayerHealthBars(hpController); numGambles++; updateTooltips("Move1"); aiMove = false; }
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 minmax = new MinMaxAI(); EvaluatedMove foundMove = minmax.MinMaxList(board, 5)[0]; //Assert.AreEqual(BoardStateOffset.H5, foundMove.move.targetPosition); if (!(foundMove.move.targetPosition == BoardStateOffset.H5 || foundMove.move.targetPosition == BoardStateOffset.G6)) { Assert.Fail("ai has to find the move H5 or G6"); } }