Beispiel #1
0
        public Game(int[,] configuration, Color PlayerChoice)
        {
            Turn = new Turn();

            GameStatus = Const.GAME_ON;

            MovesHistory = new List <Tuple <Move, int, Point> >();

            Board = new Board(configuration);

            Human = false ? Color.Empty : PlayerChoice;

            FlagshipPosition = new Point(5, 5);

            AlphaBetaSearch = new ImprovedABSearch(this);

            IterativeDeepening = new IterativeDeepening(AlphaBetaSearch);

            TranspositionTable = new TranspositionTable(Board);

            Evaluator = new Evaluation(this);

            MCEvaluator = new MonteCarloEvaluation(this);

            SearchStats = new StatsAB();

            LegalMoves = new int[11, 11];
            for (int i = 0; i < 11; i++)
            {
                for (int j = 0; j < 11; j++)
                {
                    LegalMoves[i, j] = Const.ILLEGAL_MOVE;
                }
            }
        }
        private static int GetPrincipalVariation(BoardState board, Move[] moves, int movesCount)
        {
            var entry = TranspositionTable.Get(board.Hash);

            if (entry.Flags == TranspositionTableEntryFlags.ExactScore && entry.IsKeyValid(board.Hash) && movesCount < SearchConstants.MaxDepth)
            {
                if (!board.IsMoveLegal(entry.BestMove))
                {
                    return(movesCount);
                }

                moves[movesCount] = entry.BestMove;
                board.MakeMove(entry.BestMove);

                var enemyColor = ColorOperations.Invert(board.ColorToMove);
                var king       = board.Pieces[enemyColor][Piece.King];
                var kingField  = BitOperations.BitScan(king);

                if (board.IsFieldAttacked(enemyColor, (byte)kingField))
                {
                    board.UndoMove(entry.BestMove);
                    return(movesCount);
                }

                movesCount = GetPrincipalVariation(board, moves, movesCount + 1);
                board.UndoMove(entry.BestMove);
            }

            return(movesCount);
        }
Beispiel #3
0
        public void TranspositionTable_FillAndReplacePerfTest()
        {
            TimeSpan sum        = TimeSpan.Zero;
            int      iterations = 1000;

            for (int i = 0; i < iterations; i++)
            {
                TranspositionTable tt = new TranspositionTable(TranspositionTable.DefaultSizeInBytes / 1024);
                Assert.IsNotNull(tt);

                Stopwatch sw = Stopwatch.StartNew();

                // Fill
                for (int j = 0; j < tt.Capacity; j++)
                {
                    ulong key = (ulong)j;
                    tt.Store(key, CreateMaxEntry(j));
                }

                // Replace
                for (int j = tt.Capacity - 1; j >= 0; j--)
                {
                    TranspositionTableEntry newEntry = CreateMaxEntry(j);
                    newEntry.Depth++;
                    ulong key = (ulong)j;
                    tt.Store(key, newEntry);
                }

                sw.Stop();

                sum += sw.Elapsed;
            }

            Trace.WriteLine(string.Format("Average Ticks: {0}", sum.Ticks / iterations));
        }
 public SearchService(PossibleMovesService possibleMovesService, IEvaluationService evaluationService, IInterruptor interruptor)
 {
     PossibleMovesService = possibleMovesService;
     EvaluationService    = evaluationService;
     Interruptor          = interruptor;
     TTable = new TranspositionTable <SearchTTEntry>(26);
 }
