예제 #1
0
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var game = (GameState)e.Argument;
            var move = _ai.FindGoodMove(game);

            move.MakeMove(game);
            game.Ply++;
            e.Result = game;
        }
예제 #2
0
        static void GameLoop()
        {
            int    MCTSWins     = 0;
            int    ABWins       = 0;
            int    gameIterator = 0;
            Random r            = new Random();
            var    fullauto     = new bool[] { false, false };

            fullauto[1] = true;
            var    game      = GameState.NewGame(5);
            MCTree tree      = new MCTree(game);
            var    ai        = new TakAI_V4(game.Size, maxDepth: 3);
            var    evaluator = ai.Evaluator;
            bool   gameOver;
            int    eval;
            var    recentMoves  = new Stack <IMove>();
            var    recentStates = new Stack <GameState>();

            while (true)
            {
                // print board
                PrintBoard(game, previous: recentStates.Count > 0 ? recentStates.Peek() : null);

                evaluator.Evaluate(game, out eval, out gameOver);
                if (gameOver)
                {
                    Console.Write("Game over, ");
                    if (eval == 0)
                    {
                        Console.WriteLine("Tie");
                    }
                    else if (eval > 0)
                    {
                        MCTSWins++;
                    }
                    else
                    {
                        ABWins++;
                    }
                    for (int i = 0; i < game.Size; i++)
                    {
                        gameIterator++;
                    }
                    //records results of game and resets board
                    if (gameIterator < gameNum)
                    {
                        game = GameState.NewGame(game.Size);
                    }
                }
                Console.Write("[T{0}, {1}]: ", game.Ply, (game.Ply & 1) == 0 ? 'X' : 'O');

                string cmd;
                if (fullauto[game.Ply & 1] && !gameOver)
                {
                    ABTree ABTree = new ABTree(game);
                    cmd = ABTree.AB(1, 15F);

                    /*
                     * cmd = "ai";
                     * Console.WriteLine(cmd);*/
                }
                else
                {
                    //cmd = Console.ReadLine().Trim();
                    var legalMoves = new List <IMove>();
                    Helper.EnumerateMoves(legalMoves, game, ai.RandomPositions);
                    int index = r.Next(legalMoves.Count);
                    evaluator.Evaluate(game, out eval, out gameOver);
                    if (!gameOver)
                    {
                        //check if current state exists in MCT. If so, move root node to maintain exploration records
                        if (!tree.changeRoot(game))
                        {
                            tree = new MCTree(game);
                        }
                        tree.evaluate(tree.root);
                        cmd = tree.MCTS(15);

                        /*ABTree tree = new ABTree(game);
                         * cmd = tree.AB(1);*/
                        //Console.WriteLine("\nMCTree:" + cmd);
                    }
                    else
                    {
                        cmd = "";
                    }
                }

                if (string.IsNullOrEmpty(cmd) || cmd == "q")
                {
                    break;
                }
                else if (cmd == "help")
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("==Global commands");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine("ai        AI will choose a move for this player");
                    Console.WriteLine("ai on     This player will become completely controlled by the AI");
                    Console.WriteLine("ai N      Set AI difficulty to N [2-9], default is 3.");
                    Console.WriteLine("ai off    Disable AI control for all players");
                    Console.WriteLine("undo      Undo last move, including the AI's response (if any)");
                    Console.WriteLine("list      List all legal moves in the current board position");
                    Console.WriteLine("          Warning: level N+1 is roughly 30 to 50 times slower than N!");
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("==Move notation");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine("          Use Portable Tak Notation (PTN)");
                    Console.WriteLine("          https://www.reddit.com/r/Tak/comments/3o2omm/tak_game_notation/");
                    Console.Write("<Press any key to continue>");
                    Console.ReadKey();
                    Console.WriteLine();
                }
                else if (cmd == "undo")
                {
                    while (recentMoves.Count > 0)
                    {
                        var undoing = recentMoves.Pop();
                        undoing.TakeBackMove(game);
                        game.Ply--;
                        recentStates.Pop();
                        if (!fullauto[game.Ply & 1])
                        {
                            break;
                        }
                    }
                }
                else if (cmd == "ai off")
                {
                    fullauto[0] = fullauto[1] = false;
                }
                else if (cmd.StartsWith("ai ") && cmd.Length > 3 && Char.IsDigit(cmd[3]))
                {
                    int diff = 0;
                    if (!int.TryParse(cmd.Substring(3), out diff))
                    {
                        diff = 0;
                    }
                    if (diff < 2 || diff > 9)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("Invalid difficulty level.  Legal values are 2 thru 9.");
                        Console.ForegroundColor = ConsoleColor.Gray;
                    }
                    else
                    {
                        if (diff == ai.MaxDepth)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("AI difficulty is already set to " + diff.ToString());
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.Cyan;
                            ai.MaxDepth             = diff;
                            Console.WriteLine("AI difficulty set to " + diff.ToString());
                            Console.ForegroundColor = ConsoleColor.Gray;
                        }
                    }
                }
                else
                {
                    if (gameOver)
                    {
                        Console.WriteLine("Invalid command");
                    }
                    else if (cmd == "ai on" || cmd == "ai")
                    {
                        if (cmd == "ai on")
                        {
                            fullauto[game.Ply & 1] = true;
                        }
                        var move = ai.FindGoodMove(game);

                        var restoreColor = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.DarkGray;
                        Console.WriteLine("ai move => {0}", move.Notate());
                        Console.ForegroundColor = restoreColor;

                        recentStates.Push(game.DeepCopy());
                        recentMoves.Push(move);
                        move.MakeMove(game);
                        game.Ply++;
                    }
                    else if (cmd == "list")
                    {
                        var legalMoves = new List <IMove>();
                        Helper.EnumerateMoves(legalMoves, game, ai.RandomPositions);
                        foreach (var move in legalMoves)
                        {
                            Console.WriteLine(move.Notate());
                        }
                    }
                    else
                    {
                        TakEngine.Notation.MoveNotation notated;
                        if (!TakEngine.Notation.MoveNotation.TryParse(cmd, out notated))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("UNRECOGNIZED MOVE NOTATION.  Type 'help' for more information.");
                            Console.ForegroundColor = ConsoleColor.Gray;
                            continue;
                        }

                        var legalMoves = new List <IMove>();
                        Helper.EnumerateMoves(legalMoves, game, ai.RandomPositions);
                        var match = notated.MatchLegalMove(legalMoves);
                        if (match == null)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("ILLEGAL MOVE.  Type 'help' for more information.");
                            Console.ForegroundColor = ConsoleColor.Gray;
                        }
                        else
                        {
                            recentStates.Push(game.DeepCopy());
                            recentMoves.Push(match);
                            match.MakeMove(game);
                            game.Ply++;
                        }
                    }
                }
            }
            File.AppendAllText("Records/records.csv", MCTSWins.ToString() + "," + ABWins.ToString() + Environment.NewLine);
            Console.WriteLine("Exiting");
        }
