Example #1
0
        bool ValidateNotation()
        {
            ValidatedMove     = null;
            ValidatedNotation = null;
            MoveNotation notated;

            if (!MoveNotation.TryParse(txtNotation.Text, out notated))
            {
                lblError.Text    = "Unrecognized notation";
                lblError.Visible = true;
                return(false);
            }
            var ai    = new TakAI_V4(_game.Size);
            var moves = new List <IMove>();

            Helper.EnumerateMoves(moves, _game, ai.NormalPositions);
            ValidatedMove = notated.MatchLegalMove(moves);
            if (ValidatedMove == null)
            {
                lblError.Text    = "Illegal move";
                lblError.Visible = true;
                return(false);
            }
            ValidatedNotation = notated;
            lblError.Visible  = false;
            return(true);
        }
Example #2
0
        List <IMove> moveOptions(GameState game)
        {
            //built-in function that is used to list available moves (maxDepth is irrelivant)
            var ai        = new TakAI_V4(game.Size, maxDepth: 0);
            var evaluator = ai.Evaluator;

            var legalMoves = new List <IMove>();

            Helper.EnumerateMoves(legalMoves, game, ai.RandomPositions);
            return(legalMoves);
        }
Example #3
0
 protected override void OnLoad(EventArgs e)
 {
     base.OnLoad(e);
     _game           = GameState.NewGame(5);
     _ai             = new TakAI_V4(_game.Size);
     _evaluator      = _ai.Evaluator;
     _boardView      = new BoardView();
     _boardView.Dock = DockStyle.Fill;
     _boardView.Game = _game;
     this.Controls.Add(_boardView);
     //_boardView.MouseOverSpotChanged += boardView_MouseOverSpotChanged;
 }
Example #4
0
        static void ReplayMoves(GameState game)
        {
            string movesText = @"NOT IN USE";

            var ai    = new TakAI_V4(game.Size);
            var lines = movesText.Split('\n');

            foreach (var line in lines)
            {
                var notation = line.Substring(line.IndexOf(':') + 1).Trim();
                var moves    = new List <IMove>();
                Helper.EnumerateMoves(moves, game, ai.NormalPositions);
                var move = moves.First(x => x.Notate() == notation);
                move.MakeMove(game);
                game.Ply++;
            }
        }
Example #5
0
        public string AB(int depth, float time)
        {
            List <IMove> moves       = moveOptions(root.state);
            List <float> evaluations = new List <float>();
            var          ai          = new TakAI_V4(root.state.Size, maxDepth: 0);
            var          evaluator   = ai.Evaluator;
            bool         gameOver;
            int          eval;

            Console.WriteLine(moves.Count);
            foreach (IMove m in moves)
            {
                GameState tempState = root.state.DeepCopy();
                ABNode    n         = new ABNode(!root.player, tempState);
                TakEngine.Notation.MoveNotation notated;
                TakEngine.Notation.MoveNotation.TryParse(m.Notate(), out notated);
                var match = notated.MatchLegalMove(moves);
                match.MakeMove(n.state);
                tempState.Ply++;

                evaluator.Evaluate(root.state, out eval, out gameOver);
                if (gameOver)
                {
                    return(m.Notate());
                }
                evaluations.Add(ABSearch((new ABNode(!root.player, tempState)), 0, depth, time));
            }


            //get argMax of list
            int   i   = 0;
            int   arg = 0;
            float max = 0;

            foreach (float f in evaluations)
            {
                if (f > max)
                {
                    max = f;
                    arg = i;
                }
                i++;
            }
            return(moves[arg].Notate());
        }