Beispiel #5
0
        public void TranspositionTable_MaxMemoryTest()
        {
            long expectedSizeInBytes = TranspositionTable.DefaultSizeInBytes;

            TranspositionTable tt = new TranspositionTable(expectedSizeInBytes);

            Assert.IsNotNull(tt);

            int count = tt.Capacity;

            long startMemoryUsage = GC.GetTotalMemory(true);

            for (int i = 0; i < tt.Capacity; i++)
            {
                ulong key = (ulong)i;
                tt.Store(key, CreateMaxEntry(i));
            }
            long endMemoryUsage = GC.GetTotalMemory(true);

            Assert.AreEqual(tt.Capacity, tt.Count);

            long actualSizeInBytes = endMemoryUsage - startMemoryUsage;

            double usageRatio = actualSizeInBytes / (double)expectedSizeInBytes;

            Trace.WriteLine(string.Format("Usage: {0}/{1} ({2:P2})", actualSizeInBytes, expectedSizeInBytes, usageRatio));

            Assert.IsTrue(usageRatio - 1.0 <= 0.01, string.Format("Table is too big {0:P2}: {1} bytes (~{2} bytes per entry)", usageRatio, actualSizeInBytes - expectedSizeInBytes, (actualSizeInBytes - expectedSizeInBytes) / tt.Count));
        }
 private void StartSearch()
 {
     TranspositionTable.Clear();
     ProcessNode();
     NodesSearched = 0;
     Moves.Clear();
     Score = 0;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="RegularSearch"/> class.
 /// </summary>
 /// <param name="transpositionTable">The transposition table.</param>
 /// <param name="historyTable">The history table.</param>
 /// <param name="killerTable">The killer table.</param>
 public RegularSearch(TranspositionTable transpositionTable, HistoryTable historyTable, KillerTable killerTable)
 {
     _transpositionTable = transpositionTable;
     _historyTable       = historyTable;
     _killerTable        = killerTable;
     _quiescenceSearch   = new QuiescenceSearch();
     _patternsDetector   = new PatternsDetector();
 }
Beispiel #8
0
 static Game()
 {
     CastlePositionalOr = new[, ]
     {
         { ECastlelingRights.WhiteOo, ECastlelingRights.BlackOo },
         { ECastlelingRights.WhiteOoo, ECastlelingRights.BlackOoo }
     };
     Table = new TranspositionTable(32);
 }
        private void IterativeDeepening_OnSearchUpdate(object sender, SearchStatistics statistics)
        {
            // Main search result
            _interactiveConsole.WriteLine($"  === Depth: {statistics.Depth}, Score: {statistics.Score}, Best: {statistics.PrincipalVariation[0]}, " +
                                          $"Time: {((float) statistics.SearchTime / 1000):F} s");

            // Normal search
            _interactiveConsole.WriteLine($"   Normal search: Nodes: {statistics.Nodes}, Leafs: {statistics.Leafs}, " +
                                          $"Branching factor: {statistics.BranchingFactor:F}, Beta cutoffs: {statistics.BetaCutoffs}");

            // Quiescence search
            _interactiveConsole.WriteLine($"   Q search: Nodes: {statistics.QNodes}, Leafs: {statistics.QLeafs}, " +
                                          $"Branching factor: {statistics.QBranchingFactor:F}, Beta cutoffs: {statistics.QBetaCutoffs}");

            // Total
            _interactiveConsole.WriteLine($"   Total: Nodes: {statistics.TotalNodes} ({((float)statistics.TotalNodesPerSecond / 1000000):F} MN/s), " +
                                          $"Leafs: {statistics.TotalLeafs}, Branching factor: {statistics.TotalBranchingFactor:F}, " +
                                          $"Beta cutoffs: {statistics.TotalBetaCutoffs}");

#if DEBUG
            // Beta cutoffs at first move
            _interactiveConsole.WriteLine($"   Beta cutoffs at first move: {statistics.BetaCutoffsAtFirstMove} ({statistics.BetaCutoffsAtFirstMovePercent:F} %), " +
                                          $"Q Beta cutoffs at first move: {statistics.QBetaCutoffsAtFirstMove} ({statistics.QBetaCutoffsAtFirstMovePercent:F} %)");

            // Transposition statistics
            _interactiveConsole.WriteLine($"   TT: " +
                                          $"Added: {statistics.TTAddedEntries}, " +
                                          $"Replacements: {statistics.TTReplacements} ({statistics.TTReplacesPercent:F} %), " +
                                          $"Hits: {statistics.TTHits} ({statistics.TTHitsPercent:F} %), " +
                                          $"Missed: {statistics.TTNonHits}, " +
                                          $"Filled: {TranspositionTable.GetFillLevel():F} %");

            // Pawn hash table statistics
            _interactiveConsole.WriteLine($"   PHT: " +
                                          $"Added: {statistics.EvaluationStatistics.PHTAddedEntries}, " +
                                          $"Replacements: {statistics.EvaluationStatistics.PHTReplacements} ({statistics.EvaluationStatistics.PHTReplacesPercent:F} %), " +
                                          $"Hits: {statistics.EvaluationStatistics.PHTHits} ({statistics.EvaluationStatistics.PHTHitsPercent:F} %), " +
                                          $"Missed: {statistics.EvaluationStatistics.PHTNonHits}, " +
                                          $"Filled: {PawnHashTable.GetFillLevel():F} %");

            // Evaluation hash table statistics
            _interactiveConsole.WriteLine($"   EHT: " +
                                          $"Added: {statistics.EvaluationStatistics.EHTAddedEntries}, " +
                                          $"Replacements: {statistics.EvaluationStatistics.EHTReplacements} ({statistics.EvaluationStatistics.EHTReplacesPercent:F} %), " +
                                          $"Hits: {statistics.EvaluationStatistics.EHTHits} ({statistics.EvaluationStatistics.EHTHitsPercent:F} %), " +
                                          $"Missed: {statistics.EvaluationStatistics.EHTNonHits}, " +
                                          $"Filled: {EvaluationHashTable.GetFillLevel():F} %");

            _interactiveConsole.WriteLine($"   Valid TT moves: {statistics.TTValidMoves}, Invalid TT moves: {statistics.TTInvalidMoves}, " +
                                          $"IID hits: {statistics.IIDHits}, Loud generations: {statistics.LoudMovesGenerated}, " +
                                          $"Quiet generations: {statistics.QuietMovesGenerated}");
#endif


            _interactiveConsole.WriteLine();
        }
Beispiel #10
0
        public void Run(params string[] parameters)
        {
            TranspositionTable.Clear();
            PawnHashTable.Clear();
            EvaluationHashTable.Clear();
            KillerHeuristic.Clear();
            HistoryHeuristic.Clear();

            _uciClient.BoardState.SetDefaultState();
        }
Beispiel #11
0
 public ArtemisEngine(GameState gameState, IEngineConfig config, OpeningBook openingBook)
 {
     this.gameState     = gameState;
     transpositionTable = new TranspositionTable(config);
     evConfig           = new EvaluationConfig();
     evaluator          = new PositionEvaluator(gameState, evConfig);
     Config             = config;
     this.openingBook   = openingBook;
     threadMaster       = new ThreadMaster(this, gameState, transpositionTable, config);
 }
Beispiel #12
0
        public void LoadGameAIConfig(XmlReader reader)
        {
            if (null == reader)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    ExpansionPieces expansionPieces = EnumUtils.ParseExpansionPieces(reader["GameType"]);

                    switch (reader.Name)
                    {
                    case "TranspositionTableSizeMB":
                        ParseTranspositionTableSizeMBValue(reader.ReadElementContentAsString());
                        break;

                    case "MaxHelperThreads":
                        ParseMaxHelperThreadsValue(reader.ReadElementContentAsString());
                        break;

                    case "PonderDuringIdle":
                        ParsePonderDuringIdleValue(reader.ReadElementContentAsString());
                        break;

                    case "MaxBranchingFactor":
                        ParseMaxBranchingFactorValue(reader.ReadElementContentAsString());
                        break;

                    case "ReportIntermediateBestMoves":
                        ParseReportIntermediateBestMovesValue(reader.ReadElementContentAsString());
                        break;

                    case "MetricWeights":
                        SetStartMetricWeights(expansionPieces, MetricWeights.ReadMetricWeightsXml(reader.ReadSubtree()));
                        SetEndMetricWeights(expansionPieces, MetricWeights.ReadMetricWeightsXml(reader.ReadSubtree()));
                        break;

                    case "StartMetricWeights":
                        SetStartMetricWeights(expansionPieces, MetricWeights.ReadMetricWeightsXml(reader.ReadSubtree()));
                        break;

                    case "EndMetricWeights":
                        SetEndMetricWeights(expansionPieces, MetricWeights.ReadMetricWeightsXml(reader.ReadSubtree()));
                        break;

                    case "InitialTranspositionTable":
                        SetInitialTranspositionTable(expansionPieces, TranspositionTable.ReadTranspositionTableXml(reader.ReadSubtree()));
                        break;
                    }
                }
            }
        }