예제 #3
0
        static void Analysis()
        {
            while (true)
            {
GetPath:
                Console.Write("PTN file? ");
                var path = Console.ReadLine();
                if (string.IsNullOrEmpty(path))
                {
                    break;
                }

                if (!System.IO.File.Exists(path))
                {
                    Console.WriteLine();
                    Console.WriteLine("File does not exist");
                    goto GetPath;
                }

                TakEngine.Notation.GameRecord gameRecord;
                int size;
                try
                {
                    var database = TakEngine.Notation.TakPGN.LoadFromFile(path);
                    if (database.Games.Count != 1)
                    {
                        Console.WriteLine("Database does not contain exactly 1 game");
                        goto GetPath;
                    }
                    gameRecord = database.Games[0];
                    size       = gameRecord.BoardSize;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    goto GetPath;
                }

                var ai = new TakAI_V4(size);
                while (true)
                {
                    Console.Write("Level [{0}]? ", ai.MaxDepth);
                    var response = Console.ReadLine();
                    if (string.IsNullOrEmpty(response))
                    {
                        break;
                    }
                    int level;
                    if (int.TryParse(response.Trim(), out level) && level >= 2 && level < 10)
                    {
                        ai.MaxDepth = level;
                        break;
                    }
                    Console.WriteLine("Invalid response");
                }

                var game       = GameState.NewGame(size);
                var legalMoves = new List <IMove>();
                var evaluator  = ai.Evaluator;
                foreach (var notated in gameRecord.MoveNotations)
                {
                    int    turn   = (game.Ply >> 1) + 1;
                    int    player = (game.Ply & 1) + 1;
                    string header = string.Format("#{0}, {1}.{2}: {3}", game.Ply + 1, turn, player, notated.Text);
                    Console.Write("{0,-30}", header);

                    legalMoves.Clear();
                    Helper.EnumerateMoves(legalMoves, game, ai.NormalPositions);
                    var move = notated.MatchLegalMove(legalMoves);
                    if (move == null)
                    {
                        Console.WriteLine("Illegal move?");
                        break;
                    }
                    move.MakeMove(game);
                    game.Ply++;

                    int  unused;
                    bool gameOver;
                    evaluator.Evaluate(game, out unused, out gameOver);
                    if (gameOver)
                    {
                        break;
                    }

                    ai.MaxDepth--;
                    ai.FindGoodMove(game);
                    var myeval = ai.LastEvaluation * -1;
                    ai.MaxDepth++;
                    move.TakeBackMove(game);
                    game.Ply--;

                    var aimove = ai.FindGoodMove(game);

                    {
                        int eval = myeval;
                        if (0 != (game.Ply & 1))
                        {
                            eval *= -1;
                        }
                        Console.WriteLine("Eval: {0}", eval);
                    }
                    if (Math.Abs(myeval - ai.LastEvaluation) > 100)
                    {
                        if (ai.LastEvaluation > 1000)
                        {
                            Console.WriteLine();
                            Console.WriteLine("Missed opportunity, AI sees certain victory:");
                            Console.WriteLine("  " + aimove.Notate());
                            Console.WriteLine();
                        }
                        if (myeval < -1000)
                        {
                            Console.WriteLine();
                            Console.WriteLine("Blunder, defeat is now certain!");
                            Console.WriteLine("  AI suggests {0}, with expected outcome of {1}", aimove.Notate(), ai.LastEvaluation);
                        }
                    }
                    else if (Math.Abs(myeval - ai.LastEvaluation) >= 20)
                    {
                        Console.WriteLine();
                        Console.WriteLine("Poor move?  AI suggests {0}, with expected outcome of {1}", aimove.Notate(), ai.LastEvaluation);
                    }

                    move.MakeMove(game);
                    game.Ply++;
                }
            }
        }