Example #6
0
        //uses above functions to perform an n-play MTCS
        public string MCTS(int n)
        {
            for (int i = 0; i < n; i++)
            {
                MCNode chosen = Selection();
                Expand(chosen);
                bool result = simulate(chosen);
                backProp(chosen, result);
            }

            float maxWins  = 0F;
            int   winIndex = 0;
            float maxPlays = 0;

            var  ai        = new TakAI_V4(root.state.Size, maxDepth: 0);
            var  evaluator = ai.Evaluator;
            bool gameOver;
            int  eval;

            //chooses highest win rate (or winning move if available)
            for (int i = 0; i < root.children.Count; i++)
            {
                evaluator.Evaluate(root.children[i].state, out eval, out gameOver);
                if (gameOver)
                {
                    return(root.legalMoves[i].Notate());
                }
                if (root.children[i].winRate() > maxWins)
                {
                    if (root.children[i].plays > maxPlays)
                    {
                        maxPlays = root.children[i].plays;
                    }
                    maxWins  = root.children[i].wins;
                    winIndex = i;
                }
            }

            return(root.legalMoves[winIndex].Notate());
        }
Example #7
0
        //performs MCTS selection step (do not call if an available move is a win state)
        MCNode Selection()
        {
            var ai        = new TakAI_V4(root.state.Size, maxDepth: 0);
            var evaluator = ai.Evaluator;

            //random selection for testing purposes
            Random r     = new Random();
            int    index = r.Next(root.children.Count);

            MCNode        iterator         = root.children[index];
            List <MCNode> iteratorChildren = iterator.children;

            //looks for unexpanded node
            while (iterator.children.Count > 0)
            {
                bool gameOver;
                int  eval;  //irrelivant, only exists to call evaluate function to look for gameover states

                //random
                int iteratorIndex = r.Next(iteratorChildren.Count);

                //avoid repeating pre-evaluated win states
                evaluator.Evaluate(iteratorChildren[iteratorIndex].state, out eval, out gameOver);
                if (!gameOver)
                {
                    iterator         = iteratorChildren[iteratorIndex];
                    iteratorChildren = iterator.children;
                }
                else
                {
                    //avoids using the same value twice
                    iteratorChildren.RemoveAt(iteratorIndex);
                }
            }

            return(iterator);
        }
Example #8
0
        //enumerates all available moves at a given node
        void Expand(MCNode leaf)
        {
            var ai        = new TakAI_V4(root.state.Size, maxDepth: 4);
            var evaluator = ai.Evaluator;

            List <IMove> moves = moveOptions(leaf.state);

            TakEngine.Notation.MoveNotation notated;
            foreach (var m in moves)
            {
                GameState tempState = leaf.state.DeepCopy();
                TakEngine.Notation.MoveNotation.TryParse(m.Notate(), out notated);
                var match = notated.MatchLegalMove(moves);
                match.MakeMove(tempState);
                tempState.Ply++;
                leaf.children.Add(new MCNode(!leaf.player, tempState, leaf));
                leaf.legalMoves.Add(m);
                evaluator.Evaluate(leaf.children[leaf.children.Count - 1].state, out eval, out gameOver);
                if (gameOver)
                {
                    backProp(leaf.children[leaf.children.Count - 1], !leaf.player);
                }
            }
        }
Example #9
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");
        }
Example #10
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++;
                }
            }
        }
