# The map module The `map` module contains two important classes: - the `Tile` class - the `Map` class ## The `Tile` class This class contains the different possible values for the tiles of the map. Each value has its own meaning, and the names given are explicit enough. This class also contains a method named `color` which return a 3-uple containing the red, green and blue channels of the colors of the corresponding tile. This is espeacially useful for rendering the game on a window. ## The `Map` class `Map` is one of the most important class of this project. It is made to be easy to manipulate with things like PyTorch. It contains an `np.array` of two dimensions containing two rows and two columns more that what specify, because is automatically adds border to your map. This means that when you run ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) ``` it really creates a 7x7 `np.array`, in which the interior is filled with `Tile.EMPTY` and the border with `Tile.WALL`. ### Playing with maps If you want to modify the map, you can do so by using the getters. **Be careful, the getter doesn't take the border into account**. You won't be able to modify the border with the getters. To use the getters, you can do like this: ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) # Sets the top left corner of the map to PLAYER_ONE_HEAD # This does not modify the border, it modifies the inner tile. my_map[0, 0] = Tile.PLAYER_ONE_HEAD ``` You can easily clone a map: ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) my_second_map = my_map.clone() # Clones the whole map ``` If you want to clone the array of a map and apply a function to it at the same time, you can do like this: ``` python def my_function(tile): return tile.value + 1 my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) my_map.apply(my_function) ``` If you need, you can use some more parameters and create lambdas, which might give you a clearer code: ``` python def my_function(tile, offset): return tile.value + offset my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) my_map.apply(lambda tile: my_function(tile, 1)) ``` ### Playing with maps' np-arrays At any moment, you can get a reference to the `np.array` of the map by using the `array` method: ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) my_array = my_map.array() my_array[0][0] = ... # Modifies the top left tile of the border of the map ``` Be careful: when you get a reference to an np-array, you need to remember: - the np-array does cantain the border, so the (i, j) tile of the map is the (i + 1, j + 1) tile of the array - since you get a reference to the np-array, modifying it will also modify the map If you wan to modify an np-array without modifying the map, you can use the `clone_array` method: ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL) my_array = my_map.clone_array() # Modifying my_array won't modify my_map my_array[0][0] = ... ``` ### Getting input for your neural network First of all, it's important to realize that the map does not depend on who is the player 1. When a player's `action` method is called, it is called with the map as parameter, and also the id so that the player is able to know who he is on the map. You can easily convert the map to an input for your neural network by using the `state_for_player` method. It takes the id of the player as a parameter and returns a numpy array that will have: - 1 where tiles are empty - -1 where tiles are walls or bodies of snakes - 10 for the head of the player with the corresponding id - -10 for the head of the other player ``` python my_map = Map(5, 5, Tile.EMPTY, Tile.WALL); # ... my_input = map.state_for_player(1) ```