pytron-book/src/Map.md

3.6 KiB

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

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:

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:

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:

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:

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:

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:

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
my_map = Map(5, 5, Tile.EMPTY, Tile.WALL);
# ...
my_input = map.state_for_player(1)