Example #11
0
        public static void FindQuickWin(string outpath)
        {
            var ai = new TakAI_V4[] {
                new TakAI_V4(BoardSize, maxDepth: 6, evaluator: new SimpleEvaluator(BoardSize)),
                new TakAI_V4(BoardSize, maxDepth: 5)
            };
            var movelog = new List <string>();
            int fastest = int.MaxValue;

            if (System.IO.File.Exists(outpath))
            {
                using (var reader = System.IO.File.OpenText(outpath))
                {
                    var line = reader.ReadLine();
                    fastest = int.Parse(line);
                }
            }

            while (true)
            {
                var guid = System.Guid.NewGuid();
                PrintTimeStampedMessage("Started new game");
                var game = GameState.NewGame(BoardSize);
                movelog.Clear();

                var fixedmoves = new string[] { "a1", "e1" };
                foreach (var fixedmove in fixedmoves)
                {
                    PrintTimeStampedMessage(string.Concat(game.Ply, ": ", fixedmove));
                    GameState.Play(game, fixedmove);
                    movelog.Add(fixedmove);
                }

                bool gameOver;
                int  eval;

                do
                {
                    IMove move;
                    int   player = game.Ply & 1;
                    move = ai[player].FindGoodMove(game);
                    var notation = move.Notate();
                    PrintTimeStampedMessage(string.Concat(game.Ply, ": ", notation));
                    movelog.Add(notation);
                    move.MakeMove(game);
                    game.Ply++;
                    ai[0].Evaluator.Evaluate(game, out eval, out gameOver);
                } while (!gameOver);

                string result;
                if (eval == 0)
                {
                    result = "Tie";
                }
                else
                {
                    if (eval > 0)
                    {
                        result = "First player wins (W: " + ai[0].Evaluator.Name + ")";
                    }
                    else
                    {
                        result = "Second player wins (B: " + ai[1].Evaluator.Name + ")";
                    }

                    if (eval == Math.Abs(Evaluation.FlatWinEval))
                    {
                        result += " via flats";
                    }
                    else
                    {
                        result += " via road";
                    }
                }
                PrintTimeStampedMessage(result);

                if (eval > 0 && movelog.Count < fastest)
                {
                    fastest = movelog.Count;
                    using (var writer = System.IO.File.CreateText(outpath))
                    {
                        writer.WriteLine(fastest);
                        writer.WriteLine("' Game ID {0}", guid);
                        writer.WriteLine("' Moves {0}", movelog.Count);
                        writer.WriteLine("' Result {0}", result);
                        for (int i = 0; i < movelog.Count; i++)
                        {
                            writer.WriteLine("{0}\t{1}", i + 1, movelog[i]);
                        }
                    }
                }
            }
        }
Example #12
0
        public static void RunTest(string appendPath)
        {
            int[] totalScore = new int[] { 0, 0 };
            var   aitype1    = new TakAI_V4(BoardSize);

            aitype1.MaxDepth = 6;
            var aitype2 = new TakAI_V4(BoardSize);

            aitype2.MaxDepth = 6;
            var evaluator   = new PositionalEvaluatorV3(BoardSize);
            var movelog     = new List <string>();
            var durationlog = new List <TimeSpan>();

            for (int gameCount = 0; ; gameCount++)
            {
                var guid = System.Guid.NewGuid();
                PrintTimeStampedMessage("Started new game");
                var game = GameState.NewGame(BoardSize);
                movelog.Clear();
                durationlog.Clear();
                bool   gameOver;
                int    eval;
                var    starttime = DateTime.Now;
                ITakAI ai1, ai2;
                if (0 == (gameCount & 1))
                {
                    ai1 = aitype1;
                    ai2 = aitype2;
                }
                else
                {
                    ai1 = aitype2;
                    ai2 = aitype1;
                }
                do
                {
                    var   movestart = DateTime.Now;
                    IMove move;
                    if (0 == (game.Ply & 1))
                    {
                        move = ai1.FindGoodMove(game);
                    }
                    else
                    {
                        move = ai2.FindGoodMove(game);
                    }
                    var duration = DateTime.Now.Subtract(movestart);
                    var notation = move.Notate();
                    PrintTimeStampedMessage(string.Concat(game.Ply, ": ", notation));
                    movelog.Add(notation);
                    durationlog.Add(duration);
                    move.MakeMove(game);
                    game.Ply++;
                    evaluator.Evaluate(game, out eval, out gameOver);
                } while (!gameOver);

                string result;
                if (eval == 0)
                {
                    result = "Tie";
                }
                else
                {
                    if (eval > 0)
                    {
                        totalScore[gameCount & 1] += 1;
                        result = "First player wins (W: " + ai1.Evaluator.Name + ")";
                    }
                    else
                    {
                        totalScore[(gameCount + 1) & 1] += 1;
                        result = "Second player wins (W: " + ai2.Evaluator.Name + ")";
                    }

                    if (eval == Math.Abs(Evaluation.FlatWinEval))
                    {
                        result += " via flats";
                    }
                    else
                    {
                        result += " via road";
                    }
                }
                PrintTimeStampedMessage(result);
                PrintTimeStampedMessage(string.Format("{0}={1}, {2}={3}",
                                                      aitype1.Evaluator.Name, totalScore[0], aitype2.Evaluator.Name, totalScore[1]));

                using (var writer = System.IO.File.AppendText(appendPath))
                {
                    writer.WriteLine("' Game ID {0}", guid);
                    writer.WriteLine("' AI1 difficulty {0}", ai1.MaxDepth);
                    writer.WriteLine("' AI2 difficulty {0}", ai2.MaxDepth);
                    writer.WriteLine("' Started {0}", starttime.ToString(DateFormat));
                    writer.WriteLine("' Duration {0}", DateTime.Now.Subtract(starttime));
                    writer.WriteLine("' Moves {0}", movelog.Count);
                    writer.WriteLine("' Result {0}", result);
                    for (int i = 0; i < movelog.Count; i++)
                    {
                        writer.WriteLine("{0}\t{1}\t{2}", i + 1, movelog[i], durationlog[i]);
                    }
                }
            }
        }
