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); }
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); }
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(); }
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(); }
public void Run(params string[] parameters) { TranspositionTable.Clear(); PawnHashTable.Clear(); EvaluationHashTable.Clear(); KillerHeuristic.Clear(); HistoryHeuristic.Clear(); _uciClient.BoardState.SetDefaultState(); }
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); }
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; } } } }
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); }
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; }
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; }
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); } }
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(); }
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); }
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(); }
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; }
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; }
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); }
public void setTTLogSize(int logSize) { tt = new TranspositionTable(logSize); }
public RegularSearch(TranspositionTable transpositionTable) { _transpositionTable = transpositionTable; _quiescenceSearch = new QuiescenceSearch(); }
static Game() { Table = new TranspositionTable(256); }
void Awake() { zobristKeys = new ZobristKeys(61, 2); //zobristKeys.Print(); transpositionTable = new TranspositionTable(hashTableLength); }
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(); }
public void TranspositionTable_NewTest() { TranspositionTable tt = new TranspositionTable(); Assert.IsNotNull(tt); }
/// <summary> /// Initializes a new instance of the <see cref="AICore"/> class. /// </summary> public AICore() { _transpositionTable = new TranspositionTable(); }
public AICore() { _transpositionTable = new TranspositionTable(); _regularSearch = new RegularSearch(_transpositionTable); }