示例#1
0
        public TakAI2(int boardSize, int maxDepth = DefaultMaxDepth)
        {
            _maxDepth         = maxDepth;
            _rand             = new Random();
            _singleThreadData = new AIThreadData(boardSize);

            // Initialize list of all legal board positions
            _normalPositions = new BoardPosition[boardSize * boardSize];
            for (int i = 0; i < _normalPositions.Length; i++)
            {
                _normalPositions[i] = new BoardPosition(i % boardSize, i / boardSize);
            }

            // Copy board positions into an alternate array that can be randomized to make the AI more interesting
            _randomPositions = new BoardPosition[boardSize * boardSize];
            Array.Copy(_normalPositions, _randomPositions, _normalPositions.Length);
        }
示例#2
0
        public IMove FindGoodMove(GameState game)
        {
            // Clear cancelation state before beginning to process the move
            _canceled = _canceling = false;

            _evals = 0;
            _timer.Stop();
            _timer.Reset();
            _timer.Restart();

            // Randomize order of board positions so that the AI appears less predictable
            // in the early phases of the game
            _randomPositions.RandomizeOrder(_rand);

            IMove bestMove = null;
            int   bestEval;

            if (_singleThreadData == null)
            {
                _singleThreadData = new AIThreadData(game.Size, _maxDepth, Evaluator);
            }
            _singleThreadData.Reset(game);
            for (_deepenTo = 0; _deepenTo <= _maxDepth; _deepenTo++)
            {
                FindGoodMove(_singleThreadData, 0, null, out bestMove, out bestEval);
                if (Math.Abs(bestEval) >= Evaluation.FlatWinEval)
                {
                    break;
                }
                LastEvaluation = bestEval;
            }

            _timer.Stop();
            if (Properties.Settings.Default.debug)
            {
                System.IO.File.AppendAllText(DebugLogFilePath,
                                             string.Format("{0}\t{1}\t{2:0.0000}\t{3:0.0000}\r\n",
                                                           Evaluator.Name,
                                                           _evals,
                                                           _timer.Elapsed.TotalSeconds,
                                                           (double)_evals / _timer.Elapsed.TotalSeconds));
            }

            return(bestMove);
        }
示例#3
0
        void FindGoodMove(AIThreadData data, int depth, int?prune, out IMove bestMove, out int bestEval)
        {
            bestMove = null;
            bestEval = int.MinValue;
            if (_canceling)
            {
                _canceled = true;
                return;
            }
            var depthMoves = data.DepthMoves;

            while (depth >= depthMoves.Count)
            {
                depthMoves.Add(new List <IMove>());
            }
            var moves = depthMoves[depth];

            moves.Clear();

            var game = data.Game;

            EnumerateMoves(moves, game, _randomPositions);

            foreach (var move in moves)
            {
                move.MakeMove(game);
                game.Ply++;

                int  eval;
                bool gameOver;
                data.Evaluator.Evaluate(game, out eval, out gameOver);
                if (0 == (game.Ply & 1))
                {
                    eval *= -1;
                }
                if (!(depth == _maxDepth || gameOver))
                {
                    IMove opmove;
                    int   opeval;
                    FindGoodMove(data, depth + 1, bestMove == null ? (int?)null : -bestEval, out opmove, out opeval);
                    eval = opeval * -1;
                }
                if (eval > bestEval)
                {
                    bestMove = move;
                    bestEval = eval;
                }

                game.Ply--;
                move.TakeBackMove(game);

                if (gameOver && eval > 0)
                {
                    break;
                }
                if (prune.HasValue && eval >= prune.Value)
                {
                    break;
                }
            }
        }
示例#4
0
        void FindGoodMove(AIThreadData data, int depth, int?prune, out IMove bestMove, out int bestEval)
        {
            bestMove = null;
            bestEval = -999999;
            if (_canceling)
            {
                _canceled = true;
                return;
            }
            var moves = data.DepthMoves[depth];

            moves.Clear();

            var game = data.Game;

            Helper.EnumerateMoves(moves, game, _randomPositions);

            // on the very first ply we only need to consider moves in one quadrant of the board because of rotational symmetry
            if (data.Game.Ply == 0)
            {
                var maxcoord = (data.Game.Size + 1) >> 1;
                for (int i = 0; i < moves.Count; i++)
                {
                    var m = (PlacePieceMove)moves[i];
                    if (m.Pos.X >= maxcoord || m.Pos.Y >= maxcoord)
                    {
                        moves[i] = moves[moves.Count - 1];
                        moves.RemoveAt(moves.Count - 1);
                    }
                }
            }

            {
                int writeto = 0;
                if (data.KillerMoves1[depth] != null)
                {
                    var killer = data.KillerMoves1[depth];
                    for (int i = writeto + 1; i < moves.Count; i++)
                    {
                        if (moves[i].CompareTo(killer))
                        {
                            var swap = moves[writeto];
                            moves[writeto] = moves[i];
                            moves[i]       = swap;
                            writeto++;
                            break;
                        }
                    }
                }
                if (data.KillerMoves2[depth] != null)
                {
                    var killer = data.KillerMoves2[depth];
                    for (int i = writeto + 1; i < moves.Count; i++)
                    {
                        if (moves[i].CompareTo(killer))
                        {
                            var swap = moves[writeto];
                            moves[writeto] = moves[i];
                            moves[i]       = swap;
                            writeto++;
                            break;
                        }
                    }
                }
            }

            foreach (var move in moves)
            {
                move.MakeMove(game);
                game.Ply++;

                int  eval;
                bool gameOver;
                if (depth != _deepenTo)
                {
                    data.SimpleEvaluator.Evaluate(game, out eval, out gameOver);
                }
                else
                {
                    data.Evaluator.Evaluate(game, out eval, out gameOver);
                }
                _evals++;
                if (0 == (game.Ply & 1))
                {
                    eval *= -1;
                }
                if (!(depth == _deepenTo || gameOver))
                {
                    IMove opmove;
                    int   opeval;
                    FindGoodMove(data, depth + 1, bestMove == null ? (int?)null : -bestEval, out opmove, out opeval);
                    eval = opeval * -1;
                }
                if (eval > bestEval)
                {
                    bestMove = move;
                    bestEval = eval;

                    data.KillerMoves2[depth] = data.KillerMoves1[depth];
                    data.KillerMoves1[depth] = bestMove;
                }

                game.Ply--;
                move.TakeBackMove(game);

                if (gameOver && eval > 0)
                {
                    break;
                }
                if (prune.HasValue && eval >= prune.Value)
                {
                    break;
                }
            }
        }