Example #13
0
        public float evaluate(MCNode node)
        {
            float positionValue = 0;
            int   flatCount = 0;
            int   highestCap = 0;
            int   maxCap = 0, maxCapEnemy = 0;
            int   losingState = 0;

            //Set coefficient values here for ease of parameter tuning
            float flatCo = 1F;
            float capCo  = 5F;
            float lossCo = 1000F;

            //check if position is one move away from an enemy win state
            List <IMove> moves     = moveOptions(node.state);
            var          ai        = new TakAI_V4(root.state.Size, maxDepth: 0);
            var          evaluator = ai.Evaluator;
            bool         gameOver;
            int          eval;

            TakEngine.Notation.MoveNotation notated;
            GameState state = node.state.DeepCopy();

            foreach (var m in moves)
            {
                TakEngine.Notation.MoveNotation.TryParse(m.Notate(), out notated);
                var match = notated.MatchLegalMove(moves);
                match.MakeMove(state);
                state.Ply++;
                evaluator.Evaluate(state, out eval, out gameOver);
                if (gameOver)
                {
                    losingState = 1;
                }
                m.TakeBackMove(state);
            }

            //count the number of flat stones
            for (int i = 0; i < node.state.Size; i++)
            {
                for (int j = 0; j < node.state.Size; j++)
                {
                    if (node.state.Board[i, j].Count > 0)
                    {
                        var piece = node.state.Board[i, j][node.state.Board[i, j].Count - 1];
                        if (Piece.GetStone(piece) == Piece.Stone_Flat)
                        {
                            if ((Piece.GetPlayerID(piece) == 1 && !node.player) || (Piece.GetPlayerID(piece) == 0 && node.player))
                            {
                                flatCount++;
                            }
                            else
                            {
                                //Account for enemy flat stones, making the heuristic a differential rather than a simple count
                                flatCount--;
                            }
                        }

                        //check for highest capstone
                        if (Piece.GetStone(piece) == Piece.Stone_Cap)
                        {
                            if (Piece.GetPlayerID(piece) == 1 && !node.player)
                            {
                                maxCapEnemy = node.state.Board[i, j].Count;
                            }
                            else if (Piece.GetPlayerID(piece) == 0 && node.player)
                            {
                                maxCap = node.state.Board[i, j].Count;
                            }
                        }
                    }
                }
            }

            //check which (if either) player has the highest capstone
            if (maxCap > maxCapEnemy)
            {
                highestCap = 1;
            }
            else if (maxCap < maxCapEnemy)
            {
                highestCap = -1;
            }

            positionValue = flatCount * flatCo + highestCap * capCo + losingState * lossCo;
            return(positionValue);
        }
