pytron-book/src/Map.md

122 lines
3.6 KiB
Markdown
Raw Normal View History

2019-05-22 10:59:27 +02:00
# 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
```
<strong>
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
</strong>
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)
```