Beispiel #13
0
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult dlg = MessageBox.Show("Da li ste sigurni da zelite da zatvorite igru?", "Zatvaranje igre", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);

            if (dlg == DialogResult.Cancel)
            {
                e.Cancel = true;
            }
            this.Hide();
            TranspositionTable.Serialize(game.Computer.TranspTable);
        }
Beispiel #14
0
 public InfoNewPv(
     int positionCount,
     long elapsedMilliseconds,
     int depth,
     uint currentMove,
     double score,
     TranspositionTable transpositionTable)
     : base(positionCount, elapsedMilliseconds, depth, transpositionTable)
 {
     this.CurrentMove = currentMove;
     this.Score       = score;
 }
Beispiel #15
0
 public PVSearch(ArtemisEngine engine, GameState gameState, TranspositionTable transpositionTable, KillerMoves killerMoves, PositionEvaluator evaluator, MoveEvaluator moveEvaluator,
                 QuiescenceSearch quietSearch, ConcurrentDictionary <ulong, bool> searchedNodes, IEngineConfig config)
 {
     this.engine             = engine;
     this.gameState          = gameState;
     this.transpositionTable = transpositionTable;
     this.killerMoves        = killerMoves;
     this.evaluator          = evaluator;
     this.moveEvaluator      = moveEvaluator;
     this.quietSearch        = quietSearch;
     this.searchedNodes      = searchedNodes;
     this.config             = config;
 }
