Problem p01453 - Generation 3

Orig Description

Problem G: Spring Tile
One morning, when you woke up, you were in a maze full of springs.
You don't know why you are in this unfamiliar place. Though there is an option to wait for help quietly, you know from experience that if you stay in such a maze for a long time, a sudden gust of wind will eventually blow and blow you away. However, it is impossible to judge the time until the gust of wind comes. Therefore, you thought that the best strategy would be to act so that the expected value of the number of moves required to escape from the maze is minimized before the gust of wind blows.
You picked up an unidentified scroll that had fallen at your feet and tried reading it, and by chance, you were able to perceive the entire map of the maze. Furthermore, by drinking the grass you happened to have, you were able to know the positions of all the traps. Apparently, there are no other traps in this maze except for dangerous monsters and springs.
This maze is in the shape of a rectangle with several types of tiles arranged in a row, as shown below, for example.
########
#..##g.#
#*#.*#.#
#......#
#*s#*.*#
########
"." : Floor. You can move around freely on it.
"#" : Wall. You cannot enter the wall.
"s" : Your initial position. The tile below this tile is a floor.
"g" : Stairs. If you get on this tile, you will have escaped from the maze.
"*" : Spring. If you get on this tile, you will be randomly thrown onto one of the floors (excluding the stair and spring tiles). The probability of being thrown onto each floor is the same.
The type of tile is one of the five listed above.
You can move one square in any direction (up, down, left, or right) from the tile you are currently on. However, you cannot move diagonally.
Given the map of the maze, find the expected number of moves required to escape from the maze if you take the best strategy. Do not include the number of moves you are thrown by the spring in the total number of moves.
Input
W H
c11 c12 ... c1w
c21 c22 ... c2w
::    :
ch1 ch2 ... ccw
The first line of input contains two integers W (3 ≤ W ≤ 500) and H (3 ≤ H ≤ 500), written in this order, separated by a single space. W is the width of the maze and H is the height of the maze.
The next H lines contain W characters each, representing the map of the maze (not separated by spaces). The format of this part is as shown in the example above. Note that "s" and "g" appear exactly once each in the data. Also, the outermost layer of the maze is surrounded by walls.
It can be assumed that even if you move or are thrown by a spring in any way, it will not fall into a "state where it is impossible to escape, even if you can arbitrarily set the floor you are thrown by a spring".
Output
Find the expected number of moves required to escape from the maze if you take the best strategy. The output may contain an error, but the relative error with respect to the true value must be less than 10-9.
Sample Input 1
8 6
########
#..##g.#
#*#.*#.#
#......#
#*s#*.*#
########
Sample Output 1
5.857142857143
Sample Input 2
21 11
#####################
#*#*.*.*.*.*.*.*.*#*#
#*#...............#*#
#*#.#.#.#.#.#.#.#.#*#
##.#.#.#.#.#.#.#.#.##
#...................#
##.#.#.#.#.#.#.#.#.##
#s#.#.#.#.#.#.#.#.#g#
#...................#
#...................#
#####################
Sample Output 2
20.000000000000
Sample Input 3
9 8
#########
#...#*.*#
#.*.#...#
#...#*.*#
#########
#.s....g#
#.*#.*..#
#########
Sample Output 3
5.000000000000

Extracted Specification

Canonicalized Input Description:

An integer W (3 ≤ W ≤ 500), representing some width.
An integer H (3 ≤ H ≤ 500), representing some height.
H lines each containing W characters from the set {'.', '#', 's', 'g', '*'}. The characters in each line are not separated by spaces.

### Example Input:

```
8 6
########
#..##g.#
#*#.*#.#
#......#
#*s#*.*#
########
```

### Function Signature:
Write a function f(W, H, grid) that takes in the input.
def f(W: int, H: int, grid: List[str]):
    ''' 
    W: an integer 
    H: an integer 
    grid: a list of strings
    '''

Test Case Generator

Sure, I'll create a test case generator for the "Spring Tile" problem. The generator will create random mazes based on the given constraints. 

Here's a Python function to generate random test cases for this problem:

```python
import random

def generate_maze(W, H):
    # Create a maze filled with walls
    maze = [['#' for _ in range(W)] for _ in range(H)]

    # Helper function to place a character at a random position that's not a wall
    def place_random(char):
        while True:
            x = random.randint(1, W-2)
            y = random.randint(1, H-2)
            if maze[y][x] == '.':
                maze[y][x] = char
                return
    
    # Generate inner maze structure with floors
    for y in range(1, H-1):
        for x in range(1, W-1):
            maze[y][x] = random.choice(['.', '*', '.'])

    # Place the start 's' and goal 'g'
    place_random('s')
    place_random('g')
    
    return maze

def tcgen():
    # Define the dimensions of the maze
    W = random.randint(3, 500)
    H = random.randint(3, 500)
    
    # Generate the maze
    maze = generate_maze(W, H)
    
    # Convert the maze to the required input format
    input_maze = '\n'.join([''.join(row) for row in maze])
    
    # Print the dimensions and the maze
    print(f"{W} {H}")
    print(input_maze)

# Example usage
tcgen()
```

**Explanation:**
1. **generate_maze(W, H)**: This function creates a maze with the given width (W) and height (H).
   - It starts by filling the entire maze with walls ('#').
   - Then it randomly places floor tiles ('.') and spring tiles ('*') in the inner part of the maze.
   - Finally, it places the start ('s') and goal ('g') tiles at random positions that are not walls.

2. **tcgen()**: This function generates random dimensions for the maze, generates the maze itself, and then prints it in the required format.

You can call `tcgen()` to generate a new random test case each time. Adjust the random choices or constraints as needed based on the problem requirements.

Extract Arguments

def extract_arguments(fh):
    W, H = map(int, fh.readline().strip().split())
    maze = [fh.readline().strip() for _ in range(H)]
    return W, H, maze

# if __name__ == "__main__":
#     input_path = sys.argv[1]
#     with open(input_path, 'r') as fh: 
#         W, H, maze = extract_arguments(fh)
#         f(W, H, maze)