public float Score(FastWorld w, int ownIndex, Util.FillResult fill) { int maxLength = 0; int sumLength = 0; int otherCount = 0; for (int i = 0; i < w.Snakes.Count; ++i) { if (i == ownIndex) { continue; } if (!w.Snakes[i].Alive) { continue; } sumLength += w.Snakes[i].Length; otherCount += 1; if (w.Snakes[i].Length > maxLength) { maxLength = w.Snakes[i].Length; } } float averageLength = sumLength / (float)otherCount; float interpLength = 0.9f * maxLength + 0.1f * averageLength; float deltaAdvantage = w.Snakes[ownIndex].Length - interpLength; float deltaMetric = ScoreDeltaAdvantage(deltaAdvantage); float deltaOnEatMetric = ScoreDeltaAdvantage(deltaAdvantage + 1); // If food distance metric is 1, want to be exactly as good as eating one // fruit. Since food distance metric is always less than 1, ensures that eating // is always better than guarding with proximity of 1. float foodMetricMultiplier = (deltaOnEatMetric - deltaMetric) * FruitMultiplierFactor; float score = deltaMetric + FoodDistanceMetric(w, ownIndex, fill) * foodMetricMultiplier; Debug.Assert(!float.IsNaN(score)); return(score); }
private float FoodDistanceMetric(FastWorld w, int ownIndex, Util.FillResult fill) { int bestOwnDistance = int.MaxValue; foreach (var fruit in w.Fruits) { var dist = fill.Distances[fruit.Y, fruit.X]; if (dist <= 0) { continue; } bestOwnDistance = Math.Min(bestOwnDistance, dist); } if (bestOwnDistance == int.MaxValue) { return(0); } return((float)Math.Exp(-FoodDistanceDecay * bestOwnDistance)); }