/// <summary> /// Executes the best commands out of the given ActionsChooser /// </summary> public void Execute(ActionsChooser chooser) { // if chooser is null if (chooser == null) { return; } ActionsPack bestPack = chooser.ChooseBestStableCombination(); //increase readability of game-log this.Log(LogType.Events, LogImportance.ExtremelyImportant, " "); this.Log(LogType.Events, LogImportance.ExtremelyImportant, "------START-EVENT-INFO------"); // execute all the commands from the best ActionsPack chosen foreach (Command cmd in bestPack.GetCommands()) { if (cmd == null) { continue; } cmd.Execute(this.NativeObject); this.Log(LogType.Events, LogImportance.ExtremelyImportant, cmd); // log the command in-game foreach (string info in cmd.GetAdditionalInformation()) // log the additional info in-game { this.Log(LogType.Events, LogImportance.ExtremelyImportant, "Additional information: {0}", info); } this.Log(LogType.Events, LogImportance.ExtremelyImportant, " "); } //increase readability of game-log this.Log(LogType.Events, LogImportance.ExtremelyImportant, "-------END-EVENT-INFO-------"); this.Log(LogType.Events, LogImportance.ExtremelyImportant, " "); }
//////////Methods////////// /// <summary> /// The method that the engine calls whenever our turn arrives /// </summary> public void DoTurn(IPirateGame game) { game.Debug("start turn at {0}", game.TimeRemaining()); // if this is the first turn if (game.GetTurn() == 1) { // create a new game enviroment this.game = new Game(game); // initialize the event list, and fill it up! this.events = new List <Event>(); this.AddEvents(); // initialize the states manager, and fill it up! this.statesManager = new StatesManager(); this.AddStates(); // initialize the actions chooser this.actionsChooser = new ActionsChooser(this.game); } // if this is NOT the first turn else { // update the game enviroment this.game.Update(game); // update the states manager this.statesManager.Update(this.game); } this.game.Log(LogType.Timing, LogImportance.Important, "finish update at {0}", this.game.GetTimeRemaining()); // run the best events for us this.UpdateChooser(); this.game.Execute(this.actionsChooser); this.game.Log(LogType.Timing, LogImportance.ExtremelyImportant, "finish turn at {0}", this.game.GetTimeRemaining()); game.Debug("real finish at {0}", game.TimeRemaining()); }
/// <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) { //Counts how many of the pirates in the cluster carry treasure, will be used for event value. List <Pirate> treasurePiratesInCluster = this.hotspot.Intersect(game.GetEnemyPirates(PirateState.CarryingTreasure)).ToList(); int valueInCluster = treasurePiratesInCluster.Sum(pirate => pirate.CarriedTreasureValue); List <Pirate> protectors = game.GetEnemyPiratesInAttackRange(this.hotspot, PirateState.Free); bool myPirateInCluster = false; int drunkDouches = game.GetMyPiratesInAttackRange(this.hotspot, PirateState.Drunk).Count; //Checks if there is a pirate in the cluster already, if so - tells it to be a smart douchebag! foreach (Pirate myPirate in game.GetMyPirates(PirateState.Free)) { if (Game.InAttackRange(myPirate, this.hotspot, myPirate.AttackRadius)) // pirate is in cluster already! { myPirateInCluster = true; //Release the douche!; if (treasurePiratesInCluster.Count > 0) { foreach (Pirate enemy in treasurePiratesInCluster) // go to an enemy with treasure spawn to lock it (act as a douch) { if (game.GetPirateOn(enemy.InitialLocation) != null && game.GetPirateOn(enemy.InitialLocation) != myPirate) { continue; } List <Pirate> threats = game.GetEnemyDangerousPiratesInAttackRange(myPirate); var sailOptions = game.GetCompleteSailOptions(myPirate, enemy.InitialLocation, false, Terrain.CurrentTreasureLocation); foreach (var pair in sailOptions) { if (pair.Key.Equals(enemy.InitialLocation) || game.GetEnemyDangerousPiratesInAttackRange(pair.Key).Union(threats).Count() == 0 || myPirate.DefenseDuration > 0) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); ap.AddEnemyPirate(enemy); double value = DOUCH_SPAWN_CAMP + valueInCluster * TREASURE_VAL + (this.hotspot.Count - treasurePiratesInCluster.Count) * NO_TREASURE_VAL - Game.ManhattanDistance(enemy.InitialLocation, enemy) - Utils.Pow(pair.Value, 1.2); if (enemy.HasPowerup(SpeedPowerup.NAME) && statesManager.GetState <ImpendingDoomState>().IsDoomIncoming) { value *= IMPENDING_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in DouchebagEvent - case: spawn-camp pirate {0}, Value: {1:F3}", enemy.Id, value); chooser.AddActionsPack(ap, value); } } } } /*else * { * foreach (var pair in game.GetCompleteSailOptions(myPirate, this.hotspot, 0, 0, myPirate.MaxSpeed, true, 0, myPirate.MaxSpeed, 2, Terrain.CurrentTreasureLocation, Terrain.EnemyLocation)) // or return to the center of the cluster * { * //ActionsPack ap = ActionsPack.NewSailPack(game, myPirate, pair.Key, this.Id); * ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); * * double value = DOUCH_CLUSTER_CAMP + (this.enemiesInCluster.Count - treasurePiratesInCluster.Count) * NO_TREASURE_VAL - Utils.Pow(pair.Value, 1.2) - PROTECTOR_VAL * protectors.Count + treasurePiratesInCluster.Count * TREASURE_VAL; * * ap.BurnInformation("Made in DouchebagEvent case: cluster-camp, Value: {0:F3}", value); * * chooser.AddActionsPack(ap, value); * } * }*/ } } if (!myPirateInCluster && drunkDouches < treasurePiratesInCluster.Count) // no pirate in cluster - send in the douches! (become a doouche) { foreach (Pirate myPirate in game.GetMyPirates(PirateState.Free)) { foreach (Pirate enemy in treasurePiratesInCluster) // go to an enemy with treasure spawn to lock it (act as a douch) { var sailOptions = game.GetCompleteSailOptions(myPirate, enemy.InitialLocation, Terrain.CurrentTreasureLocation); foreach (var pair in sailOptions) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); ap.AddEnemyPirate(enemy); double value = DOUCH_BECOME + valueInCluster * TREASURE_VAL + (this.hotspot.Count - treasurePiratesInCluster.Count) * NO_TREASURE_VAL - Game.ManhattanDistance(enemy.InitialLocation, enemy) - Utils.Pow(pair.Value, 1.5) - PROTECTOR_VAL * protectors.Count; if (enemy.HasPowerup(SpeedPowerup.NAME) && statesManager.GetState <ImpendingDoomState>().IsDoomIncoming) { value *= IMPENDING_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in DouchebagEvent case: become spawn-camper on pirate {0}, Value: {1:F3}", enemy.Id, value); chooser.AddActionsPack(ap, value); } } /*var sailOptions = game.GetCompleteSailOptions(myPirate, this.hotspot, 0, 0, myPirate.MaxSpeed, true, 0, myPirate.MaxSpeed, 2, Terrain.CurrentTreasureLocation); * * 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.NewSailPack(game, myPirate, pair.Key, this.Id); * ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); * * double value = DOUCH_BECOME + treasurePiratesInCluster.Count * TREASURE_VAL + (this.enemiesInCluster.Count - treasurePiratesInCluster.Count) * NO_TREASURE_VAL - Utils.Pow(pair.Value, 1.25) - PROTECTOR_VAL * protectors.Count; * value = 0.2 * value; * * ap.BurnInformation("Made in DouchebagEvent case: become cluster-camper, Value: {0:F3}", 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.CarryingTreasure) // can't move = can't dodge / if I'm shielded no point in dodging { return; } TreasureDancingState treasureDancingState = statesManager.GetState <TreasureDancingState>(); bool dodgedLastTurn = treasureDancingState.IsPirateDancing(this.myPirate); List <Pirate> enemies = game.GetEnemyPirates(PirateState.Free); if (enemies.Count == 0) // no enemies = no threat { return; } if (!dodgedLastTurn) //Pirate is carrying Treasure - can only move 1 step { foreach (var pair in GetTreasureDodgeOptions(this.myPirate, game)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, pair.Key), base.Id); double distanceLeft = Game.ManhattanDistance(pair.Key, this.myPirate.InitialLocation); double getCloserPrioritize = (distanceLeft == 0 ? myPirate.CarriedTreasureValue * 65536 : (distanceLeft + 1.0) / (distanceLeft)); //This is so it would prioritize moving in the direction that makes us closer. double value = myPirate.CarriedTreasureValue * PIRATE_WITH_TREASURE_DODGING - pair.Value / (pair.Value + 1.0) + getCloserPrioritize; ap.BurnInformation("Made by DodgeEvent - case: dodge attack, Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } } else { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, this.myPirate), base.Id); double value = myPirate.CarriedTreasureValue * PIRATE_WITH_TREASURE_DODGING - 0.1; ap.BurnInformation("Made by DodgeEvent - case: dodge ram stage 2, Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } foreach (var pair in GetRamDodgeOptions(this.myPirate, game)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, pair.Key), base.Id); double value = myPirate.CarriedTreasureValue * PIRATE_WITH_TREASURE_DODGING - pair.Value / (pair.Value + 1.0); ap.BurnInformation("Made by DodgeEvent - case: dodge ram stage 1, Value: {0:F3}", 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 Seek&Destroy { return; } // get all the enemy pirates with treasure, sorted by their manhattan distance to me List <Pirate> enemyPiratesWithTreasure = game.GetEnemyClosestPirates(this.myPirate, PirateState.CarryingTreasure); ImpendingDoomState impendingDoom = statesManager.GetState <ImpendingDoomState>(); double pirateCountMultiplier = (double)game.ActionsPerTurn / (double)game.GetAllEnemyPiratesCount(); pirateCountMultiplier = pirateCountMultiplier > 1 ? 1.0 : pirateCountMultiplier; // If the enemy has treasure foreach (Pirate enemy in enemyPiratesWithTreasure) { if (Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius - 1)) { continue; //We are in attack range to AttackEvent. This should be handled by it. } int distanceLeftForEnemy = Game.ManhattanDistance(enemy, enemy.InitialLocation); if (distanceLeftForEnemy <= 1 || distanceLeftForEnemy < Game.ManhattanDistance(this.myPirate, enemy) / game.ActionsPerTurn) { continue; //It's too late now, we can't reach him. Douchebag should handle this. } //get the sailing directions ILocateable dest = enemy; int distanceFromDest = (int)this.myPirate.AttackRadius - 2; foreach (Powerup up in game.GetPowerups()) { if (up is AttackPowerup && Game.OnTrack(myPirate, enemy, up)) { dest = up; distanceFromDest = 0; break; } } var sailOptions = game.GetCompleteSailOptions(this.myPirate, enemy, 0, distanceFromDest, Terrain.CurrentTreasureLocation, Terrain.EnemyLocation); //Get sailing packs - with Value and Burnt information according to the Distance Category from the enemy switch (GetDistanceCategory(game, enemy, Game.EuclideanDistance(myPirate, enemy))) { case DistanceCategory.Close: //enemy is close to me 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.AddEnemyPirate(enemy); double value = CLOSE_ENEMY_HAS_TREASURE * enemy.CarriedTreasureValue - Utils.Pow((pair.Value), 1.5) - Game.ManhattanDistance(pair.Key, enemy.InitialLocation); if (impendingDoom.IsDoomIncoming) { value = value * IMPENDING_DOOM_MULTIPLYER; } if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } //value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: close treasure", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; case DistanceCategory.Medium: //enemy is in medium range 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.AddEnemyPirate(enemy); double value = MEDIUM_RANGE_ENEMY_HAS_TREASURE * enemy.CarriedTreasureValue - Utils.Pow((pair.Value) + (game.ActionsPerTurn + 1) / 2 - 2, 1.3) - Game.ManhattanDistance(pair.Key, enemy.InitialLocation); if (enemy.HasPowerup(SpeedPowerup.NAME)) { value += ENEMY_WITH_SPEED_UP_AND_TREASURE; } if (impendingDoom.IsDoomIncoming) { value = value * IMPENDING_DOOM_MULTIPLYER; } if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: medium treasure", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; case DistanceCategory.Far: //enemy is far away 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.AddEnemyPirate(enemy); double value = FAR_RANGE_ENEMY_HAS_TREASURE * enemy.CarriedTreasureValue - Utils.Pow((pair.Value) - game.ActionsPerTurn / 3 - 2, 1.2) - Game.ManhattanDistance(pair.Key, enemy.InitialLocation); if (enemy.HasPowerup(SpeedPowerup.NAME)) { value += ENEMY_WITH_SPEED_UP_AND_TREASURE; } if (impendingDoom.IsDoomIncoming) { value = value * IMPENDING_DOOM_MULTIPLYER; } if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: far treasure", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; } } Pirate closest = null; if (game.GetEnemyPiratesCount(PirateState.Free) > 0) { closest = game.GetEnemyClosestPirates(myPirate, PirateState.Free)[0]; } //if the enemy doesn't have a treasure foreach (Pirate enemy in game.GetEnemyPirates(PirateState.Free)) { if (Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius)) { continue; //We are in attack range to AttackEvent. This should be handled by it. } //get the sailing directions var sailOptions = game.GetCompleteSailOptions(this.myPirate, enemy, 0, (int)this.myPirate.AttackRadius, Terrain.CurrentTreasureLocation, Terrain.EnemyLocation); //Get sailing packs - with Value and Burnt information according to the Distance Category from the enemy if (enemy.PowerupCount > 0) { switch (GetDistanceCategory(game, enemy, Game.EuclideanDistance(myPirate, enemy))) { case DistanceCategory.Close: //enemy is close to me 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.AddEnemyPirate(enemy); double value = CLOSE_ENEMY_HAS_POWERUP - Utils.Pow((pair.Value), 1.3); if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: close powerup", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; case DistanceCategory.Medium: //enemy is in medium range 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.AddEnemyPirate(enemy); double value = MEDIUM_RANGE_ENEMY_HAS_POWERUP - Utils.Pow((pair.Value) + (game.ActionsPerTurn + 1) / 2 - 2, 1.2); if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: medium powerup", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; case DistanceCategory.Far: //enemy is far away 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.AddEnemyPirate(enemy); double value = FAR_RANGE_ENEMY_HAS_POWERUP - Utils.Pow((pair.Value) - game.ActionsPerTurn / 3 - 2, 1); if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: far powerup", enemy.Id, value); chooser.AddActionsPack(ap, value); } } break; } } else if (enemy == closest || !game.EnemyArmada) { if (impendingDoom.IsDoomIncoming) { return; } if (myPirate.CanAttack) //Seek and Destroy a non-treasure enemy only if you can shoot him { if (Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius)) { continue; //We are in attack range to AttackEvent. This should be handled by it.; } //Get sailing packs 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.AddEnemyPirate(enemy); double value = Utils.Max(ENEMY_HAS_NO_TREASURE - Utils.Pow(pair.Value, 0.7), 1.0 / (pair.Value + 1.0)); if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value *= pirateCountMultiplier; ap.BurnInformation("Made in SeekAndDestroyEvent, against {0}, value: {1:F3}, case: no Treasure", enemy.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) { 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); } } } }
/// <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.treasurePirate.State != PirateState.CarryingTreasure) { return; } //Counts how many of the pirates in the cluster carry treasure, will be used for event value. List <Pirate> enemyPirates = new List <Pirate>(); foreach (Pirate enemy in game.GetEnemyPirates(PirateState.Free)) { if (Game.InAttackRange(enemy, treasurePirate, enemy.AttackRadius + enemy.MaxSpeed)) { enemyPirates.Add(enemy); } } enemyPirates = enemyPirates.OrderBy(p => Game.EuclideanDistance(p, this.treasurePirate)).ToList(); if (enemyPirates.Count == 0) //No threats { return; } TreasureDancingState treasureDancingState = statesManager.GetState <TreasureDancingState>(); ImpendingVictoryState impendingVictory = statesManager.GetState <ImpendingVictoryState>(); //Sends in an escort to destory/block an enemy foreach (Pirate myPirate in game.GetMyPirates(PirateState.Free)) { //Bodyguard foreach (Pirate enemy in enemyPirates) // try to block an enemy's path/destroy it { //1st priority - shoot him! if (game.IsAttackPossible(myPirate, enemy) && !game.IsAttackPossible(enemy, treasurePirate)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new AttackCommand(myPirate, enemy), base.Id); double value = ESCORT_GUARD_VALUE - Game.EuclideanDistance(enemy, this.treasurePirate); if (impendingVictory.IsVictoryIncoming) { value = value * IMPENDING_VICTORY_MULTIPLYER; } value *= this.treasurePirate.CarriedTreasureValue; ap.BurnInformation("Made in EscortEvent - case: shoot threat, Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } //2nd priority - ram him! if (Game.ManhattanDistance(enemy, myPirate) <= myPirate.MaxSpeed) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, enemy), base.Id); ap.AddEnemyPirate(enemy); double value = ESCORT_GUARD_VALUE - Game.EuclideanDistance(enemy, this.treasurePirate) - Game.ManhattanDistance(enemy, myPirate); if (impendingVictory.IsVictoryIncoming) { value = value * IMPENDING_VICTORY_MULTIPLYER; } value *= this.treasurePirate.CarriedTreasureValue; ap.BurnInformation("Made in EscortEvent - case: ram enemy {0}, Value: {1:F3}", enemy.Id, value); chooser.AddActionsPack(ap, value); } //3rd priority - body block him if (Game.EuclideanDistance(enemy, treasurePirate) >= game.AttackRadius) { foreach (var pair in game.GetCompleteSailOptions(myPirate, ClosestOnCircle(myPirate.AttackRadius, this.treasurePirate, enemy), 0, 1, Terrain.CurrentTreasureLocation, Terrain.EnemyLocation)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); double value = ESCORT_VALUE - Game.EuclideanDistance(enemy, this.treasurePirate) - Utils.Pow(pair.Value, 1.3); if (impendingVictory.IsVictoryIncoming) { value = value * IMPENDING_VICTORY_MULTIPLYER; } value *= this.treasurePirate.CarriedTreasureValue; ap.BurnInformation("Made in EscortEvent - case: block enemy {0}, Value: {1:F3}", enemy.Id, value); chooser.AddActionsPack(ap, value); } } } //This code does escorts even if there are no enemies close, currently not implemented /*else if (enemyPirates.Count <= 0) * { * foreach (var pair in game.GetCompleteSailOptions(myPirate, treasurePirate, Terrain.CurrentTreasureLocation, Terrain.EnemyLocation)) * { * ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(myPirate, pair.Key), base.Id); * * double value = 0.8 * (ESCORT_VALUE - Utils.Pow(Game.ManhattanDistance(myPirate, pair.Key), 1.3)); * if (impendingVictory.IsVictoryIncoming) * value = value * IMPENDING_VICTORY_MULTIPLYER; * value *= this.treasurePirate.CarriedTreasureValue; * * ap.BurnInformation("Made in EscortEvent - case: become escort, Value: {0:F3}", 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.treasure.CarryingPirate == null) { return; } Pirate carrying = this.treasure.CarryingPirate; double multiplyer = Utils.Pow(1 - ((double)game.GetMyPiratesCount(PirateState.CarryingTreasure)) / game.GetMyPiratesCount(PirateState.Free, PirateState.CarryingTreasure), 2); multiplyer *= this.treasure.Value; switch (carrying.Owner) { case Owner.Enemy: if (game.GetMyPiratesCount(PirateState.Free) > 0) { Pirate myClosestPirate = game.GetMyClosestPirates(carrying, PirateState.Free)[0]; foreach (Pirate free in game.GetMyPirates(PirateState.Free)) { if (free == myClosestPirate) { continue; } var sailOptions = game.GetCompleteSailOptions(free, treasure.InitialLocation, Terrain.EnemyLocation, Terrain.CurrentTreasureLocation); 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(free, pair.Key), base.Id); ap.AddTreasure(treasure); double returnDistance = Game.ManhattanDistance(free.InitialLocation, treasure); double maxDistance = game.Rows + game.Collumns; double value = (TREASURE_VALUE - Utils.Pow(pair.Value, 0.9)) * multiplyer * ((maxDistance - returnDistance) / (maxDistance)); if (myClosestPirate.HasPowerup(SpeedPowerup.NAME)) { value = value * SPEED_POWERUP_MULTIPLYER; } switch (GetDistanceCategory(game, myClosestPirate, Game.EuclideanDistance(carrying, myClosestPirate))) { case DistanceCategory.Close: value = value * ENEMY_HAS_TREASURE_ALLY_CLOSE; ap.BurnInformation("Made in GhostTreasureEvent, collecting treasure {0} from {1}, value: {2:F3}, case: close ally", treasure.Id, carrying.Id, value); break; case DistanceCategory.Medium: value = value * ENEMY_HAS_TREASURE_ALLY_MEDIUM; ap.BurnInformation("Made in GhostTreasureEvent, collecting treasure {0} from {1}, value: {2:F3}, case: medium ally", treasure.Id, carrying.Id, value); break; case DistanceCategory.Far: value = value * ENEMY_HAS_TREASURE_ALLY_FAR; ap.BurnInformation("Made in GhostTreasureEvent, collecting treasure {0} from {1}, value: {2:F3}, case: far ally", treasure.Id, carrying.Id, value); break; default: continue; } chooser.AddActionsPack(ap, value); } } } } break; case Owner.Me: if (game.GetEnemyPiratesCount(PirateState.Free) > 0) { Pirate closestEnemy = game.GetEnemyClosestPirates(carrying, PirateState.Free)[0]; if (Game.InAttackRange(carrying, closestEnemy, closestEnemy.AttackRadius + closestEnemy.MaxSpeed)) { if (game.GetMyPiratesCount(PirateState.Free) > 0) { Pirate closestAlly = game.GetMyClosestPirates(carrying, PirateState.Free)[0]; if (Game.InAttackRange(carrying, closestAlly, closestAlly.AttackRadius) || Game.InAttackRange(closestAlly, closestEnemy, closestAlly.AttackRadius)) { return; // is safe by the power of escort } foreach (Pirate free in game.GetMyPirates(PirateState.Free)) { var sailOptions = game.GetCompleteSailOptions(free, treasure.InitialLocation, Terrain.EnemyLocation, Terrain.CurrentTreasureLocation); 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(free, pair.Key), base.Id); ap.AddTreasure(treasure); double returnDistance = Game.ManhattanDistance(free.InitialLocation, treasure); double maxDistance = game.Rows + game.Collumns; double value = (TREASURE_VALUE - Utils.Pow(pair.Value, 0.9)) * multiplyer * ((maxDistance - returnDistance) / (maxDistance)); if (free.HasPowerup(SpeedPowerup.NAME)) { value = value * SPEED_POWERUP_MULTIPLYER; } value = value * ALLY_ABOUT_TO_DIE; ap.BurnInformation("Made in GhostTreasureEvent, collecting treasure {0} from {1}, value: {2:F3}, case: dead ally", treasure.Id, carrying.Id, value); chooser.AddActionsPack(ap, value); } } } } } } break; default: break; } }
/// <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.CanDefend || this.myPirate.DefenseDuration > 0) { return; } List <Pirate> threats = new List <Pirate>(); bool isDouche = game.GetPirateSpawnOn(myPirate) != null && game.GetPirateSpawnOn(myPirate).Owner == Owner.Enemy; // If my pirate is a douche, he shouldn't ram the enemy since spawn-blocking is better. if (this.myPirate.State != PirateState.CarryingTreasure) { foreach (Pirate threat in game.GetEnemyDangerousPiratesInAttackRange(this.myPirate)) { if (game.PredictAttack(threat) == PredictionResult.False) { continue; } threats.Add(threat); foreach (Pirate treasurePirate in game.GetMyPirates(PirateState.CarryingTreasure)) // Assume a pirate prefers to shoot a treasure pirate over a non-treasure pirate if he can { if (Game.InAttackRange(treasurePirate, threat, threat.AttackRadius)) { threats.Remove(threat); break; } } } } else { threats = game.GetEnemyDangerousPiratesInAttackRange(this.myPirate); threats.RemoveAll(p => game.PredictAttack(p) == PredictionResult.False); foreach (Pirate ally in game.GetMyPirates(PirateState.Free)) { if (Game.InAttackRange(ally, myPirate, ally.AttackRadius) && ally.CanAttack) { return; } } } if (threats.Count == 0) // I'm safe, yay me! { return; } ActionsPack ap = ActionsPack.NewCommandPack(game, new DefendCommand(this.myPirate), base.Id); double value = PIRATE_DOESNT_HAVE_TREASURE; if (this.myPirate.State == PirateState.CarryingTreasure) { value = PIRATE_HAS_TREASURE * this.myPirate.CarriedTreasureValue; } else if (isDouche && this.myPirate.State != PirateState.CarryingTreasure) { value = PIRATE_IS_DOUCHE; } ap.BurnInformation("Made in DefendEvent, Value: {0:F3}", 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 take power ups. If my pirate already has a power up, he shouldn't take another. { return; } // Get all the free powerups and sort them by manhattan distance to me List <Powerup> freePowerUps = game.GetPowerups().OrderBy(t => Game.ManhattanDistance(t, this.myPirate)).ToList(); // Get the maximum treasure value int maxTreasureValue = 1; foreach (Treasure t in game.GetTreasures(TreasureState.FreeToTake, TreasureState.BeingCarried)) { if (t.Value > maxTreasureValue) { maxTreasureValue = t.Value; } } // try to sail to each treasure foreach (Powerup powerup in freePowerUps) { if (game.GetPirateOn(powerup) != null) // there is a pirate where the treasure is, most likely a drunk one. Leave it be. { continue; } var sailOptions = game.GetCompleteSailOptions(this.myPirate, powerup, myPirate.DefenseDuration == 0 || Game.ManhattanDistance(myPirate, powerup) <= myPirate.MaxSpeed, Terrain.EnemyLocation, Terrain.CurrentTreasureLocation); 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); double value = -Utils.Pow(pair.Value, 1.5); if (powerup is AttackPowerup) { value += ATTACK_POWERUP_VALUE; } else if (powerup is SpeedPowerup) { value += SPEED_POWERUP_VALUE; } else { value += DEFAULT_POWERUP_VALUE; } if (pair.Value == 0) { value += PICK_UP_VALUE; } value *= Utils.Pow(0.75, myPirate.PowerupCount); // Add a multiplier for maximum treasure value if (powerup is SpeedPowerup) { value *= maxTreasureValue; } ap.AddPowerup(powerup); ap.BurnInformation("Made in PowerUpEvent. Fetching PowerUp: {0}. Value: {1:F3}", powerup.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.State != PirateState.Free) { return; } bool inRisk = false; // Is my pirate in risk of shooting right now? foreach (Pirate threat in game.GetEnemyPirates(PirateState.Free)) { if (Game.InAttackRange(threat, myPirate, threat.AttackRadius) || Game.ManhattanDistance(threat, myPirate) <= threat.MaxSpeed) { inRisk = true; break; } } bool isDouche = game.GetPirateSpawnOn(myPirate) != null && game.GetPirateSpawnOn(myPirate).Owner == Owner.Enemy; // If my pirate is a douche, he shouldn't ram the enemy since spawn-blocking is better. // try to attack every enemy pirate which is carrying a treasure / which is free foreach (Pirate enemy in game.GetEnemyPirates(PirateState.CarryingTreasure, PirateState.Free, PirateState.Drunk)) { //safe attack a treasure carrier if (enemy.State == PirateState.CarryingTreasure) { if (Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius - 1) && //in close range - enemy can't escape game.IsAttackPossible(this.myPirate, enemy) && //can fire (!inRisk || isDouche)) // it's safe to shoot (a douche shouldn't care if it's safe or not to shoot - he has nothing to lose) { ActionsPack ap = ActionsPack.NewCommandPack(game, new AttackCommand(this.myPirate, enemy), this.Id); double value = ENEMY_HAS_TREASURE * enemy.CarriedTreasureValue; if (myPirate.HasPowerup(AttackPowerup.NAME)) { value *= ATTACK_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in AttackEvent, case: shoot treasure. Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } else if ((Game.ManhattanDistance(enemy, enemy.InitialLocation) <= enemy.MaxSpeed || inRisk || !myPirate.CanAttack || myPirate.TurnsToAttackReload > enemy.DefenseDuration) && enemy.MaxSpeed < myPirate.MaxSpeed && !enemy.HasPowerup(SpeedPowerup.NAME))// ram { if (!isDouche || (!myPirate.CanDefend && inRisk && Game.ManhattanDistance(enemy, enemy.InitialLocation) > enemy.MaxSpeed)) { // ram his predicted location Location predictedLocation = game.PredictMovement(enemy); // if there is no predicted location, try to ram his current location if (predictedLocation == null) { predictedLocation = enemy.Location; } if (Game.ManhattanDistance(predictedLocation, myPirate) <= myPirate.MaxSpeed) // too far to ram { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, predictedLocation), this.Id); ap.AddEnemyPirate(enemy); double value = ENEMY_HAS_TREASURE * enemy.CarriedTreasureValue - Game.ManhattanDistance(myPirate, enemy); ap.BurnInformation("Made in AttackEvent, case: ram treasure. Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } } } else if (enemy.DefenseDuration > 0 && myPirate.TurnsToAttackReload < enemy.DefenseDuration && Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius - 1)) { var sailOptions = game.GetCompleteSailOptions(this.myPirate, enemy.InitialLocation, 0, 0, this.myPirate.MaxSpeed, this.myPirate.DefenseDuration == 0, 0, enemy.MaxSpeed, 2, Terrain.EnemyLocation, Terrain.CurrentTreasureLocation); 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.AddEnemyPirate(enemy); double value = GHOST_TREASURE_VAL * enemy.CarriedTreasureValue - Utils.Pow(pair.Value, 1.5) - Game.ManhattanDistance(pair.Key, enemy); if (myPirate.HasPowerup(AttackPowerup.NAME)) { value *= ATTACK_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in AttackEvent, against {0}, value: {1:F3}, case: ghost shielded treasure", enemy.Id, value); chooser.AddActionsPack(ap, value); } } } } else if (enemy.PowerupCount > 0) { /*double multiplier = 2 * game.GetMyPiratesInAttackRange(enemy, PirateState.Free).Count; * multiplier += 4 * game.GetMyPiratesInAttackRange(enemy, PirateState.CarryingTreasure).Count;*/ double multiplier = 1; if (game.GetMyPiratesInAttackRange(enemy, PirateState.Free).Count > 1 && game.GetMyPiratesInAttackRange(enemy, PirateState.CarryingTreasure).Count == 0) { multiplier = 8; } if (game.IsAttackPossible(myPirate, enemy) && enemy.TurnToSober == 0) //fire! { ActionsPack ap = ActionsPack.NewCommandPack(game, new AttackCommand(this.myPirate, enemy), base.Id); double value = ENEMY_HAS_POWERUP; if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } value = value * multiplier; ap.BurnInformation("Made in AttackEvent, case: shoot powerup. Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } else if (Game.ManhattanDistance(myPirate, enemy) <= myPirate.MaxSpeed && myPirate.PowerupCount == 0)// ram { if (!isDouche) { if (!enemy.CanAttack && !enemy.CanDefend) { continue; } // ram his location Location enemyLocation = enemy.Location; // assume enemy will shoot or defend, otherwise ramming is practically impossible ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, enemyLocation), base.Id); double value = ENEMY_HAS_POWERUP - Game.ManhattanDistance(myPirate, enemy); value = value * multiplier; ap.AddEnemyPirate(enemy); ap.BurnInformation("Made in AttackEvent, case: ram powerup. Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } } } //just attack a free pirate else if (enemy.State == PirateState.Free && Game.InAttackRange(this.myPirate, enemy, this.myPirate.AttackRadius)) { if (!myPirate.CanAttack) { continue; } if (enemy.DefenseDuration > 0) { continue; } if (game.IsAttackPossible(this.myPirate, enemy)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new AttackCommand(this.myPirate, enemy), base.Id); /*double multiplier = 2 * game.GetMyPiratesInAttackRange(enemy, PirateState.Free).Count; * multiplier += 4 * game.GetMyPiratesInAttackRange(enemy, PirateState.CarryingTreasure).Count;*/ double multiplier = 1; if (game.GetMyPiratesInAttackRange(enemy, PirateState.Free).Count > 1 && game.GetMyPiratesInAttackRange(enemy, PirateState.CarryingTreasure).Count == 0) { multiplier = 8; } double value = ENEMY_HAS_NO_TREASURE * multiplier; if (myPirate.HasPowerup(AttackPowerup.NAME)) { value = value * ATTACK_POWERUP_MULTIPLYER; } ap.BurnInformation("Made in AttackEvent, case: shoot regular. Value: {0:F3}", value); chooser.AddActionsPack(ap, value); } } } }
/// <summary> /// Add possible responses to "chooser", based on the situation in "game" and in "statesManager" /// </summary> public abstract void AddResponseOptions(Game game, StatesManager statesManager, ActionsChooser chooser);
private const double GARBAGE_COLLECTION_VALUE = 120; // - (distanceLeft^1.5), range of values is about 200 to 180 /// <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.State != PirateState.Drunk || (game.GetPirateSpawnOn(this.myPirate) != null && game.GetPirateSpawnOn(this.myPirate).Owner == Owner.Enemy)) //If my pirate isn't drunk it doesn't need help { return; } // try to sail to "collect" the pirate foreach (Pirate free in game.GetMyPirates(PirateState.Free)) { var sailOptions = game.GetCompleteSailOptions(free, this.myPirate, Terrain.CurrentTreasureLocation); 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 RamCommand(free, this.myPirate, pair.Key), base.Id); ap.AddMyPirate(myPirate); double distanceFromSpawnModifier = Utils.Pow(Game.ManhattanDistance(free.InitialLocation, free), 1.5); double timeModifier = Utils.Pow(game.TurnsUntilSober - this.myPirate.TurnToSober, 1.5); double value = Utils.Max(GARBAGE_COLLECTION_VALUE - timeModifier - distanceFromSpawnModifier - Utils.Pow(pair.Value, 1.5), 35); ap.BurnInformation("Made in GarbageCollection event, saving {0}, Value: {1:F3}", this.myPirate.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 the pirate is not carrying treasure OR if he can't move, we cannot do anything if (this.myPirate.State != PirateState.CarryingTreasure || !this.myPirate.CanMove) { return; } /* * bool isEscorted = false; * foreach (Pirate ally in game.GetMyFreePirates()) * { * if (Game.InAttackRange(ally, myPirate, ally.AttackRadius)) * { * isEscorted = true; * break; * } * }*/ var sailOptions = game.GetCompleteSailOptions(this.myPirate, this.myPirate.InitialLocation, myPirate.DefenseDuration == 0 && Game.ManhattanDistance(myPirate, myPirate.InitialLocation) > myPirate.MaxSpeed, Terrain.EnemyLocation); List <Pirate> closestEnemies = game.GetEnemyClosestPirates(myPirate, PirateState.Free); // check all possible destinations for returning home foreach (var pair in sailOptions) { if (sailOptions[0].Value > pair.Value && (game.GetPirateOn(pair.Key) == null || game.GetPirateOn(pair.Key).Owner == Owner.Me)) { ActionsPack ap = ActionsPack.NewCommandPack(game, new SailCommand(this.myPirate, pair.Key), base.Id); double prioritize = (pair.Value == 0 ? myPirate.CarriedTreasureValue * 65536 : 5.0 * (pair.Value + 1.0) / (pair.Value)); double stayAwayPrioritize = 10; if (closestEnemies.Count > 0) { Pirate enemy = closestEnemies[0]; if (Game.ManhattanDistance(enemy, myPirate) > enemy.MaxSpeed) { double distanceToEnemy = Game.EuclideanDistance(pair.Key, enemy); stayAwayPrioritize = 5.0 * (distanceToEnemy) / (distanceToEnemy + 1.0); } } double value = (MOVE_TOWARDS_HOME + prioritize + stayAwayPrioritize - Utils.Pow(pair.Value, 1.3)) * myPirate.CarriedTreasureValue; if (myPirate.HasPowerup(SpeedPowerup.NAME)) { value = value * SPEED_POWERUP_MULTIPLYER; } if (game.GetAllMyPiratesCount() > game.ActionsPerTurn) { value += ARMADA_BONUS; } ap.BurnInformation("Made in ReturnTreasureEvent, Value: {0:F3}", 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.State != PirateState.Drunk) { return; } Pirate enemy = game.GetPirateSpawnOn(this.myPirate); if (enemy != null && enemy.Owner == Owner.Enemy) { ActionsPack ap = ActionsPack.NewCommandPack(game, new DoNothingCommand(), base.Id); double value = BLOCKADE_VALUE; ap.AddEnemyPirate(enemy); ap.AddMyPirate(this.myPirate); ap.BurnInformation("Made in DrunkBlockadeEvent for pirate {0} on pirate {1}, Value: {2:F3}", this.myPirate, enemy.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) { //Counts how many of the pirates in the cluster carry treasure, will be used for event value. List <Pirate> treasurePiratesInCluster = this.hotspot.Intersect(game.GetMyPirates(PirateState.CarryingTreasure)).ToList(); int valueInCluster = treasurePiratesInCluster.Sum(pirate => pirate.CarriedTreasureValue); if (valueInCluster == 0) { return; } // the pirates in the threat zone List <Pirate> enemiesInCluster = game.GetEnemyPiratesInAttackRange(this.hotspot, PirateState.Free).Union( game.GetEnemyPiratesInAttackRange(this.hotspot, PirateState.Drunk)).ToList(); //Checks if there is an enemy in the cluster already, if so - sends in the cavalry! foreach (Pirate enemy in enemiesInCluster) { if (enemy.State == PirateState.Drunk && game.GetPirateSpawnOn(enemy.Location) != null && game.GetPirateSpawnOn(enemy.Location).Owner != Owner.Me) { continue; } foreach (Pirate myPirate in game.GetMyPirates(PirateState.Free)) { var sailOptions = game.GetCompleteSailOptions(myPirate, enemy, myPirate.DefenseDuration == 0 && !Game.InAttackRange(myPirate, enemy, enemy.AttackRadius), Terrain.CurrentTreasureLocation); 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(myPirate, pair.Key), this.Id); ap.AddEnemyPirate(enemy); double value = BASE_VAL + valueInCluster * TREASURE_VAL + (this.hotspot.Count - treasurePiratesInCluster.Count) * NO_TREASURE_VAL + enemiesInCluster.Count * ENEMY_VAL - Utils.Pow(pair.Value, 1.25); if (this.hotspot.Contains(myPirate)) { value += IS_HOME_VAL; } if (statesManager.GetState <ImpendingVictoryState>().IsVictoryIncoming) { value *= IMPENDING_VICTORY_MULT; } ap.BurnInformation("Made in AntiTeroristEvent against {0}, Value: {1:F3}", enemy.Id, value); chooser.AddActionsPack(ap, value); } } } } }