private string compute() { // GameState currentState = States[States.Count() - 1]; Point myPosition = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team).Position; // Timer.Reset(); Timer.Start(); // List <GameState> futureStatesBomb = computeFutureStates(myPosition); Tuple <List <MapPoint>, List <MapPoint> > mapsBomb = computeMap(futureStatesBomb); // List <GameState> futureStates = computeFutureStates(new Point(-1, -1)); Tuple <List <MapPoint>, List <MapPoint> > maps = computeMap(futureStates); if (maps.Item1 == null) { maps = new Tuple <List <MapPoint>, List <MapPoint> >(new List <MapPoint>(), new List <MapPoint>()); } // double planningTime = Timer.ElapsedMilliseconds; debug("Planning - " + planningTime + "ms"); // List <Point> around = new List <Point>(); for (int i = 0; i < GameState.W; i++) { for (int j = 0; j < GameState.H; j++) { around.Add(new Point(i, j)); } } around = around.OrderBy(p => Manhattan(p, myPosition)).ToList(); // int pointer = 0; List <Tuple <GameState.Option, Tuple <double, Point> > > options = new List <Tuple <GameState.Option, Tuple <double, Point> > >(); while ((options.Count() < 20) || (Timer.ElapsedMilliseconds < 90 && pointer < around.Count())) { Point p = around[pointer]; GameState.Option bomb = new GameState.Option() { Location = p, Bomb = true }; GameState.Option move = new GameState.Option() { Location = p, Bomb = false }; options.Add(new Tuple <GameState.Option, Tuple <double, Point> >(bomb, calcScore(bomb, futureStates, maps.Item1))); options.Add(new Tuple <GameState.Option, Tuple <double, Point> >(move, calcScore(move, futureStates, maps.Item1))); pointer++; } // options = options.OrderByDescending(o => o.Item2.Item1).ToList(); GameState.Option strategy = options[0].Item1; currentState.Strategy = strategy; // Timer.Stop(); long time = Timer.ElapsedMilliseconds; debug("Options - " + time + "ms, " + options.Count() + " items"); for (int i = 0; i < 8; i++) { debug((options[i].Item1.Bomb ? "BOMB " : "MOVE ") + options[i].Item1.Location.X + "," + options[i].Item1.Location.Y + " => " + options[i].Item2); } //Determine action string action = "MOVE"; if (States.Count() >= 2 && States[States.Count() - 2].Strategy.Bomb && States[States.Count() - 2].Strategy.Location == myPosition) { action = "BOMB"; } debug("Original action is " + action); //Target is the strategy's <Score, Nextstep>.Nextstep Point target = options[0].Item2.Item2; //Evasion if (mapsBomb.Item2 == null) { action = "MOVE"; debug("Cannot BOMB and run, change to MOVE"); } // List <MapPoint> culled = (action == "BOMB") ? mapsBomb.Item2 : maps.Item2; if (culled != null && culled.Count() > 0) { List <Point> validMoves; bool hasTrail1 = culled.First().Trail.Count() > 1; if (hasTrail1) { validMoves = culled.Select(trail => trail.Trail[1]).Distinct().ToList(); } else { validMoves = culled.Select(trail => trail.Position).Distinct().ToList(); } if (!validMoves.Contains(target)) { debug("Evasion from " + target + " to " + validMoves[0]); target = validMoves[0]; } } //Leaving a bomb if (Manhattan(target, myPosition) == 1 && (currentState.Entities.Exists(b => b.Type == GameState.EntityType.Bomb && b.Position == myPosition) || action == "BOMB")) { // List <Point> availableDirections = new List <Point>(); int range = (action == "BOMB") ? currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team).Range : currentState.Entities.Where(b => b.Type == GameState.EntityType.Bomb && b.Position == myPosition).Select(b => b.Range).Max(); int rounds = (action == "BOMB") ? 8 : currentState.Entities.Where(b => b.Type == GameState.EntityType.Bomb && b.Position == myPosition).Select(b => b.Rounds).Min(); //Check if in each direction has a corridor and turnaround foreach (Point d in Directions) { //Corridor must be long enough bool existsCorridor = true; for (int c = 1; c <= range; c++) { Point check = new Point(myPosition.X + d.X * c, myPosition.Y + d.Y * c); if (check.X < 0 || check.X >= GameState.W || check.Y < 0 || check.Y >= GameState.H) { existsCorridor = false; break; } if (currentState.Board[check.X, check.Y] != '.') { existsCorridor = false; } } //Or have turnaround within time int mustHaveTurnWithin = rounds - 2; bool hasTurnAround = false; for (int offset = 1; offset <= mustHaveTurnWithin; offset++) { //Corridor must exist Point check = new Point(myPosition.X + d.X * offset, myPosition.Y + d.Y * offset); if (check.X < 0 || check.X >= GameState.W || check.Y < 0 || check.Y >= GameState.H) { break; } if (currentState.Board[check.X, check.Y] != '.') { break; } //Sides bool checkHorizontal = (check.X != myPosition.X); Point upperLeft = checkHorizontal ? new Point(check.X, check.Y + 1) : new Point(check.X + 1, check.Y); Point lowerRight = checkHorizontal ? new Point(check.X, check.Y - 1) : new Point(check.X - 1, check.Y); bool noUpperLeft = upperLeft.X < 0 || upperLeft.X >= GameState.W || upperLeft.Y < 0 || upperLeft.Y >= GameState.H; bool noLowerRight = lowerRight.X < 0 || lowerRight.X >= GameState.W || lowerRight.Y < 0 || lowerRight.Y >= GameState.H; if ((!noUpperLeft && (currentState.Board[upperLeft.X, upperLeft.Y] == '.')) || (!noLowerRight && (currentState.Board[lowerRight.X, lowerRight.Y] == '.'))) { hasTurnAround = true; break; } } // if (existsCorridor || hasTurnAround) { availableDirections.Add(new Point(myPosition.X + d.X, myPosition.Y + d.Y)); } } // if (availableDirections.Count() > 0 && (!availableDirections.Contains(target))) { debug("Changed target from " + target + " to " + availableDirections[0]); target = availableDirections[0]; } } // int myBombsCount = currentState.Entities.Count(e => e.Team == Team && e.Type == GameState.EntityType.Bomb); if (myBombsCount >= 3) { action = "MOVE"; } if (options[0].Item2.Item1 < -50) { action = "MOVE"; } // return(action + " " + target.X + " " + target.Y); }
private string compute() { // Timer.Reset(); Timer.Start(); // GameState currentState = States[States.Count() - 1]; Point myPosition = currentState.Entities.First(e => e.Type == GameState.EntityType.Player && e.Team == Team).Position; List <Point> around = new List <Point>(); for (int i = 0; i < GameState.W; i++) { for (int j = 0; j < GameState.H; j++) { around.Add(new Point(i, j)); } } around = around.OrderBy(p => Manhattan(p, myPosition)).ToList(); // int pointer = 0; List <Tuple <GameState.Option, double> > options = new List <Tuple <GameState.Option, double> >(); while (Timer.ElapsedMilliseconds < 85 && pointer < around.Count()) { Point p = around[pointer]; GameState.Option bomb = new GameState.Option() { Location = p, Bomb = true }; GameState.Option move = new GameState.Option() { Location = p, Bomb = false }; options.Add(new Tuple <GameState.Option, double>(bomb, calcScore(bomb))); options.Add(new Tuple <GameState.Option, double>(move, calcScore(move))); pointer++; } // options = options.OrderByDescending(o => o.Item2).ToList(); GameState.Option strategy = options[0].Item1; currentState.Strategy = strategy; // Timer.Stop(); long time = Timer.ElapsedMilliseconds; debug("Options - " + options.Count() + " items, " + time + "ms"); for (int i = 0; i < 8; i++) { debug((options[i].Item1.Bomb ? "BOMB " : "MOVE ") + options[i].Item1.Location.X + "," + options[i].Item1.Location.Y + " => " + options[i].Item2); } // string action = "MOVE"; if (States.Count() >= 2 && States[States.Count() - 2].Strategy.Bomb && States[States.Count() - 2].Strategy.Location == myPosition) { action = "BOMB"; } Point target = strategy.Location; if (myPosition != target) { List <Point> path = GetPath(currentState, myPosition, target); target = path[path.Count() - 1]; } return(action + " " + target.X + " " + target.Y); }
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 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); }