Beispiel #16
0
 public ThreadMaster(ArtemisEngine engine, GameState gameState, TranspositionTable transpositionTable, IEngineConfig config)
 {
     this.gameState          = gameState;
     this.transpositionTable = transpositionTable;
     this.config             = config;
     threadsNum    = Environment.ProcessorCount;
     searchThreads = new SearchThread[threadsNum];
     for (int t = 0; t < threadsNum; t++)
     {
         GameState threadState = new GameState(gameState.PregeneratedAttacks, gameState.ZobristHashUtils);
         searchThreads[t] = new SearchThread(engine, this, threadState, transpositionTable, searchedNodes, config);
     }
 }
Beispiel #17
0
        private void MainForm_Load(object sender, EventArgs e)
        {
            tlp.Enabled = false;
            Stopwatch s = new Stopwatch();

            s.Start();
            LoadingForm lf = new LoadingForm();

            lf.Show();
            lf.Enabled = false;
            // lf.Refresh();
            game.Computer.TranspTable = TranspositionTable.Deserialize();
            s.Stop();
            if (s.ElapsedMilliseconds < 2000)
            {
                System.Threading.Thread.Sleep(2000);
            }
            lf.Close();
        }
Beispiel #18
0
        public void TestTranspositionTable()
        {
            var transpositionTable = new TranspositionTable(FakeLogger.Instance, TranspositionTableHelper.SizeInMegaBytesRange.Lower);

            Assert.That(transpositionTable.Version, Is.Not.EqualTo(0));

            const long       Key      = 0x12345678ABCDEF01L;
            const long       OtherKey = 0x987654321L;
            const ScoreBound Bound    = ScoreBound.Exact;
            const int        Depth    = CommonEngineConstants.MaxPlyDepthUpperLimit;

            var bestMove   = GameMove.FromStringNotation("b2b1q");
            var score      = EvaluationScore.Mate;
            var localScore = new EvaluationScore(-789);

            var entry = new TranspositionTableEntry(Key, bestMove, score, localScore, Bound, Depth);

            transpositionTable.Save(ref entry);
            Assert.That(entry.Version, Is.EqualTo(transpositionTable.Version));

            Assert.That(transpositionTable.ProbeCount, Is.EqualTo(0));
            Assert.That(transpositionTable.HitCount, Is.EqualTo(0));

            var foundEntry1 = transpositionTable.Probe(Key);

            Assert.That(transpositionTable.ProbeCount, Is.EqualTo(1));
            Assert.That(transpositionTable.HitCount, Is.EqualTo(1));
            Assert.That(foundEntry1.HasValue, Is.True);
            Assert.That(foundEntry1.Value.Key, Is.EqualTo(Key));
            Assert.That(foundEntry1.Value.BestMove, Is.EqualTo(bestMove));
            Assert.That(foundEntry1.Value.Score, Is.EqualTo(score));
            Assert.That(foundEntry1.Value.LocalScore, Is.EqualTo(localScore));
            Assert.That(foundEntry1.Value.Bound, Is.EqualTo(Bound));
            Assert.That(foundEntry1.Value.Depth, Is.EqualTo(Depth));
            Assert.That(foundEntry1.Value.Version, Is.EqualTo(transpositionTable.Version));

            var foundEntry2 = transpositionTable.Probe(OtherKey);

            Assert.That(transpositionTable.ProbeCount, Is.EqualTo(2));
            Assert.That(transpositionTable.HitCount, Is.EqualTo(1));
            Assert.That(foundEntry2.HasValue, Is.False);
        }
Beispiel #19
0
        private bool ProcessNode()
        {
            int hashKey = WorkingTableau.GetUpPilesHashKey();

            if (TranspositionTable.Contains(hashKey))
            {
                return(false);
            }
            TranspositionTable.Add(hashKey);

            NodesSearched++;
            double score = CalculateSearchScore();

            if (score > Score)
            {
                Score = score;
                Moves.Copy(WorkingTableau.Moves);
            }

            return(true);
        }
        private void Test(BoardState boardState, string name, int depth)
        {
            _interactiveConsole.WriteLine($" == {name}:");

            TranspositionTable.Clear();
            PawnHashTable.Clear();
            EvaluationHashTable.Clear();
            KillerHeuristic.Clear();
            HistoryHeuristic.Clear();

            var context = new SearchContext(boardState)
            {
                MaxDepth = depth
            };

            IterativeDeepening.OnSearchUpdate += IterativeDeepening_OnSearchUpdate;
            IterativeDeepening.FindBestMove(context);
            IterativeDeepening.OnSearchUpdate -= IterativeDeepening_OnSearchUpdate;

            _interactiveConsole.WriteLine();
        }
