/// <summary> /// Calculates the best possible move for the specified parameters. /// </summary> /// <param name="color">The initial player.</param> /// <param name="bitboard">The bitboard.</param> /// <param name="preferredTime">Time allocated for AI.</param> /// <returns>The result of AI calculating.</returns> public AIResult Calculate(Color color, Bitboard bitboard, float preferredTime) { var result = new AIResult(); var colorSign = ColorOperations.ToSign(color); var stopwatch = new Stopwatch(); int estimatedTimeForNextIteration; result.Color = color; result.PreferredTime = preferredTime; if (bitboard.ReversibleMoves == 0 && preferredTime != 0) { _transpositionTable.Clear(); } stopwatch.Start(); do { result.Depth++; var stats = new AIStats(); result.Score = colorSign * _regularSearch.Do(color, new Bitboard(bitboard), result.Depth, AIConstants.InitialAlphaValue, AIConstants.InitialBetaValue, stats); result.PVNodes = GetPVNodes(bitboard, color); result.Stats = stats; result.Ticks = stopwatch.Elapsed.Ticks; OnThinkingOutput?.Invoke(this, new ThinkingOutputEventArgs(result)); estimatedTimeForNextIteration = (int)stopwatch.Elapsed.TotalMilliseconds * result.Stats.BranchingFactor; }while (estimatedTimeForNextIteration < preferredTime * 1000 && result.Depth < 12 && Math.Abs(result.Score) != AIConstants.MateValue); return(result); }
private void HelperTask(HelperTaskParameters param) { var historyTable = new HistoryTable(); var killerTable = new KillerTable(); var helperSearch = new RegularSearch(_transpositionTable, historyTable, killerTable); killerTable.SetInitialDepth(param.InitialDepth); helperSearch.Do(param.Color, param.Bitboard, param.InitialDepth, AIConstants.InitialAlphaValue, AIConstants.InitialBetaValue, param.Deadline, true, new AIStats()); }
/// <summary> /// Calculates the best possible move for the specified parameters. /// </summary> /// <param name="color">The initial player.</param> /// <param name="bitboard">The bitboard.</param> /// <param name="preferredTime">Time allocated for AI.</param> /// <param name="helperTasks">The helper tasks count (0 for single thread).</param> /// <returns>The result of AI calculating.</returns> public AIResult Calculate(Color color, Bitboard bitboard, float preferredTime, int helperTasks) { var result = new AIResult(); var colorSign = ColorOperations.ToSign(color); var stopwatch = new Stopwatch(); int estimatedTimeForNextIteration; var historyTable = new HistoryTable(); var killerTable = new KillerTable(); var regularSearch = new RegularSearch(_transpositionTable, historyTable, killerTable); result.Color = color; result.PreferredTime = preferredTime; var deadline = preferredTime != 0 ? DateTime.Now.AddSeconds(preferredTime * 2).Ticks : DateTime.Now.AddSeconds(1).Ticks; historyTable.Clear(); killerTable.Clear(); if (bitboard.ReversibleMoves == 0 && preferredTime > 0) { _transpositionTable.Clear(); } stopwatch.Start(); do { result.Depth++; killerTable.SetInitialDepth(result.Depth); if (result.Depth >= AIConstants.MinimalDepthToStartHelperThreads) { for (var i = 0; i < helperTasks; i++) { var param = new HelperTaskParameters { Bitboard = new Bitboard(bitboard), Color = color, Deadline = deadline, InitialDepth = result.Depth }; Task.Run(() => HelperTask(param)); } } var stats = new AIStats(); var score = colorSign * regularSearch.Do(color, new Bitboard(bitboard), result.Depth, AIConstants.InitialAlphaValue, AIConstants.InitialBetaValue, deadline, false, stats); if (DateTime.Now.Ticks <= deadline) { result.PVNodes = GetPVNodes(bitboard, color); result.Score = score; OnThinkingOutput?.Invoke(this, new ThinkingOutputEventArgs(result)); } else { result.Depth--; _transpositionTable.Clear(); } result.Stats = stats; result.Ticks = stopwatch.Elapsed.Ticks; estimatedTimeForNextIteration = (int)stopwatch.Elapsed.TotalMilliseconds * result.Stats.BranchingFactor; }while (estimatedTimeForNextIteration < preferredTime * 1000 && result.Depth < AIConstants.MaxDepth && Math.Abs(result.Score) != AIConstants.MateValue); return(result); }