//Create a bfs graph based on startPos. public Bfs(Consoden.TankGame.GameState gameState, Position startPos) { this.gameState=gameState; this.startPos = startPos; gamePaths = new int[SizeX, SizeY]; for (int x=0; x<SizeX; x++) { for (int y=0; y<SizeY; y++) { gamePaths [x, y] = int.MaxValue; } } gamePaths [startPos.X, startPos.Y] = 0; EvaluateShortestPaths (startPos, 1); }
//Find the direction to move for shortest path to target. public Consoden.TankGame.Direction.Enumeration BacktrackFromSquare(Position target) { var nextMove = Backtrack (target); // Shortest path is one step less if (Move (startPos, Consoden.TankGame.Direction.Enumeration.Left) == nextMove) return Consoden.TankGame.Direction.Enumeration.Left; else if (Move (startPos, Consoden.TankGame.Direction.Enumeration.Right) == nextMove) return Consoden.TankGame.Direction.Enumeration.Right; else if (Move (startPos, Consoden.TankGame.Direction.Enumeration.Up) == nextMove) return Consoden.TankGame.Direction.Enumeration.Up; else if (Move (startPos, Consoden.TankGame.Direction.Enumeration.Down) == nextMove) return Consoden.TankGame.Direction.Enumeration.Down; else return Consoden.TankGame.Direction.Enumeration.Neutral; }
//Check if square is a wall. public bool IsWall(Position p) { return RawVal (p.X, p.Y) == 'x'; }
//Check if square has a smoke grenade. public bool IsSmokeGrenade(Position p) { return RawVal (p.X, p.Y) == 's'; }
//Is there a redeemer in this square public bool IsRedeemerInPosition(Position p) { for (int i=0; i<this.gameState.Redeemers.Count; i++) { if (gameState.Redeemers [i].IsNull ()) continue; Consoden.TankGame.Redeemer redeemer = gameState.Redeemers [i].Obj; if (p.X == redeemer.PosX.Val && p.Y == redeemer.PosY.Val) { return true; } } return false; }
//Check if square has redeemerAmmo. public bool isRedeemerAmmo(Position p) { return RawVal (p.X, p.Y) == 'r'; }
//Check if there is poison gas in this square. public bool IsPoisonGas(Position p) { return RawVal (p.X, p.Y) == 'p'; }
//Is there a missile in this square public bool IsMissileInPosition(Position p) { for (int i=0; i<this.gameState.Missiles.Count; i++) { if (gameState.Missiles [i].IsNull ()) continue; Consoden.TankGame.Missile missile = gameState.Missiles [i].Obj; if ((p.X == missile.HeadPosX.Val && p.Y == missile.HeadPosY.Val) || (p.X == missile.TailPosX.Val && p.Y == missile.TailPosY.Val)) { return true; } } return false; }
private Position Backtrack(Position target) { if (!CanReachSquare(target)) { return new Position (-1, -1); } // Steps to square int steps = StepsToSquare(target); // one step - found the next square if (steps == 1) { return target; } // Shortest path is one step less var left = Move (target, Consoden.TankGame.Direction.Enumeration.Left); if (StepsToSquare(left) == (steps-1)) { return Backtrack(left); } var right = Move (target, Consoden.TankGame.Direction.Enumeration.Right); if (StepsToSquare(right) == (steps-1)) { return Backtrack(right); } var up = Move (target, Consoden.TankGame.Direction.Enumeration.Up); if (StepsToSquare(up) == (steps-1)) { return Backtrack(up); } var down = Move (target, Consoden.TankGame.Direction.Enumeration.Down); if (StepsToSquare(down) == (steps-1)) { return Backtrack(down); } // How did this happend?? return new Position (-1, -1); }
//Check if there is poison gas in this square. public bool IsLaserAmmo(Position p) { return RawVal (p.X, p.Y) == 'l'; }
//Check if there is a coin in this square. public bool IsCoin(Position p) { return RawVal (p.X, p.Y) == '$'; }
//Check if square is reachable. public bool CanReachSquare(Position pos) { if (pos.X >= SizeX || pos.X < 0 || pos.Y >= SizeY || pos.Y < 0) { return false; } return gamePaths[pos.X, pos.Y] < int.MaxValue; }
private void EvaluateShortestPathsHelper(Position nextPos, int steps) { char next = RawVal (nextPos.X, nextPos.Y); bool isEmpty=next=='.' || next=='$' || next=='p'; if (isEmpty) { if (steps < gamePaths[nextPos.X, nextPos.Y]) { gamePaths[nextPos.X, nextPos.Y] = steps; EvaluateShortestPaths(nextPos, steps+1); } } }
private void EvaluateShortestPaths(Position pos, int steps) { EvaluateShortestPathsHelper(Move(pos, Consoden.TankGame.Direction.Enumeration.Left), steps); EvaluateShortestPathsHelper(Move(pos, Consoden.TankGame.Direction.Enumeration.Right), steps); EvaluateShortestPathsHelper(Move(pos, Consoden.TankGame.Direction.Enumeration.Up), steps); EvaluateShortestPathsHelper(Move(pos, Consoden.TankGame.Direction.Enumeration.Down), steps); }
//Move p one step in specified direction and returns the new position. public Position Move(Position p, Consoden.TankGame.Direction.Enumeration d) { switch (d) { case Consoden.TankGame.Direction.Enumeration.Left: return new Position ((p.X - 1 + SizeX) % SizeX, p.Y); case Consoden.TankGame.Direction.Enumeration.Right: return new Position ((p.X + 1) % SizeX, p.Y); case Consoden.TankGame.Direction.Enumeration.Up: return new Position (p.X, (p.Y - 1 + SizeY) % SizeY); case Consoden.TankGame.Direction.Enumeration.Down: return new Position (p.X, (p.Y + 1) % SizeY); default: return p; } }
//Check if there is a mine in this square. public bool IsMine(Position p) { return RawVal (p.X, p.Y) == 'o'; }
//Print game state public void PrintState() { Console.WriteLine ("Game board"); PrintMap(); Console.WriteLine ("Own position {0},{1}", OwnPosition.X, OwnPosition.Y); Console.WriteLine ("Enemy position {0},{1}", EnemyPosition.X, EnemyPosition.Y); Console.WriteLine ("Active missiles"); for (int i=0; i<this.gameState.Missiles.Count; i++) { if (gameState.Missiles [i].IsNull ()) continue; Consoden.TankGame.Missile missile = gameState.Missiles [i].Obj; Position head = new Position (missile.HeadPosX.Val, missile.HeadPosY.Val); Position tail = new Position (missile.TailPosX.Val, missile.TailPosY.Val); Consoden.TankGame.Direction.Enumeration direction = missile.Direction.Val; Console.WriteLine ("Missile position - head {0},{1}", head.X, head.Y); Console.WriteLine ("Missile position - tail {0},{1}", tail.X, tail.Y); Console.Write ("Missile direction "); switch (direction) { case Consoden.TankGame.Direction.Enumeration.Left: Console.WriteLine ("Left"); break; case Consoden.TankGame.Direction.Enumeration.Right: Console.WriteLine ("Right"); break; case Consoden.TankGame.Direction.Enumeration.Up: Console.WriteLine ("Up"); break; case Consoden.TankGame.Direction.Enumeration.Down: Console.WriteLine ("Down"); break; case Consoden.TankGame.Direction.Enumeration.Neutral: Console.WriteLine ("Neutral"); break; } Console.WriteLine (); } Console.WriteLine (); }
//Least number of moves needed to reach square. public int StepsToSquare(Position pos) { if (pos.X >= SizeX || pos.X < 0 || pos.Y >= SizeY || pos.Y < 0) { return int.MaxValue; } return gamePaths[pos.X, pos.Y]; }