Beispiel #21
0
    public Playfield QStep()
    {
        GC.Collect();
        float maxQValue = Single.MinValue;
        Playfield bestState = lastState;
        //epsilon greedy             

        //List<Action> moves = Movegenerator.Instance.getMoveList(lastState, false, false, true);
        //int prevCount = lastState.playerSecond.ownMinions.Count;
        tt = new TranspositionTable();
        lastState.debugMinions();
        tt.addToMap(new Playfield(lastState));
        List<Playfield> moves = new List<Playfield>();
        //Playfield currentState = new Playfield(lastState).endTurn(false, false); //if need end turn
        //moves.Add(new Playfield(lastState));
        getAllpossibleStates(lastState, ref moves);

        Helpfunctions.Instance.logg("movesize = " + moves.Count);

        foreach (Playfield p in moves) {
            Helpfunctions.Instance.logg("===============P:hashkey = " + tt.getHashkey(p));
            p.printActions();
            p.printBoard();
        }

        if (moves.Count == 0)
        {
            return bestState;
        }

        if (GameManager.getRNG().NextDouble() < EPSILON)
        {
            bestState = moves[GameManager.getRNG().Next(moves.Count)];
        }
        else
        {
            foreach (Playfield posState in moves)
            {
                float QValue = Q(posState);
                if (QValue > maxQValue)
                {
                    maxQValue = QValue;
                    bestState = posState;
                    //if (afterState.playerSecond.ownMinions.Count == 0 && prevCount != 0 && afterState.playerFirst.ownMinions.Count != 0)//hardcode player second
                    //{
                    //    reward = 1;
                    //    Helpfunctions.Instance.logg("board reward received");
                    //}
                    if ((playerSide && bestState.getGameResult() == 0) || (!playerSide && bestState.getGameResult() == 1))
                    {
                        //reward = afterState.turnCounter;
                        reward = 1; //is it good?
                        Helpfunctions.Instance.logg("win reward received");
                    }
                    else
                    {
                        reward = 0;
                    }
                }
            }
        }

        //update weights
        float difference = reward + DISCOUNT_FACTOR * maxQValue - qLast;
        //if(debug) System.out.printf("%.5f\n", difference);
        List<float> features = getFeatures(lastState);
        //printFeatures(); //self play? 相减? 检验正确性(update每一步打出来) tile coding? binary?
        lastState.debugMinions();
        for (int j = 0; j < NUM_FEATURES; j++)
        {
            //if(debug) System.out.printf("w%d = %.5f + %.5f * %.5f * %.1f = ", i, weights.get(i), LEARNING_RATE, difference, features.get(i));
            weights[j] = weights[j] + LEARNING_RATE * difference * features[j];
            //if(debug) System.out.printf("%.5f\n", weights.get(i));
        }
        normalizeWeights();

        lastState = bestState;
        qLast = maxQValue;


        Helpfunctions.Instance.logg("best:");
        bestState.printActions();

        return bestState;

    }
Beispiel #22
0
        public SearchThread(ArtemisEngine engine, ThreadMaster master, GameState gameState, TranspositionTable transpositionTable, ConcurrentDictionary <ulong, bool> searchedNodes, IEngineConfig config)
        {
            this.master    = master;
            this.gameState = gameState;
            EvaluationConfig evConfig = new EvaluationConfig();

            evaluator     = new PositionEvaluator(gameState, evConfig);
            moveEvaluator = new MoveEvaluator(evConfig);
            quietSearch   = new QuiescenceSearch(engine, gameState, evaluator, moveEvaluator);
            pvSearch      = new PVSearch(engine, gameState, transpositionTable, killerMoves, evaluator, moveEvaluator, quietSearch, searchedNodes, config);
            this.config   = config;
        }
