public static MetricWeights ReadMetricWeightsXml(XmlReader xmlReader) { if (null == xmlReader) { throw new ArgumentNullException("xmlReader"); } MetricWeights mw = new MetricWeights(); while (xmlReader.Read()) { if (xmlReader.IsStartElement() && !xmlReader.Name.EndsWith("MetricWeights")) { string key = xmlReader.Name; double value = xmlReader.ReadElementContentAsDouble(); BugType bugType; BugTypeWeight bugTypeWeight; if (TryParseKeyName(key, out bugType, out bugTypeWeight)) { mw.Set(bugType, bugTypeWeight, value + mw.Get(bugType, bugTypeWeight)); } } } return(mw); }
public GameAI() { StartMetricWeights = new MetricWeights(); EndMetricWeights = new MetricWeights(); TranspositionTable = new TranspositionTable(); }
public GameAI(GameAIConfig config) { if (null == config) { throw new ArgumentNullException("config"); } StartMetricWeights = config.StartMetricWeights?.Clone() ?? new MetricWeights(); EndMetricWeights = config.EndMetricWeights?.Clone() ?? new MetricWeights(); if (config.TranspositionTableSizeMB.HasValue) { if (config.TranspositionTableSizeMB.Value <= 0) { throw new ArgumentOutOfRangeException("config.TranspositionTableSizeMB"); } _transpositionTable = new TranspositionTable(config.TranspositionTableSizeMB.Value * 1024 * 1024); } else { _transpositionTable = new TranspositionTable(); } if (config.MaxBranchingFactor.HasValue) { if (config.MaxBranchingFactor.Value <= 0) { throw new ArgumentOutOfRangeException("config.MaxBranchingFactor"); } _maxBranchingFactor = config.MaxBranchingFactor.Value; } }
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; }
public MetricWeights Clone() { MetricWeights clone = new MetricWeights(); clone.CopyFrom(this); return(clone); }
public void CopyFrom(MetricWeights source) { if (null == source) { throw new ArgumentNullException("source"); } Array.Copy(source._bugTypeWeights, _bugTypeWeights, source._bugTypeWeights.Length); }
public void Add(MetricWeights a) { if (null == a) { throw new ArgumentNullException("a"); } for (int i = 0; i < _bugTypeWeights.Length; i++) { _bugTypeWeights[i] += a._bugTypeWeights[i]; } }
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); }
public MetricWeights GetNormalized(double targetMaxValue = 100.0, bool round = true, int decimals = 6) { if (targetMaxValue <= 0.0) { throw new ArgumentOutOfRangeException("targetMaxValue"); } MetricWeights clone = Clone(); // Copy bug weights into local array double[] dblWeights = new double[clone._bugTypeWeights.Length]; Array.Copy(clone._bugTypeWeights, dblWeights, clone._bugTypeWeights.Length); double max = double.MinValue; foreach (double weight in dblWeights) { max = Math.Max(max, Math.Abs(weight)); } // Normalize to new range for (int i = 0; i < dblWeights.Length; i++) { double value = dblWeights[i]; int sign = Math.Sign(value); double absValue = Math.Abs(value); dblWeights[i] = sign * (absValue / max) * targetMaxValue; } // Populate clone with normalized weights for (int i = 0; i < clone._bugTypeWeights.Length; i++) { clone._bugTypeWeights[i] = round ? Math.Round(dblWeights[i], decimals) : dblWeights[i]; } return(clone); }