Example #14
0
        bool simulate(MCNode start)
        {
            int          eval = 0;
            bool         gameOver;
            var          ai        = new TakAI_V4(start.state.Size, maxDepth: 3);
            var          evaluator = ai.Evaluator;
            List <IMove> moves     = moveOptions(start.state);

            Expand(start);

            //check for end of game
            evaluator.Evaluate(start.state, out eval, out gameOver);
            if (gameOver)
            {
                return(!start.player);
            }

            List <float> evaluations = new List <float>();

            //random play
            for (int i = 0; i < moves.Count; i++)
            {
                MCNode m = start.children[i];
                float  f = evaluate(m);
                //Console.WriteLine(f);
                if (f >= 0F)
                {
                    evaluations.Add(f);
                }
            }

            if (evaluations.Count == 0)
            {
                return(false);
            }

            float sum = evaluations.Sum();

            Random r           = new Random();
            double selectValue = r.NextDouble();
            float  selection   = 0F;
            int    moveIndex   = 0;

            while (selection < selectValue)
            {
                //Console.WriteLine(evaluations.Count.ToString() + "," + moveIndex.ToString());
                selection += evaluations[moveIndex] / sum;
                moveIndex++;
            }

            MCNode tempNode = new MCNode(!start.player, start.state.DeepCopy());

            TakEngine.Notation.MoveNotation notated;
            //Console.WriteLine(moveIndex.ToString() + "," + evaluations.Count.ToString() + "," + moves.Count.ToString());
            TakEngine.Notation.MoveNotation.TryParse(moves[moveIndex - 1].Notate(), out notated);
            var match = notated.MatchLegalMove(moves);

            match.MakeMove(tempNode.state);
            tempNode.state.Ply++;

            return(simulate(tempNode));
        }
Example #15
0
        public float ABSearch(ABNode node, int ply, int depth, float time, float alpha = float.MinValue, float beta = float.MinValue)
        {
            if (ply > depth)
            {
                return(evaluate(node));
            }
            List <IMove> moves       = moveOptions(root.state);
            List <float> evaluations = new List <float>();
            var          ai          = new TakAI_V4(root.state.Size, maxDepth: 0);
            var          evaluator   = ai.Evaluator;
            bool         gameOver;
            int          eval;
            int          i = 0;

            time /= moves.Count;
            while (i < moves.Count)
            {
                IMove  m = moves[i];
                ABNode n = new ABNode(!node.player, node.state);
                TakEngine.Notation.MoveNotation notated;
                TakEngine.Notation.MoveNotation.TryParse(m.Notate(), out notated);
                var match = notated.MatchLegalMove(moves);

                /* match.MakeMove(n.state);
                 * node.state.Ply++;
                 *
                 * evaluator.Evaluate(n.state, out eval, out gameOver);
                 * if (gameOver)
                 * {
                 *   if (node.player)
                 *       return 1000F;
                 *   else
                 *       return -1000F;
                 * }*/
                var task = Task.Run(() =>
                {
                    return(ABSearch(n, ply + 1, depth, (float)(time)));
                });

                bool completedOnTime = task.Wait(TimeSpan.FromMilliseconds(time));

                //float e = ABSearch(n, ply + 1, depth);
                float e = 0;
                if (completedOnTime)
                {
                    e = task.Result;

                    evaluations.Add(e);

                    //alpha-beta pruning
                    if (node.player)    //max
                    {
                        if (e > alpha)
                        {
                            alpha = e;
                        }
                        if (e > beta)
                        {
                            return(e);
                        }
                    }
                    if (!node.player)   //min
                    {
                        if (e < beta)
                        {
                            beta = e;
                        }
                        if (e <= alpha)
                        {
                            return(e);
                        }
                    }
                }
                else
                {
                    evaluations.Add(0);
                }
                i++;
            }

            if (node.player)
            {
                return(evaluations.Max());
            }
            else
            {
                return(evaluations.Min());
            }
        }