Beispiel #23
0
        public static int FindBestMove(SearchContext context, int depth, int ply, int alpha, int beta, bool allowNullMove, bool friendlyKingInCheck)
        {
            if (context.Statistics.Nodes >= context.MaxNodesCount)
            {
                context.AbortSearch = true;
                return(0);
            }

            if (context.AbortSearch)
            {
                return(0);
            }

            context.Statistics.Nodes++;

            if (context.BoardState.Pieces[context.BoardState.ColorToMove][Piece.King] == 0)
            {
                context.Statistics.Leafs++;
                return(-EvaluationConstants.Checkmate + ply);
            }

            if (context.BoardState.IsThreefoldRepetition())
            {
                context.Statistics.Leafs++;
                return(EvaluationConstants.ThreefoldRepetition);
            }

            if (context.BoardState.IsInsufficientMaterial())
            {
                if (!friendlyKingInCheck && !context.BoardState.IsKingChecked(ColorOperations.Invert(context.BoardState.ColorToMove)))
                {
                    context.Statistics.Leafs++;
                    return(EvaluationConstants.InsufficientMaterial);
                }
            }

            if (context.BoardState.IsFiftyMoveRuleDraw())
            {
                context.Statistics.Leafs++;

                if (context.BoardState.IsKingChecked(ColorOperations.Invert(context.BoardState.ColorToMove)))
                {
                    return(EvaluationConstants.Checkmate + ply);
                }

                return(EvaluationConstants.ThreefoldRepetition);
            }

            if (depth <= 0)
            {
                context.Statistics.Leafs++;
                return(QuiescenceSearch.FindBestMove(context, depth, ply, alpha, beta));
            }

            var originalAlpha = alpha;
            var pvNode        = beta - alpha > 1;

            var entry    = TranspositionTable.Get(context.BoardState.Hash);
            var hashMove = Move.Empty;

            if (entry.Flags != TranspositionTableEntryFlags.Invalid && entry.IsKeyValid(context.BoardState.Hash))
            {
#if DEBUG
                context.Statistics.TTHits++;
#endif
                if (entry.Flags != TranspositionTableEntryFlags.AlphaScore)
                {
                    var isMoveLegal = context.BoardState.IsMoveLegal(entry.BestMove);
                    if (isMoveLegal)
                    {
                        hashMove = entry.BestMove;
#if DEBUG
                        context.Statistics.TTValidMoves++;
#endif
                    }
#if DEBUG
                    else
                    {
                        context.Statistics.TTInvalidMoves++;
                    }
#endif
                }

                if (entry.Depth >= depth)
                {
                    switch (entry.Flags)
                    {
                    case TranspositionTableEntryFlags.AlphaScore:
                    {
                        if (entry.Score < beta)
                        {
                            beta = entry.Score;
                        }

                        break;
                    }

                    case TranspositionTableEntryFlags.ExactScore:
                    {
                        if (!pvNode)
                        {
                            entry.Score = (short)TranspositionTable.TTToRegularScore(entry.Score, ply);
                            return(entry.Score);
                        }

                        break;
                    }

                    case TranspositionTableEntryFlags.BetaScore:
                    {
                        if (entry.Score > alpha)
                        {
                            alpha = entry.Score;
                        }

                        break;
                    }
                    }

                    if (alpha >= beta)
                    {
                        context.Statistics.BetaCutoffs++;
                        return(entry.Score);
                    }
                }
            }
#if DEBUG
            else
            {
                context.Statistics.TTNonHits++;
            }
#endif

            if (NullWindowCanBeApplied(context.BoardState, depth, allowNullMove, pvNode, friendlyKingInCheck))
            {
                context.BoardState.MakeNullMove();
                var score = -FindBestMove(context, depth - 1 - SearchConstants.NullWindowDepthReduction, ply + 1, -beta, -beta + 1, false, false);
                context.BoardState.UndoNullMove();

                if (score >= beta)
                {
                    context.Statistics.BetaCutoffs++;
                    return(score);
                }
            }

            if (IIDCanBeApplied(depth, entry.Flags, hashMove))
            {
                FindBestMove(context, depth - 1 - SearchConstants.IIDDepthReduction, ply, alpha, beta, allowNullMove, friendlyKingInCheck);

                var iidEntry = TranspositionTable.Get(context.BoardState.Hash);
                if (iidEntry.IsKeyValid(context.BoardState.Hash))
                {
                    hashMove = iidEntry.BestMove;

#if DEBUG
                    context.Statistics.IIDHits++;
#endif
                }
            }

            Span <Move>  moves      = stackalloc Move[SearchConstants.MaxMovesCount];
            Span <short> moveValues = stackalloc short[SearchConstants.MaxMovesCount];
            var          bestMove   = Move.Empty;
            var          movesCount = 0;

            var loudMovesGenerated  = false;
            var quietMovesGenerated = false;

            if (hashMove == Move.Empty)
            {
                movesCount = context.BoardState.GetLoudMoves(moves, 0);
                MoveOrdering.AssignLoudValues(context.BoardState, moves, moveValues, movesCount, depth, bestMove);
                loudMovesGenerated = true;

                context.Statistics.LoudMovesGenerated++;

                if (movesCount == 0)
                {
                    movesCount = context.BoardState.GetQuietMoves(moves, 0);
                    MoveOrdering.AssignQuietValues(context.BoardState, moves, moveValues, 0, movesCount, depth);
                    quietMovesGenerated = true;

                    context.Statistics.QuietMovesGenerated++;
                }
            }
            else
            {
                moves[0]      = hashMove;
                moveValues[0] = MoveOrderingConstants.HashMove;
                movesCount    = 1;
            }

            var pvs = true;
            for (var moveIndex = 0; moveIndex < movesCount; moveIndex++)
            {
                MoveOrdering.SortNextBestMove(moves, moveValues, movesCount, moveIndex);

                if (loudMovesGenerated && moves[moveIndex] == hashMove)
                {
                    goto postLoopOperations;
                }

                if (loudMovesGenerated && !quietMovesGenerated && moveValues[moveIndex] < 100)
                {
                    var loudMovesCount = movesCount;

                    movesCount = context.BoardState.GetQuietMoves(moves, movesCount);
                    MoveOrdering.AssignQuietValues(context.BoardState, moves, moveValues, loudMovesCount, movesCount, depth);
                    MoveOrdering.SortNextBestMove(moves, moveValues, movesCount, moveIndex);
                    quietMovesGenerated = true;

                    context.Statistics.QuietMovesGenerated++;

                    if (moves[moveIndex] == hashMove)
                    {
                        goto postLoopOperations;
                    }
                }

                if (context.MoveRestrictions != null && ply == 0)
                {
                    if (!context.MoveRestrictions.Contains(moves[moveIndex]))
                    {
                        continue;
                    }
                }

                context.BoardState.MakeMove(moves[moveIndex]);

                var score            = 0;
                var enemyKingInCheck = context.BoardState.IsKingChecked(context.BoardState.ColorToMove);

                if (pvs)
                {
                    score = -FindBestMove(context, depth - 1, ply + 1, -beta, -alpha, allowNullMove, enemyKingInCheck);
                    pvs   = false;
                }
                else
                {
                    var reducedDepth = depth;

                    if (LMRCanBeApplied(depth, friendlyKingInCheck, enemyKingInCheck, moveIndex, moves))
                    {
                        reducedDepth = LMRGetReducedDepth(depth, pvNode);
                    }

                    score = -FindBestMove(context, reducedDepth - 1, ply + 1, -alpha - 1, -alpha, allowNullMove, enemyKingInCheck);
                    if (score > alpha)
                    {
                        score = -FindBestMove(context, depth - 1, ply + 1, -beta, -alpha, allowNullMove, enemyKingInCheck);
                    }
                }

                context.BoardState.UndoMove(moves[moveIndex]);

                if (score > alpha)
                {
                    alpha    = score;
                    bestMove = moves[moveIndex];

                    if (alpha >= beta)
                    {
                        if (moves[moveIndex].IsQuiet())
                        {
                            KillerHeuristic.AddKillerMove(moves[moveIndex], context.BoardState.ColorToMove, depth);
                            HistoryHeuristic.AddHistoryMove(context.BoardState.ColorToMove, moves[moveIndex].From, moves[moveIndex].To, depth);
                        }

#if DEBUG
                        if (moveIndex == 0)
                        {
                            context.Statistics.BetaCutoffsAtFirstMove++;
                        }
                        else
                        {
                            context.Statistics.BetaCutoffsNotAtFirstMove++;
                        }
#endif

                        context.Statistics.BetaCutoffs++;
                        break;
                    }
                }

postLoopOperations:
                if (!loudMovesGenerated)
                {
                    movesCount = context.BoardState.GetLoudMoves(moves, 0);
                    MoveOrdering.AssignLoudValues(context.BoardState, moves, moveValues, movesCount, depth, bestMove);
                    moveIndex          = -1;
                    loudMovesGenerated = true;

                    context.Statistics.LoudMovesGenerated++;

                    if (movesCount == 0)
                    {
                        movesCount = context.BoardState.GetQuietMoves(moves, 0);
                        MoveOrdering.AssignQuietValues(context.BoardState, moves, moveValues, 0, movesCount, depth);
                        quietMovesGenerated = true;

                        context.Statistics.QuietMovesGenerated++;
                    }
                }

                if (!quietMovesGenerated && moveIndex == movesCount - 1)
                {
                    var loudMovesCount = movesCount;

                    movesCount = context.BoardState.GetQuietMoves(moves, movesCount);
                    MoveOrdering.AssignQuietValues(context.BoardState, moves, moveValues, loudMovesCount, movesCount, depth);
                    quietMovesGenerated = true;

                    context.Statistics.QuietMovesGenerated++;
                }
            }

            // Don't save invalid scores to the transposition table
            if (context.AbortSearch)
            {
                return(0);
            }

            // Don't add invalid move (done after checkmate) to prevent strange behaviors
            if (alpha == -(-EvaluationConstants.Checkmate + ply + 1))
            {
                return(alpha);
            }

            // Return draw score or checkmate score as leafs
            if (alpha == -EvaluationConstants.Checkmate + ply + 2)
            {
                if (context.BoardState.IsKingChecked(context.BoardState.ColorToMove))
                {
                    return(alpha);
                }

                return(0);
            }

            if (entry.Age != context.TranspositionTableEntryAge || entry.Depth <= depth)
            {
                var valueToSave = alpha;
                var entryType   = alpha <= originalAlpha ? TranspositionTableEntryFlags.AlphaScore :
                                  alpha >= beta ? TranspositionTableEntryFlags.BetaScore :
                                  TranspositionTableEntryFlags.ExactScore;

                if (entryType == TranspositionTableEntryFlags.ExactScore)
                {
                    valueToSave = TranspositionTable.RegularToTTScore(alpha, ply);
                }

                TranspositionTable.Add(context.BoardState.Hash, new TranspositionTableEntry(
                                           context.BoardState.Hash,
                                           (short)valueToSave, bestMove,
                                           (byte)depth, entryType,
                                           (byte)context.TranspositionTableEntryAge)
                                       );

#if DEBUG
                if (entry.Flags != TranspositionTableEntryFlags.Invalid)
                {
                    context.Statistics.TTReplacements++;
                }

                context.Statistics.TTAddedEntries++;
#endif
            }

            return(alpha);
        }
