/// <summary> /// The main method of the FloodFill AI. /// </summary> /// <param name="p"> Point to start/continue the flooding from. </param> private void Flood(Point p, int keyIndex, int slidingIndex) { // If the exit has already been found or we have already visited this tile, stop the flooding. if (exitFound || visited[p.X, p.Y, keyIndex, slidingIndex]) { return; } // GuardTile is subclass of HoleTile so this will return for both. // Can't use the same for walls because DoorTile is a subclass of WallTile. // Can't use doors for which you don't have the key. if (tileField.GetTile(p) is HoleTile || tileField.GetType(p) == TileType.Wall || (tileField.GetType(p) == TileType.Door && (keyIndex & keys[(tileField.GetTile(p) as DoorTile).DoorColor]) == 0)) { return; } // The current tile has been visited. visited[p.X, p.Y, keyIndex, slidingIndex] = true; // Add the current tile to the route. route.Push(p); // If this is the exit, the algorithm is done. // Make sure this is after pushing p to route, otherwise you will stand still before the exit. if (tileField.GetType(p) == TileType.End) { exitFound = true; return; } // Check if the current tile is a keytile, // and whether we have already picked up a key of this color. if (tileField.GetType(p) == TileType.Key) { // Add the key to the keyIndex keyIndex |= keys[(tileField.GetTile(p) as KeyTile).KeyColor]; } // If we're on an ice tile, we need the sliding direction to see if we can change direction. if (tileField.GetType(p) == TileType.Ice) { // Retrieve the current and previous point in the route. Point current = route.Pop(); Point previous = route.Pop(); // Calculate the direction you're moving at. slidingDirection = current - previous; // Return the current and previous point to the route. route.Push(previous); route.Push(current); } //If you can move onto the tile behind the ice tile, you can't change direction if (tileField.GetType(p) == TileType.Ice && !(tileField.GetTile(p.X + slidingDirection.X, p.Y + slidingDirection.Y) is WallTile)) { //Only keep going in this direction Flood(p + slidingDirection, keyIndex, slides[GetDirectionFromPoint(slidingDirection)]); } // Otherwise we can move in all directions. else { PlayerAction[] action = getActionsInRandomOrder(); for (int i = 0; i < 5; i++) { if (action[i] == PlayerAction.SPECIAL && tileField.GetType(p) == TileType.Portal) { Flood((tileField.GetTile(p) as PortalTile).Destination, keyIndex, 0); } else if (action[i].IsDirection()) { // Obstacles are checked earlier in Flood() so we only need to check whether the new point is in the tilefield. if (!tileField.OutOfTileField(p + action[i].ToDirection().ToPoint())) { Flood(p + action[i].ToDirection().ToPoint(), keyIndex, 0); } } } } // All directions are done, return to the previous point. // If the exit has been found, keep the route intact. if (!exitFound && route.Count > 0) { route.Pop(); } }