private Tuple <double, Point> calcScore(GameState.Option option, List <GameState> futureStates, List <MapPoint> map) { GameState currentState = States[States.Count() - 1]; GameState.Entity my = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team); Point p = option.Location; // if (option.Bomb && (option.Location == new Point(0, 0) || option.Location == new Point(12, 0) || option.Location == new Point(12, 10) || option.Location == new Point(0, 10))) { return(new Tuple <double, Point>(Invalid, my.Position)); } //The tile is not worth visiting if it has a bomb, it will kill you if (currentState.Entities.Exists(e => e.Position.Equals(p) && e.Type == GameState.EntityType.Bomb)) { return(new Tuple <double, Point>(Invalid, my.Position)); } //Is the tile reachable? int distance = 0; bool reachable = false; Point nextStep = my.Position; if (my.Position == p) { reachable = true; } if (map.Exists(mp => mp.Position == p)) { MapPoint best = map.Where(mp => mp.Position == p).OrderBy(mp => mp.Depth).First(); distance = best.Depth; nextStep = best.Trail.Count() < 2 ? p : best.Trail[1]; reachable = true; } //The tile is not covered by the map, so it's either not free or is very far, check with A* provided the tile is empty else if (currentState.Board[p.X, p.Y] == '.') { List <Point> path = GetPath(currentState, my.Position, p); distance = path.Count(); if (distance > 0) { reachable = true; nextStep = path[path.Count() - 1]; } } if (!reachable) { return(new Tuple <double, Point>(Invalid, my.Position)); } //Calc bombing score GameState futureState = futureStates[Math.Min(distance, 7)]; int score = 0; if (option.Bomb) { foreach (Point d in Directions) { for (int i = 1; i < my.Range; i++) { // Point candidate = new Point(p.X + d.X * i, p.Y + d.Y * i); if (candidate.X < 0 || candidate.X >= GameState.W || candidate.Y < 0 || candidate.Y >= GameState.H) { break; } //Mark boxes if ("012".Contains(futureState.Board[candidate.X, candidate.Y])) { //Powerups count more if ("12".Contains(futureState.Board[candidate.X, candidate.Y])) { score++; } score++; break; } //Attack other players if (currentState.Entities.Exists(e => e.Type == GameState.EntityType.Player && e.Team != Team && e.Position == candidate)) { if (Manhattan(my.Position, candidate) >= 2) { score++; } } //Stop at items if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == candidate)) { break; } //Stop at walls if (futureState.Board[candidate.X, candidate.Y] == 'X') { break; } } } } //Calc power-up score if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == p)) { score += 3; } // if (score == 0) { return(new Tuple <double, Point>(Invalid, my.Position)); } //Factor in the distance int waitTurns = 0; if (option.Bomb) { int countBombs = currentState.Entities.Count(e => e.Type == GameState.EntityType.Bomb && e.Team == Team); if (countBombs >= my.Rounds) { waitTurns = currentState.Entities.Where(e => e.Type == GameState.EntityType.Bomb && e.Team == Team) .OrderBy(e => e.Rounds).First().Rounds; } } int delay = Math.Max(waitTurns, distance); // return(new Tuple <double, Point>(1.5 * score - delay, nextStep)); }
private List <GameState> computeFutureStates(Point plantBomb) { const int Exploded = 99; GameState currentState = States[States.Count() - 1]; GameState.Entity my = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team); List <GameState> futureStates = new List <GameState>(); for (int count = 0; count < 8; count++) { //Calculate bomb explosions and blast map GameState futureState = new GameState(currentState); futureState.Entities = futureState.Entities.Where(e => e.Type != GameState.EntityType.Player).ToList(); //Countdown foreach (GameState.Entity bomb in futureState.Entities.Where(e => e.Type == GameState.EntityType.Bomb)) { bomb.Rounds--; } //Add a bomb if (count == 0 && plantBomb.X >= 0 && plantBomb.Y >= 0) { futureState.Entities.Add(new GameState.Entity() { Type = GameState.EntityType.Bomb, Team = Team, Position = plantBomb, Range = my.Range, Rounds = 8 }); } //Explode the bombs List <Point> boxes = new List <Point>(); while (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Bomb && e.Rounds == 0)) { GameState.Entity bomb = futureState.Entities.First(e => e.Type == GameState.EntityType.Bomb && e.Rounds == 0); bomb.Rounds = Exploded; // foreach (Point p in Directions) { //Start from 0 to include blast map and trigger bombs at the same location for (int i = 0; i < bomb.Range; i++) { // Point candidate = new Point(bomb.Position.X + p.X * i, bomb.Position.Y + p.Y * i); if (candidate.X < 0 || candidate.X >= GameState.W || candidate.Y < 0 || candidate.Y >= GameState.H) { break; } futureState.Blasts.Add(candidate); //Trigger nearby bombs if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Bomb && e.Position == candidate && e.Rounds != Exploded)) { futureState.Entities.First(e => e.Type == GameState.EntityType.Bomb && e.Position == candidate && e.Rounds != Exploded).Rounds = 0; if (i > 0) { break; } } //Mark boxes and stop the blast if ("012".Contains(futureState.Board[candidate.X, candidate.Y])) { boxes.Add(candidate); break; } //Stop at items if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == candidate)) { GameState.Entity item = futureState.Entities.First(e => e.Type == GameState.EntityType.Item && e.Position == candidate); futureState.Entities.Remove(item); break; } //Stop at walls if (futureState.Board[candidate.X, candidate.Y] == 'X') { break; } } } } //Remove bombs futureState.Entities = futureState.Entities.Where(e => e.Rounds != Exploded).ToList(); //Boxes and items foreach (Point box in boxes.Distinct()) { //Drop items if ("12".Contains(futureState.Board[box.X, box.Y])) { futureState.Entities.Add(new GameState.Entity() { Type = GameState.EntityType.Item, Team = 0, Position = box, Rounds = int.Parse("" + futureState.Board[box.X, box.Y]), Range = 0 }); } //Remove box futureState.Board[box.X, box.Y] = '.'; } // futureStates.Add(futureState); currentState = futureState; } //Visualize blast maps for (int i = 0; i < 8; i++) { //debug("Future state " + i + "\n" + futureStates[i].Visualize()); } // return(futureStates); }
private Tuple <List <MapPoint>, List <MapPoint> > computeMap(List <GameState> futureStates) { // GameState currentState = States[States.Count() - 1]; GameState.Entity my = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team); // List <Point> Movements5 = new List <Point>(); Movements5.Add(new Point(1, 0)); Movements5.Add(new Point(-1, 0)); Movements5.Add(new Point(0, 1)); Movements5.Add(new Point(0, -1)); Movements5.Add(new Point(0, 0)); // int depth = 0; int count = 0; const int Limit = 200; List <MapPoint> map = new List <MapPoint>(); List <MapPoint> culledMap = new List <MapPoint>(); map.Add(new MapPoint() { Position = my.Position, Trail = new List <Point>(), Depth = depth }); Dictionary <int, int> culling = new Dictionary <int, int>(); bool timeout = false; // while (depth < 8 && !timeout) { //Wipe out cells covered by bomb blasts GameState futureState = futureStates[depth]; if (map.Exists(p => p.Depth == depth && futureState.Blasts.Contains(p.Position))) { culling[depth] = map.Count(p => p.Depth == depth && futureState.Blasts.Contains(p.Position)); map = map.Where(p => !(p.Depth == depth && futureState.Blasts.Contains(p.Position))).ToList(); culledMap = new List <MapPoint>(); foreach (MapPoint mp in map.Where(mpp => mpp.Depth == depth)) { culledMap.Add(mp); } } //Stop if certain death if (map.Count(p => p.Depth == depth) == 0) { return(new Tuple <List <MapPoint>, List <MapPoint> >(null, null)); } // if (count > Limit) { timeout = true; break; } //Spawn children List <MapPoint> newPoints = new List <MapPoint>(); foreach (MapPoint mapPoint in map.Where(m => m.Depth == depth)) { foreach (Point d in Movements5) { Point candidate = new Point(mapPoint.Position.X + d.X, mapPoint.Position.Y + d.Y); //Out of bounds if (candidate.X < 0 || candidate.X >= GameState.W || candidate.Y < 0 || candidate.Y >= GameState.H) { continue; } //A bomb if (d != new Point(0, 0)) { if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Bomb && e.Position == candidate)) { continue; } } //A box or a wall if (futureState.Board[candidate.X, candidate.Y] != '.') { continue; } //Add List <Point> trail = new List <Point>(); foreach (Point t in mapPoint.Trail) { trail.Add(t); } trail.Add(mapPoint.Position); newPoints.Add(new MapPoint() { Position = candidate, Trail = trail, Depth = depth + 1 }); count++; } } foreach (MapPoint p in newPoints) { map.Add(p); } depth++; } //Visualize the map debug("culledMap.Count() " + culledMap.Count()); if (culledMap.Count() > 0) { foreach (MapPoint point in culledMap) { string line = "(" + point.Position.X + ", " + point.Position.Y + ") "; foreach (Point p in point.Trail) { line += "" + p.X + "," + p.Y + "->"; } //debug(line); } } bool dump = false; if (dump) { debug("map.Count() " + map.Count()); int maxDepth = -1; if (map.Count() > 0) { maxDepth = map.Max(p => p.Depth); } for (int d = 0; d <= maxDepth; d++) { //debug("Points for d=" + d + (culling.ContainsKey(d) ? ", " + culling[d] + " culled" : "")); foreach (MapPoint point in map.Where(p => p.Depth == d)) { string line = "(" + point.Position.X + ", " + point.Position.Y + ") "; foreach (Point p in point.Trail) { line += "" + p.X + "," + p.Y + "->"; } debug(line); } } } // return(new Tuple <List <MapPoint>, List <MapPoint> >(map, culledMap)); }
private double calcScore(GameState.Option option) { Point p = option.Location; GameState currentState = States[States.Count() - 1]; GameState.Entity my = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team); if (my.Position == p) { return(Invalid); } //Is the tile empty? if (currentState.Board[p.X, p.Y] != '.') { return(Invalid); } if (currentState.Entities.Exists(e => e.Position.Equals(p) && e.Type == GameState.EntityType.Bomb)) { return(Invalid); } //Is the tile reachable? int distance = GetPath(currentState, my.Position, p).Count(); if (distance == 0) { return(Invalid); } //Calc future state - explode all the bombs and mark all the boxes GameState futureState = new GameState(currentState); //Place a bomb in future state if previous strategy is to bomb if (States.Count() >= 2 && States[States.Count() - 2].Strategy.Bomb) { futureState.Entities.Add(new GameState.Entity() { Team = Team, Type = GameState.EntityType.Bomb, Position = my.Position, Range = my.Range, Rounds = 8 }); } // foreach (GameState.Entity bomb in futureState.Entities.Where(e => e.Type == GameState.EntityType.Bomb)) { foreach (Point d in Directions) { for (int i = 1; i < bomb.Range; i++) { // Point candidate = new Point(bomb.Position.X + d.X * i, bomb.Position.Y + d.Y * i); if (candidate.X < 0 || candidate.X >= GameState.W || candidate.Y < 0 || candidate.Y >= GameState.H) { break; } //Mark boxes and stop the blast if ("012".Contains(futureState.Board[candidate.X, candidate.Y])) { futureState.Board[candidate.X, candidate.Y] = '.'; break; } //Stop at items if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == candidate)) { GameState.Entity item = futureState.Entities.First(e => e.Type == GameState.EntityType.Item && e.Position == candidate); break; } //Stop at walls if (futureState.Board[candidate.X, candidate.Y] == 'X') { break; } } } } //Calc bombing score int score = 0; if (option.Bomb) { foreach (Point d in Directions) { for (int i = 1; i < my.Range; i++) { // Point candidate = new Point(p.X + d.X * i, p.Y + d.Y * i); if (candidate.X < 0 || candidate.X >= GameState.W || candidate.Y < 0 || candidate.Y >= GameState.H) { break; } //Mark boxes if ("012".Contains(futureState.Board[candidate.X, candidate.Y])) { if ("12".Contains(futureState.Board[candidate.X, candidate.Y])) { score++; } score++; break; } //Stop at items if (futureState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == candidate)) { break; } //Stop at walls if (futureState.Board[candidate.X, candidate.Y] == 'X') { break; } } } } //Calc power-up score if (currentState.Entities.Exists(e => e.Type == GameState.EntityType.Item && e.Position == p)) { score += 3; } // if (score == 0) { if (option.Bomb) { return(2 * Invalid); } return(Invalid); } //Factor in the distance int waitTurns = 0; if (option.Bomb) { int countBombs = currentState.Entities.Count(e => e.Type == GameState.EntityType.Bomb && e.Team == Team); if (countBombs >= my.Rounds) { waitTurns = currentState.Entities.Where(e => e.Type == GameState.EntityType.Bomb && e.Team == Team) .OrderBy(e => e.Rounds).First().Rounds; } } int delay = Math.Max(waitTurns, distance); // return(1.5 * score - delay); }