public override string Update(Buster buster) { // Go to the target position return("MOVE " + buster.TargetPosition.X + " " + buster.TargetPosition.Y); }
public override void Enter(Buster buster) { }
private static void Main(string[] args) { int bustersPerPlayer = int.Parse(Console.ReadLine()); // the amount of busters you control int ghostCount = int.Parse(Console.ReadLine()); // the amount of ghosts on the map myTeamId = int.Parse(Console.ReadLine()); // if this is 0, your base is on the top left of the map, if it is one, on the bottom right for (int i = BustRangeMax; i < MapWidth; i += BustRangeMax) { for (int j = BustRangeMax; j < MapHeight; j += BustRangeMax) { var state = MapState.Unexplored; if ((i < ReleaseArea && j < ReleaseArea) || (i > MapWidth - ReleaseArea || j > MapWidth - ReleaseArea)) { state = MapState.Base; } else { state = MapState.Unexplored; } var tile = new Entity(-1, i, j, -9, (int)state, BusterState.Idle); tile.Radius = 900; tiles.Add(tile); } } // game loop while (true) { int myCount = 0; int enemyCount = 0; //Console.Error.WriteLine(string.Format("TILES: {0}", string.Join(";",tiles.Select(t=> t.X+","+t.Y).ToArray()))); int entities = int.Parse(Console.ReadLine()); // the number of busters and ghosts visible to you for (int i = 0; i < entities; i++) { string[] inputs = Console.ReadLine().Split(' '); int entityId = int.Parse(inputs[0]); // buster id or ghost id int x = int.Parse(inputs[1]); int y = int.Parse(inputs[2]); // position of this buster / ghost int entityType = int.Parse(inputs[3]); // the team id if it is a buster, -1 if it is a ghost. BusterState state = (BusterState)Enum.Parse(typeof(BusterState), inputs[4]); // For busters: 0=idle, 1=carrying a ghost. int val = int.Parse(inputs[5]); // For busters: Ghost id being carried. For ghosts: number of busters attempting to trap this ghost. if (entityType == -1) { var ghost = activeEntities.OfType <Ghost>().FirstOrDefault(e => e.Id == entityId); if (ghost == null) { ghost = new Ghost(entityId, x, y, entityType, val, state); activeEntities.Add(ghost); } else { ghost.X = x; ghost.Y = y; ghost.Value = val; ghost.State = state; } foreach (var tile in tiles.Where(t => t.Distance(ghost) < t.Radius)) { tile.Value = (int)MapState.Ghost; } } else { var buster = activeEntities.OfType <Buster>().FirstOrDefault(e => e.Id == entityId); if (buster == null) { buster = new Buster(entityId, entityType, x, y, state, val); activeEntities.Add(buster); } else { if (buster.StunTimer > 0) { buster.StunTimer--; } buster.X = x; buster.Y = y; buster.State = state; buster.Value = val; } foreach (var tile in tiles.Where(t => t.Distance(buster) < t.Radius)) { tile.Value = (int)MapState.Buster; } } } var myBusters = activeEntities.OfType <Buster>().Where(b => b.Type == myTeamId); foreach (var buster in myBusters) { Console.Error.WriteLine(string.Format("BusterState: {0} {1}", buster.Id, buster.State)); switch (buster.State) { case BusterState.Carrying: buster.ReturnToBase(); break; case BusterState.Idle: case BusterState.Stunned: buster.Search(); break; case BusterState.Trapping: Console.WriteLine("BUST " + buster.Value); break; } } activeEntities.RemoveAll(e => e.Type == -1); } }
/// <summary> /// Given all the game informations we update our Busters with last intels /// </summary> public void ComputeInformations() { // First we check if our buster is already doing a task or is stunned and skip all the task planning for them foreach (var buster in Busters) { if (buster.IsHoldingAGhost() || buster.IsStunned) { buster.GotAnOrder = true; } } // Try to steal a ghost foreach (var buster in Busters) { Player.print("Buster " + buster.EntityId + " search to chase"); // Find distance to all visible enemies carrying a ghost List <Tuple <int, int> > enemiesInRange = GetInRangeEnemiesCarrying(buster); foreach (var enemy in enemiesInRange) { // Retrieve the actual enemy Enemy foundEnemy = Enemies.Find(e => e.EntityId == enemy.Item1); // Do we already have found an enemy to chase ? If not we search if (buster.EnemyChased == null) { // We get the distance between the enemy and all busters List <Tuple <int, int> > bustersByDistance = GetDistanceToBusters(foundEnemy); foreach (var busterByDistance in bustersByDistance) { int closestBusterId = busterByDistance.Item1; if (closestBusterId == buster.EntityId) { // If we're the closest, we chase them buster.EnemyChased = foundEnemy; buster.GotAnOrder = true; break; } else { // If we're not the closest, does the other buster is busy ? Buster otherBuster = Busters.Find(e => e.EntityId == closestBusterId); if (otherBuster.IsBusy()) { buster.EnemyChased = foundEnemy; buster.GotAnOrder = true; break; } } } } else { break; } } } // Search a catchable ghost for each buster foreach (var buster in Busters.FindAll(e => e.GotAnOrder == false)) { Player.print("Buster " + buster.EntityId + " search to capture"); // First action : Try to capture a ghost // We retrieve all ghosts in capture range List <Tuple <int, int> > ghostsInRange = GetCapturableGhosts(buster); foreach (var ghost in ghostsInRange) { // Retrieve the actual ghost Ghost foundGhost = Ghosts.Find(e => e.EntityId == ghost.Item1); if (foundGhost.Life > 15) { // If half of the ghosts remains, don't catch them yet if (!((GetNumberOfGhostsCaptured() * 2) >= (int)Math.Floor((NumberOfGhosts / 3f) * 2))) { continue; } } // If we're in the first 25% of the game and half of our busters are already on this ghost, search a new one if ((GetNumberOfGhostsCaptured() * 2) <= (int)Math.Floor((NumberOfGhosts / 4f) * 1)) { Player.print("We're here"); if (foundGhost.NumberOfBustersCapturing != 0 && foundGhost.NumberOfBustersCapturing <= ((int)Math.Floor(Busters.Count / 2f)) && GetNumberOfAllyCapturing(buster, foundGhost) == foundGhost.NumberOfBustersCapturing) { Player.print("And here"); continue; } } // Do we already have found a ghost to capture ? If not we search if (buster.GhostInRange == null) { // We get the distance between the ghost and all busters List <Tuple <int, int> > bustersByDistance = GetDistanceToBusters(foundGhost); foreach (var busterByDistance in bustersByDistance) { int closestBusterId = busterByDistance.Item1; Player.print("Closest buster is " + closestBusterId); if (closestBusterId == buster.EntityId) { // If we're the closest, we capture it buster.GhostInRange = foundGhost; buster.GhostInRange.NumberOfBustersCapturing++; buster.GotAnOrder = true; break; } else { // If we're not the closest, does the other buster is busy ? Buster otherBuster = Busters.Find(e => e.EntityId == closestBusterId); if (otherBuster.IsBusy()) { buster.GhostInRange = foundGhost; buster.GhostInRange.NumberOfBustersCapturing++; buster.GotAnOrder = true; break; } } } } else { break; } } // If no ghost is easy to capture we want to check if we're not just too close from one if (buster.GhostInRange == null) { // Get all ghosts in close distance ( < 900 ) and wait to capture on next turn List <Tuple <int, int> > closeRangeGhosts = GetCloseRangeGhosts(buster); foreach (var ghost in closeRangeGhosts) { // Retrieve the actual ghost Ghost foundGhost = Ghosts.Find(e => e.EntityId == ghost.Item1); Vector2 direction = foundGhost.Position - buster.Position; Vector2 newPosition = new Vector2(); if (foundGhost.Position.X > buster.Position.X) { newPosition.X = buster.Position.X - 400; } else { newPosition.X = buster.Position.X + 400; } if (foundGhost.Position.Y > buster.Position.Y) { newPosition.Y = buster.Position.Y - 200; } else { newPosition.Y = buster.Position.Y + 200; } buster.TargetPosition = new Vector2((int)newPosition.X, (int)newPosition.Y); //if(direction.Length() <= 100f) //{ // Vector2 newPosition = new Vector2(buster.Position.X - 800, buster.Position.Y - 800); // buster.TargetPosition = new Vector2((int)newPosition.X, (int)newPosition.Y); //} //else //{ // Vector2 newPosition = buster.Position + Vector2.Normalize(direction) * 400; // buster.TargetPosition = new Vector2((int)newPosition.X, (int)newPosition.Y); //} buster.GotAnOrder = true; Player.print("Too close, moving"); } } } // Second action if no capturable ghost : Chase an enemy or attack an enemy in range (if we can stun) foreach (var buster in Busters.FindAll(e => e.GotAnOrder == false && e.CanStun == true)) { Player.print("Buster " + buster.EntityId + " search to chase"); // Find distance to all visible enemies carrying a ghost List <Tuple <int, int> > enemiesInRange = GetAllVisibleEnemiesCarrying(buster); foreach (var enemy in enemiesInRange) { // Retrieve the actual enemy Enemy foundEnemy = Enemies.Find(e => e.EntityId == enemy.Item1); // Do we already have found an enemy to chase ? If not we search if (buster.EnemyChased == null) { // We get the distance between the enemy and all busters List <Tuple <int, int> > bustersByDistance = GetDistanceToBusters(foundEnemy); foreach (var busterByDistance in bustersByDistance) { int closestBusterId = busterByDistance.Item1; if (closestBusterId == buster.EntityId) { // If we're the closest, we chase them buster.EnemyChased = foundEnemy; buster.GotAnOrder = true; break; } else { // If we're not the closest, does the other buster is busy ? Buster otherBuster = Busters.Find(e => e.EntityId == closestBusterId); if (otherBuster.IsBusy()) { buster.EnemyChased = foundEnemy; buster.GotAnOrder = true; break; } } } } else { break; } } // Third action if no enemy with a ghost : Attack a close enemy if (buster.EnemyChased == null) { // if there is 33% left or less of ghosts we stop stunning and keep for an enemy thay carry Player.print("Chase infos : " + GetNumberOfGhostsCaptured() * 2 + " " + (int)Math.Floor((NumberOfGhosts / 3f) * 2)); if ((GetNumberOfGhostsCaptured() * 2) <= (int)Math.Floor((NumberOfGhosts / 3f) * 2)) { Player.print("Buster " + buster.EntityId + " search an enemy to attack"); // Find all enemies in range enemiesInRange = GetAttackableEnemies(buster); foreach (var enemy in enemiesInRange) { // Retrieve the actual enemy Enemy foundEnemy = Enemies.Find(e => e.EntityId == enemy.Item1); // Get the distance between this enemy and all busters List <Tuple <int, int> > bustersByDistance = GetDistanceToBusters(foundEnemy); foreach (var busterByDistance in bustersByDistance) { int closestBusterId = busterByDistance.Item1; if (closestBusterId == buster.EntityId) { // If we're the closest, we chase them buster.EnemyInRange = foundEnemy; buster.GotAnOrder = true; break; } else { // If we're not the closest, does the other buster is busy ? Buster otherBuster = Busters.Find(e => e.EntityId == closestBusterId); if (otherBuster.IsBusy()) { buster.EnemyInRange = foundEnemy; buster.GotAnOrder = true; break; } else { // The closest non-busy buster will chase this enemy break; } } } } } } else { // If we are in range to attack our chased enemy int distanceToEnemy = (int)Vector2.Distance(buster.Position, buster.EnemyChased.Position); if (distanceToEnemy < 1760) { buster.EnemyInRange = buster.EnemyChased; buster.GotAnOrder = true; } } } // If no enemy in range: Get a ghost to chase foreach (var buster in Busters.FindAll(e => e.GotAnOrder == false)) { Player.print("Buster " + buster.EntityId + " search to chase a ghost"); // Fourth action if no enemy in range : Chase a ghost // Search a ghost to chase List <Tuple <int, int> > chasableGhosts = GetChasableGhosts(buster); foreach (var ghost in chasableGhosts) { // Retrieve the actual ghost Ghost foundGhost = Ghosts.Find(e => e.EntityId == ghost.Item1); if (foundGhost.Life > 15) { // If half of the ghosts remains, don't catch them yet if (!((GetNumberOfGhostsCaptured() * 2) >= (int)Math.Floor((NumberOfGhosts / 3f) * 2))) { continue; } } if ((GetNumberOfGhostsCaptured() * 2) <= (int)Math.Floor((NumberOfGhosts / 4f) * 1)) { // If we're in the first 25% of the game and half of our busters are already on this ghost, search a new one Player.print("Ghost chase infos " + foundGhost.NumberOfBustersCapturing + " " + ((int)Math.Floor(Busters.Count / 2f)) + " " + GetNumberOfAllyCapturing(buster, foundGhost)); if (foundGhost.NumberOfBustersCapturing != 0 && foundGhost.NumberOfBustersCapturing <= ((int)Math.Floor(Busters.Count / 2f)) && GetNumberOfAllyCapturing(buster, foundGhost) == foundGhost.NumberOfBustersCapturing) { continue; } } // Do we already have found a ghost to chase ? If not we search if (buster.GhostChased == null) { // We get the distance between the ghost and all busters List <Tuple <int, int> > bustersByDistance = GetDistanceToBusters(foundGhost); foreach (var busterByDistance in bustersByDistance) { Player.print("Buster " + busterByDistance.Item1 + " - distance : " + busterByDistance.Item2 + " - busy : " + Busters.Find(e => e.EntityId == busterByDistance.Item1).IsBusy()); int closestBusterId = busterByDistance.Item1; if (buster.EntityId == closestBusterId) { // If we're the closest, we chase them buster.GhostChased = foundGhost; buster.GotAnOrder = true; break; } else { // If we're not the closest, does the other buster is busy ? Buster otherBuster = Busters.Find(e => e.EntityId == closestBusterId); if (otherBuster.IsBusy()) { buster.GhostChased = foundGhost; buster.GotAnOrder = true; break; } else { // The closest non-busy buster will chase this ghost break; } } } } } } foreach (var buster in Busters) { // If we're getting in a brawl where N of our busters and N+1 of enemy busters are capturing, we stun one of them if (buster.State == BusterState.MoveState && buster.GhostInRange != null) { Player.print("Analysing a brawl by " + buster.EntityId); int num = GetNumberOfAllyCapturing(buster, buster.GhostInRange); if ((buster.GhostInRange.NumberOfBustersCapturing - num) == (num + 1) && buster.CanStun) { // Find all enemies in range List <Tuple <int, int> > enemiesInRange = GetAttackableEnemies(buster); if (enemiesInRange.Count > 0) { Enemy foundEnemy = Enemies.Find(e => e.EntityId == enemiesInRange.First().Item1); Player.print("Not this time !"); buster.GhostInRange.NumberOfBustersCapturing--; buster.GhostInRange = null; buster.EnemyInRange = foundEnemy; buster.GotAnOrder = true; } } } // Experiment one new role : Blocker //if (buster.Role == "Blocker" && !buster.IsStunned) //{ // // If around 80% of the ghosts are captured, we go and camp the enemy base // if ((GetNumberOfGhostsCaptured() * 2) >= (int)Math.Floor((NumberOfGhosts / 10f) * 8)) // { // Player.print("I'M A BLOCKER"); // // We detect an enemy not carrying ? Ignore // if ((buster.EnemyChased != null && !buster.EnemyChased.IsCarryingAGhost) || (buster.EnemyInRange != null && !buster.EnemyInRange.IsCarryingAGhost)) // { // buster.EnemyInRange = null; // buster.TargetPosition = BlockerPosition; // buster.GotAnOrder = true; // } // else // { // // If the enemy is not in range, but we know his direction and can predict if we could stun him on next turn // if (buster.EnemyChased != null) // { // Vector2 direction = EnemyBasePosition - buster.EnemyChased.Position; // Vector2 nextEnemyPosition = buster.EnemyChased.Position + (Vector2.Normalize(direction) * 800); // Player.print("Next enemy position must be : " + nextEnemyPosition); // if (Vector2.Distance(nextEnemyPosition, buster.Position) < 1700) // { // buster.EnemyInRange = buster.EnemyChased; // buster.EnemyChased = null; // buster.GotAnOrder = true; // } // } // } // if (buster.EnemyChased == null && buster.EnemyInRange == null) // { // if(buster.GhostCaptured != null) // { // // I'm running away ! // buster.GotAnOrder = true; // } // else // { // // We've stunned an enemy, get the ghost and run away // List<Tuple<int, int>> ghostsInRange = GetCapturableGhosts(buster); // foreach (var ghost in ghostsInRange) // { // // Retrieve the actual ghost // Ghost foundGhost = Ghosts.Find(e => e.EntityId == ghost.Item1); // // Do we already have found a ghost to capture ? If not we search // if (buster.GhostInRange == null) // { // buster.GhostInRange = foundGhost; // buster.GotAnOrder = true; // break; // } // } // if (buster.GhostInRange == null) // { // ghostsInRange = GetChasableGhosts(buster); // foreach (var ghost in ghostsInRange) // { // // Retrieve the actual ghost // Ghost foundGhost = Ghosts.Find(e => e.EntityId == ghost.Item1); // // Do we already have found a ghost to capture ? If not we search // if (buster.GhostInRange == null) // { // buster.GhostChased = foundGhost; // buster.GotAnOrder = true; // break; // } // } // } // } // if (buster.Position == BlockerPosition && !buster.GotAnOrder) // { // buster.TargetPosition = new Vector2(BlockerPosition.X, BlockerPosition.Y - 50); // buster.GotAnOrder = true; // } // else // { // buster.EnemyInRange = null; // buster.GhostInRange = null; // buster.GhostChased = null; // buster.TargetPosition = BlockerPosition; // buster.GotAnOrder = true; // } // } // } //} } // The buster use all the informations given by the brain to take a decision foreach (var buster in Busters) { buster.ComputeInformations(); // if the buster was chasing a ghost and he now stop moving we remove it's captured ghost reference if (buster.GhostChased != null && buster.State != BusterState.MoveState) { Player.print("Buster " + buster.EntityId + " : " + buster.State.ToString()); buster.GhostChased = null; } // if the buster was chasing an enemy and he now stop moving we remove it's chased enemy reference if (buster.EnemyChased != null && buster.State != BusterState.MoveState) { if (buster.EnemyChased.IsCarryingAGhost) { buster.TargetPosition = buster.EnemyChased.Position; buster.GotAnOrder = true; } buster.EnemyChased = null; } } // With all the informations gathered we can set the TargetPosition value of our busters according to their choosed action foreach (var buster in Busters.FindAll(e => e.IsStunned == false)) { // If the buster is holding a ghost we tell them to go to the base if (buster.IsHoldingAGhost()) { buster.TargetPosition = BasePosition; } // If the buster is moving but not chasing something and not going to release a ghost, then he's actually scouting if (buster.EnemyChased == null && buster.GhostChased == null && buster.State == BusterState.MoveState && !buster.IsHoldingAGhost() && !buster.GotAnOrder) { Player.print("Buster " + buster.EntityId + " is scouting " + GridMap.WorldToGridPosition(buster.TargetPosition).ToString()); buster.IsScouting = true; // I'm scouting, and I'm at my target position, I need a new cell to explore if (buster.TargetPosition == buster.Position) { buster.TargetPosition = GetNextPosition(buster); Player.print("Buster " + buster.EntityId + " is taking a new scout target " + GridMap.WorldToGridPosition(buster.TargetPosition).ToString()); } } else { if (buster.IsScouting) { // If I was scouting and I now have a new order, I cancel my scout order Player.print("Buster " + buster.EntityId + " stop scouting"); StopScouting(buster); } else if (buster.EnemyChased != null) { Player.print("Buster " + buster.EntityId + " continue chasing enemy " + buster.EnemyChased.EntityId); // If I'm chasing an enemy and he's not visible anymore or there is nothing at his position, we cancel and scout if (buster.TargetPosition == buster.EnemyChased.Position || !buster.EnemyChased.IsVisible) { buster.EnemyChased = null; buster.IsScouting = true; Player.print("Buster " + buster.EntityId + " is taking a new scout target"); buster.TargetPosition = GetNextPosition(buster); } } else if (buster.GhostChased != null) { Player.print("Buster " + buster.EntityId + " continue chasing ghost " + buster.GhostChased.EntityId); // If I'm chasing a ghost and there is nothing at his position, we cancel and scout if (buster.Position == buster.GhostChased.Position || buster.GhostChased.Captured) { buster.GhostChased = null; buster.IsScouting = true; Player.print("Buster " + buster.EntityId + " is taking a new scout target"); buster.TargetPosition = GetNextPosition(buster); } } } } // With all the informations we can get the target position that the buster must follow foreach (var buster in Busters.FindAll(e => e.IsStunned == false)) { if (buster.GhostChased != null) { buster.TargetPosition = buster.GhostChased.Position; } if (buster.EnemyChased != null) { buster.TargetPosition = buster.EnemyChased.Position; } if (buster.IsHoldingAGhost() && !buster.IsInDropZone) { buster.TargetPosition = BasePosition; } if (buster.LastState == BusterState.ReleaseState) { CapturedGhost.Add(buster.GhostCaptured.EntityId); } } }
/// <summary> /// Update the buser with the turn's informations /// </summary> /// <param name="entityId">id of the buster</param> /// <param name="position"></param> /// <param name="value">Ghost id being carried, number of turns before stun goes away</param> /// <param name="state">0=idle, 1=carrying a ghost, 2=stuned buster</param> public void UpdateBusterInformations(int entityId, Vector2 position, int value, int state) { // Find the buster Buster buster = Busters.Find(e => e.EntityId == entityId); switch (state) { case 0: Player.print("Buster : " + entityId.ToString() + " / Idle"); break; case 1: Player.print("Buster : " + entityId.ToString() + " / Carrying"); // Search the ghost Ghost ghost = Ghosts.Find(e => e.EntityId == value); // Set the captured ghost for the current buster buster.GhostCaptured = ghost; // Set the ghost as captured buster.GhostCaptured.Captured = true; break; case 2: Player.print("Buster : " + entityId.ToString() + " / Stunned"); // We got stunned, release our ghost if needed // If we were carrying a ghost and we drop it outside of the base we mark it as catchable if (!buster.IsInDropZone && buster.GhostCaptured != null) { buster.GhostCaptured.Captured = false; } // Reset capture and scout variables buster.GhostCaptured = null; buster.GhostChased = null; buster.EnemyChased = null; buster.TargetPosition = buster.Position; StopScouting(buster); buster.IsStunned = true; break; } // Update its position buster.Position = position; // Check for buster if they are in base range if (Vector2.Distance(buster.Position, BasePosition) <= 1600) { buster.IsInDropZone = true; } else { buster.IsInDropZone = false; } // Set target position when we've to release if (buster.LastState == BusterState.ReleaseState) { buster.TargetPosition = buster.Position; } // Update map with the position of the buster GridMap.UpdateMap(buster.Position, Turn); }
public void StopScouting(Buster buster) { buster.IsScouting = false; GridMap.UnlockCell(buster.TargetPosition); }