/// <summary> /// Add possible responses to "chooser", based on the situation in "game" and in "statesManager" /// </summary> public override void AddResponseOptions(Game game, StatesManager statesManager, ActionsChooser chooser) { if (!this.myPirate.CanMove || this.myPirate.State != PirateState.Free) { return; } int myMaxSteps = myPirate.MaxSpeed; int enemyMaxSteps; double multiplyer = Utils.Pow(1 - ((double)game.GetMyPiratesCount(PirateState.CarryingTreasure)) / game.GetMyPiratesCount(PirateState.Free, PirateState.CarryingTreasure), 2); ThreatenedTreasureState treasureState = statesManager.GetState <ThreatenedTreasureState>(); List <Treasure> treasures = treasureState.GetThreatenedTreasures().OrderBy(t => Game.ManhattanDistance(t, this.myPirate)).ToList(); while (treasures.Count > 0 && game.GetPirateOn(treasures[0]) != null) { treasures.Remove(treasures[0]); } if (treasures.Count == 0) { return; } if (Game.ManhattanDistance(this.myPirate, treasures[0]) > myMaxSteps) //only do area clear if close enough to capture treasure { return; } Treasure closestTreasure = treasures[0]; multiplyer *= closestTreasure.Value; foreach (Pirate enemy in game.GetEnemyPirates(PirateState.Free)) { enemyMaxSteps = enemy.MaxSpeed; if (Game.ManhattanDistance(enemy, closestTreasure) > enemyMaxSteps)//only do area clear if enemy is close enough to capture treasure { continue; } if (!Game.InAttackRange(this.myPirate, closestTreasure, this.myPirate.AttackRadius + 1)) //Get closer. { var sailOptions = game.GetCompleteSailOptions(this.myPirate, closestTreasure, (int)this.myPirate.AttackRadius + 1, (int)this.myPirate.AttackRadius + 1, Terrain.InEnemyRange, Terrain.CurrentTreasureLocation); foreach (var pair in sailOptions) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, pair.Key), this.Id); ap.AddTreasure(treasures[0]); double value = CLEAR_VALUE * multiplyer; ap.BurnInformation("Made in AreaClearEvent on Treasure {0} - case: not close enough, Value {1:F3}", closestTreasure.Id, value); chooser.AddActionsPack(ap, value); } } else if (Game.InAttackRange(this.myPirate, closestTreasure, this.myPirate.AttackRadius) && this.myPirate.CanAttack && enemy.DefenseDuration == 0 && Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius)) //Attack enemy. { ActionsPack ap = ActionsPack.NewCommandPack(game, new AttackCommand(this.myPirate, enemy), this.Id); ap.AddTreasure(treasures[0]); ap.AddEnemyPirate(enemy); double value = CLEAR_VALUE * multiplyer; ap.BurnInformation("Made in AreaClearEvent on Treasure {0} - case: too close, attack pirate {1}, Value: {2:F3}", closestTreasure.Id, enemy.Id, value); chooser.AddActionsPack(ap, value); } else if (Game.InAttackRange(this.myPirate, closestTreasure, this.myPirate.AttackRadius + 1)) //Stay Still. TODO: ask Adi/Itai why isn't this an else { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, this.myPirate), this.Id); ap.AddTreasure(closestTreasure); double value = CLEAR_VALUE * multiplyer; ap.BurnInformation("Made in AreaClearEvent on Treasure {0} - case: close enough, Value {1:F3}", closestTreasure.Id, value); chooser.AddActionsPack(ap, value); } } }
/// <summary> /// Add possible responses to "chooser", based on the situation in "game" and in "statesManager" /// </summary> public override void AddResponseOptions(Game game, StatesManager statesManager, ActionsChooser chooser) { if (!this.myPirate.CanMove || this.myPirate.State != PirateState.Free) //If my pirate can't move or isn't free, he can't go to fetch treasures. { return; } // Get threatened treasure state ThreatenedTreasureState treasureState = statesManager.GetState <ThreatenedTreasureState>(); // Get all the free treasures and sort them by manhattan distance to me List <Treasure> freeTreasures = treasureState.GetSafeTreasures().OrderBy(t => Game.ManhattanDistance(t, this.myPirate)).ToList(); // calculate the maximum amount of treasures to check int maxTreasuresToCheck = (int)Utils.Min(freeTreasures.Count, game.GetMyPiratesCount(PirateState.Free), game.ActionsPerTurn, game.MaxCommandsPerTurn); // remove all the excess treasures, based on their value Dictionary <int, int> usedTreasuresDict = new Dictionary <int, int>(); // the key is the value of the treasure, and the value is how many treasures with the value are already in the list for (int i = 0; i < freeTreasures.Count;) { if (usedTreasuresDict.ContainsKey(freeTreasures[i].Value)) { usedTreasuresDict[freeTreasures[i].Value]++; if (usedTreasuresDict[freeTreasures[i].Value] > maxTreasuresToCheck) { freeTreasures.RemoveAt(i); } else { i++; } } else { usedTreasuresDict.Add(freeTreasures[i].Value, 1); i++; } } double multiplyer = Utils.Pow(1 - ((double)game.GetMyPiratesCount(PirateState.CarryingTreasure)) / game.GetMyPiratesCount(PirateState.Free, PirateState.CarryingTreasure), 2); // try to sail to each treasure foreach (Treasure t in freeTreasures) { if (game.GetPirateOn(t) != null) // there is a pirate where the treasure is, most likely a drunk one. Leave it be. { continue; } ILocateable dest = t; // search for a speed powerup on the way to the treasure foreach (Powerup up in game.GetPowerups()) { if (up is SpeedPowerup && Game.OnTrack(myPirate, t, up)) { dest = up; break; } } var sailOptions = game.GetCompleteSailOptions(this.myPirate, dest, Terrain.EnemyLocation, Terrain.CurrentTreasureLocation); int maxActionsUsed = (int)Utils.Min(this.myPirate.MaxSpeed, game.ActionsPerTurn, Game.ManhattanDistance(this.myPirate, dest)); foreach (var pair in sailOptions) { if (sailOptions[0].Value > pair.Value) //sail only if it's actually better than staying in place { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, pair.Key), base.Id); ap.AddTreasure(t); double returnDistance = Game.ManhattanDistance(this.myPirate.InitialLocation, t); double maxDistance = game.Rows + game.Collumns; double value = (FETCH_VALUE - Utils.Pow(pair.Value, 0.9)) * multiplyer * ((maxDistance - returnDistance) / (maxDistance)); if (game.GetTreasuresCount(TreasureState.BeingCarried, TreasureState.Taken) == 0 && Game.ManhattanDistance(pair.Key, this.myPirate) == maxActionsUsed) { value += GAME_START_MULT; } value *= t.Value; if (myPirate.HasPowerup(SpeedPowerup.NAME)) { value *= SPEED_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in FetchTreasureEvent. Fetching Treasure: {0}, value: {1:F3}", t.Id, value); chooser.AddActionsPack(ap, value); } } } }