/// <summary> /// Calculate the mobility score for all amazons on the PieceGrid /// </summary> /// <param name="pieceGrid">PieceGrid to analyze</param> private void CalculateAllAmazonMobility(PieceGrid pieceGrid) { AmazonMobilityScores.Clear(); foreach (Point p in pieceGrid.Amazon1Points) { AmazonMobilityScores.Add(p, CalculateAmazonMobility(p, Owner.Player1, pieceGrid)); } foreach (Point p in pieceGrid.Amazon2Points) { AmazonMobilityScores.Add(p, CalculateAmazonMobility(p, Owner.Player2, pieceGrid)); } }
/// <summary> /// Build <see cref="LocalAdvantage"/> objects for each open space on the PieceGrid /// </summary> /// <param name="pieceGrid">PieceGrid to analyze</param> /// <param name="playerToMove">Player whos turn it is</param> private void CalculateLocalAdvantages(PieceGrid pieceGrid, Owner playerToMove) { LocalAdvantages.Clear(); foreach (var kvp in pieceGrid.PointPieces) { if (!(kvp.Value is Open)) { continue; } double player1QueenDistance = Player1QueenMinDistances[kvp.Key] ?? 1000d; double player2QueenDistance = Player2QueenMinDistances[kvp.Key] ?? 1000d; LocalAdvantage advantageValue = new LocalAdvantage { Player1QueenDistance = player1QueenDistance, Player2QueenDistance = player2QueenDistance, PlayerToMove = playerToMove, }; LocalAdvantages[kvp.Key] = advantageValue; } }
/// <summary> /// Build all the internal analysis data for the given PieceGrid /// </summary> /// <param name="pieceGrid">PieceGrid to analyze</param> /// <param name="playerToMove">Player whos turn it is</param> public void BuildAnalysis(PieceGrid pieceGrid, Owner playerToMove) { if (pieceGrid.Id == LastAnalyzedPieceGridId) { return; } LastAnalyzedPieceGridId = pieceGrid.Id; LocalAdvantages = new PointSquareArray <LocalAdvantage>(pieceGrid.Size); AmazonMobilityScores = new PointSquareArray <double>(pieceGrid.Size); SpecificQueenDistances = new PointSquareArray <PointSquareArray <double> >(pieceGrid.Size); SpecificKingDistances = new PointSquareArray <PointSquareArray <double> >(pieceGrid.Size); SpecificQueenDistances.Clear(); SpecificKingDistances.Clear(); Player1QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player1, true); Player1KingMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player1, false); Player2QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player2, true); Player2KingMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player2, false); CalculateLocalAdvantages(pieceGrid, playerToMove); CalculateAllAmazonMobility(pieceGrid); W = LocalAdvantages.Where(a => a.Value != null && a.Value.Player1Reachable && a.Value.Player2Reachable) .Sum(a => Math.Pow(2, -(Math.Abs(a.Value.Player1QueenDistance - a.Value.Player2QueenDistance)))); C1 = 2 * LocalAdvantages.Where(a => a.Value != null).Sum(a => Math.Pow(2, -(a.Value.Player1QueenDistance)) - Math.Pow(2, -(a.Value.Player2QueenDistance))); C2 = LocalAdvantages.Where(a => a.Value != null).Sum(a => Math.Min(1, Math.Max(-1, (a.Value.Player2KingDistance - a.Value.Player1KingDistance) / 6d))); T1 = LocalAdvantages.Where(a => a.Value != null).Sum(a => a.Value.DeltaQueen); T2 = LocalAdvantages.Where(a => a.Value != null).Sum(a => a.Value.DeltaKing); T = (F1(W) * T1) + (F2(W) * C1) + (F3(W) * C2) + (F4(W) * T2); double player1MobilitySum = AmazonMobilityScores.Where(s => pieceGrid.Amazon1Points.Contains(s.Key)) .Sum(s => IndividualWeightForM(W, s.Value)); double player2MobilitySum = AmazonMobilityScores.Where(s => pieceGrid.Amazon2Points.Contains(s.Key)) .Sum(s => IndividualWeightForM(W, s.Value)); M = player2MobilitySum - player1MobilitySum; }