Beispiel #24
0
 public void setTTLogSize(int logSize)
 {
     tt = new TranspositionTable(logSize);
 }
Beispiel #25
0
 public RegularSearch(TranspositionTable transpositionTable)
 {
     _transpositionTable = transpositionTable;
     _quiescenceSearch   = new QuiescenceSearch();
 }
Beispiel #26
0
 static Game()
 {
     Table = new TranspositionTable(256);
 }
Beispiel #27
0
 void Awake()
 {
     zobristKeys = new ZobristKeys(61, 2);
     //zobristKeys.Print();
     transpositionTable = new TranspositionTable(hashTableLength);
 }
Beispiel #28
0
        public void SaveGameAIConfig(XmlWriter writer, string rootName, ConfigSaveType configSaveType)
        {
            if (null == writer)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            if (string.IsNullOrWhiteSpace(rootName))
            {
                throw new ArgumentNullException(nameof(rootName));
            }

            writer.WriteStartElement(rootName);

            if (configSaveType.HasFlag(ConfigSaveType.BasicOptions))
            {
                if (TranspositionTableSizeMB.HasValue)
                {
                    writer.WriteElementString("TranspositionTableSizeMB", TranspositionTableSizeMB.Value.ToString());
                }

                if (!_maxHelperThreads.HasValue)
                {
                    writer.WriteElementString("MaxHelperThreads", "Auto");
                }
                else if (_maxHelperThreads.Value == 0)
                {
                    writer.WriteElementString("MaxHelperThreads", "None");
                }
                else
                {
                    writer.WriteElementString("MaxHelperThreads", _maxHelperThreads.Value.ToString());
                }

                writer.WriteElementString("PonderDuringIdle", PonderDuringIdle.ToString());

                if (MaxBranchingFactor.HasValue)
                {
                    writer.WriteElementString("MaxBranchingFactor", MaxBranchingFactor.Value.ToString());
                }

                writer.WriteElementString("ReportIntermediateBestMoves", ReportIntermediateBestMoves.ToString());
            }

            if (configSaveType.HasFlag(ConfigSaveType.MetricWeights))
            {
                foreach (KeyValuePair <ExpansionPieces, MetricWeights[]> kvp in MetricWeightSet)
                {
                    ExpansionPieces gameType = kvp.Key;
                    MetricWeights[] mw       = kvp.Value;

                    if (null != mw[0] && null != mw[1])
                    {
                        mw[0].WriteMetricWeightsXml(writer, "StartMetricWeights", gameType);
                        mw[1].WriteMetricWeightsXml(writer, "EndMetricWeights", gameType);
                    }
                    else if (null != mw[0] && null == mw[1])
                    {
                        mw[0].WriteMetricWeightsXml(writer, gameType: gameType);
                    }
                }
            }

            if (configSaveType.HasFlag(ConfigSaveType.InitialTranspositionTable))
            {
                foreach (KeyValuePair <ExpansionPieces, TranspositionTable> kvp in InitialTranspositionTables)
                {
                    ExpansionPieces    gameType = kvp.Key;
                    TranspositionTable tt       = kvp.Value;

                    tt?.WriteTranspositionTableXml(writer, "InitialTranspositionTable", gameType);
                }
            }

            writer.WriteEndElement();
        }
Beispiel #29
0
        public void TranspositionTable_NewTest()
        {
            TranspositionTable tt = new TranspositionTable();

            Assert.IsNotNull(tt);
        }
Beispiel #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AICore"/> class.
 /// </summary>
 public AICore()
 {
     _transpositionTable = new TranspositionTable();
 }
Beispiel #31
0
 public AICore()
 {
     _transpositionTable = new TranspositionTable();
     _regularSearch      = new RegularSearch(_transpositionTable);
 }