private double CalculateBoardScore(GameBoard gameBoard) { // Always score from white's point of view if (gameBoard.BoardState == BoardState.WhiteWins) { return(double.PositiveInfinity); } else if (gameBoard.BoardState == BoardState.BlackWins) { return(double.NegativeInfinity); } else if (gameBoard.BoardState == BoardState.Draw) { return(0.0); } ulong key = gameBoard.ZobristKey; if (_cachedBoardScores.TryLookup(key, out double score)) { return(score); } BoardMetrics boardMetrics = gameBoard.GetBoardMetrics(); score = CalculateBoardScore(boardMetrics, StartMetricWeights, EndMetricWeights); _cachedBoardScores.Store(key, score); return(score); }
private void DeltaFromTransTable(GameBoard gameBoard, HashSet <ulong> visitedKeys, CancellationToken token, out MetricWeights deltaStart, out MetricWeights deltaEnd) { MetricWeights ds = new MetricWeights(); MetricWeights de = new MetricWeights(); ulong key = gameBoard.ZobristKey; bool newKey = visitedKeys.Add(key); if (newKey && TranspositionTable.TryLookup(key, out TranspositionTableEntry tEntry) && tEntry.Depth > 1 && !token.IsCancellationRequested) { double colorValue = gameBoard.CurrentTurnColor == PlayerColor.White ? 1.0 : -1.0; double boardScore = colorValue * TruncateBounds(CalculateBoardScore(gameBoard)); double storedValue = TruncateBounds(tEntry.Value); BoardMetrics boardMetrics = gameBoard.GetBoardMetrics(); MetricWeights startGradient = GetGradient(boardMetrics); MetricWeights endGradient = startGradient.Clone(); double scaleFactor = TreeStrapStepConstant * (storedValue - boardScore); double startRatio = boardMetrics.PiecesInHand / (double)(boardMetrics.PiecesInHand + boardMetrics.PiecesInPlay); double endRatio = 1 - startRatio; startGradient.Scale(scaleFactor * startRatio * colorValue); endGradient.Scale(scaleFactor * endRatio * colorValue); if ((tEntry.Type == TranspositionTableEntryType.LowerBound || tEntry.Type == TranspositionTableEntryType.Exact) && storedValue > boardScore) { ds.Add(startGradient); de.Add(endGradient); } if ((tEntry.Type == TranspositionTableEntryType.UpperBound || tEntry.Type == TranspositionTableEntryType.Exact) && storedValue < boardScore) { ds.Add(startGradient); de.Add(endGradient); } foreach (Move move in GetValidMoves(gameBoard)) { if (token.IsCancellationRequested) { break; } gameBoard.TrustedPlay(move); DeltaFromTransTable(gameBoard, visitedKeys, token, out MetricWeights ds1, out MetricWeights de1); ds.Add(ds1); de.Add(de1); gameBoard.UndoLastMove(); } } deltaStart = ds; deltaEnd = de; }
private static double CalculateBoardScore(BoardMetrics boardMetrics, MetricWeights startMetricWeights, MetricWeights endMetricWeights) { double endScore = CalculateBoardScore(boardMetrics, endMetricWeights); if (boardMetrics.PiecesInHand == 0) { // In "end-game", no need to blend return(endScore); } else { // Pieces still in hand, blend start and end scores double startScore = CalculateBoardScore(boardMetrics, startMetricWeights); double startRatio = boardMetrics.PiecesInHand / (double)(boardMetrics.PiecesInHand + boardMetrics.PiecesInPlay); double endRatio = 1 - startRatio; return((startRatio * startScore) + (endRatio * endScore)); } }
private MetricWeights GetGradient(BoardMetrics boardMetrics) { MetricWeights gradient = new MetricWeights(); foreach (PieceName pieceName in EnumUtils.PieceNames) { BugType bugType = EnumUtils.GetBugType(pieceName); double colorValue = EnumUtils.GetColor(pieceName) == PlayerColor.White ? 1.0 : -1.0; gradient.Set(bugType, BugTypeWeight.InPlayWeight, gradient.Get(bugType, BugTypeWeight.InPlayWeight) + colorValue * boardMetrics[pieceName].InPlay); gradient.Set(bugType, BugTypeWeight.IsPinnedWeight, gradient.Get(bugType, BugTypeWeight.IsPinnedWeight) + colorValue * boardMetrics[pieceName].IsPinned); gradient.Set(bugType, BugTypeWeight.IsCoveredWeight, gradient.Get(bugType, BugTypeWeight.IsCoveredWeight) + colorValue * boardMetrics[pieceName].IsCovered); gradient.Set(bugType, BugTypeWeight.NoisyMoveWeight, gradient.Get(bugType, BugTypeWeight.NoisyMoveWeight) + colorValue * boardMetrics[pieceName].NoisyMoveCount); gradient.Set(bugType, BugTypeWeight.QuietMoveWeight, gradient.Get(bugType, BugTypeWeight.QuietMoveWeight) + colorValue * boardMetrics[pieceName].QuietMoveCount); gradient.Set(bugType, BugTypeWeight.FriendlyNeighborWeight, gradient.Get(bugType, BugTypeWeight.FriendlyNeighborWeight) + colorValue * boardMetrics[pieceName].FriendlyNeighborCount); gradient.Set(bugType, BugTypeWeight.EnemyNeighborWeight, gradient.Get(bugType, BugTypeWeight.EnemyNeighborWeight) + colorValue * boardMetrics[pieceName].EnemyNeighborCount); } return(gradient); }
private static double CalculateBoardScore(BoardMetrics boardMetrics, MetricWeights metricWeights) { double score = 0; foreach (PieceName pieceName in EnumUtils.PieceNames) { BugType bugType = EnumUtils.GetBugType(pieceName); double colorValue = EnumUtils.GetColor(pieceName) == PlayerColor.White ? 1.0 : -1.0; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.InPlayWeight) * boardMetrics[pieceName].InPlay; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.IsPinnedWeight) * boardMetrics[pieceName].IsPinned; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.IsCoveredWeight) * boardMetrics[pieceName].IsCovered; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.NoisyMoveWeight) * boardMetrics[pieceName].NoisyMoveCount; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.QuietMoveWeight) * boardMetrics[pieceName].QuietMoveCount; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.FriendlyNeighborWeight) * boardMetrics[pieceName].FriendlyNeighborCount; score += colorValue * metricWeights.Get(bugType, BugTypeWeight.EnemyNeighborWeight) * boardMetrics[pieceName].EnemyNeighborCount; } return(score); }