From e14866950e7a6044a0dcf8c7c0c8d420eb5ec60a Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Wed, 13 Mar 2019 21:01:54 +0100 Subject: [PATCH] Adds docs --- README.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++---- tron/map.py | 8 +++- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9c5656f..3cf1aca 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ This program is a simple python game, made for implementing your own AIs. - [How to download the game](#how-to-download-the-game) - [How to play the game](#how-to-play-the-game) - [How to create your own AI](#how-to-create-your-own-ai) + - [Info about how map works](#about-map) ## How to download the game @@ -15,17 +16,20 @@ The first step is to clone the repository: git clone https://gitea.tforgione.fr/tforgione/pytron ``` -Then, ensure you have `python3` and `pygame` installed. You can test you have everything by executing the following command: +Then, ensure you have `python3` and `pygame` installed. You can test you have +everything by executing the following command: ``` python3 -c "import pygame" ``` - - if you get a `python3: command not found`, it means you don't have `python3`, you can install it on ubuntu like so: + - if you get a `python3: command not found`, it means you don't have + `python3`, you can install it on ubuntu like so: ``` sh sudo apt install python3 ``` - - if you get a `ImportError: No module named 'pygame'`, it means you don't have `pygame`, you can install it on ubuntu like so: + - if you get a `ImportError: No module named 'pygame'`, it means you don't + have `pygame`, you can install it on ubuntu like so: ``` sh sudo apt install python3-pip sudo pip3 install pygame @@ -33,16 +37,23 @@ python3 -c "import pygame" ## How to play the game -There are two runnable scripts in the repository, which are mostly here to be examples: +There are two runnable scripts in the repository, which are mostly here to be +examples: - - `play.py` which shows how to create a game with a window and play against an AI. - - `headless.py` which shows how to run a game with AIs without watching the interface, and thus, really fast. + - `play.py` which shows how to create a game with a window and play against + an AI. + - `headless.py` which shows how to run a game with AIs without watching the + interface, and thus, really fast. ## How to create your own AI -You need to write a class that derives from `snake.player.Player`. You have to define a constructor, so you can instanciate it, and implement the method `action` which takes as parameter the map of the game, and returns the direction you want to take. +You need to write a class that derives from `snake.player.Player`. You have to +define a constructor, so you can instanciate it, and implement the method +`action` which takes as parameter the map of the game, and returns the +direction you want to take. -For example, you can create a file `myplayer.py` at the root of this repository containing the following: +For example, you can create a file `myplayer.py` at the root of this repository +containing the following: ``` python from snake.player import Player, Direction @@ -90,3 +101,81 @@ if __name__ == '__main__': ``` and it should work. + +## About map + +[Map](https://gitea.tforgione.fr/tforgione/pytron/src/branch/master/tron/map.py#L10) +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 + +``` python3 +my_map = Map(5, 5, Case.EMPTY, Case.WALL) +``` + +it really creates a 7x7 `np.array`, in which the interior is filled with +`Case.EMPTY` and the border with `Case.WALL`. + +### Playing with maps + +If you want to modify the map, you can do so by using the getters. **Be +careful, the getter don'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: + +``` python3 +my_map = Map(5, 5, Case.EMPTY, Case.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] = Case.PLAYER_ONE_HEAD +``` + +You can easily clone a map: +``` python3 +my_map = Map(5, 5, Case.EMPTY, Case.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: +``` python3 +def my_function(x): + return x + 1 + +my_map = Map(5, 5, Case.EMPTY, Case.WALL) +my_map.apply(my_function) +``` + +### 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: + +``` python3 +my_map = Map(5, 5, Case.EMPTY, Case.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: + +``` python3 +my_map = Map(5, 5, Case.EMPTY, Case.WALL) +my_array = my_map.clone_array() +# Modifying my_array won't modify my_map +my_array[0][0] = ... +``` diff --git a/tron/map.py b/tron/map.py index 201e13a..79388c5 100644 --- a/tron/map.py +++ b/tron/map.py @@ -34,7 +34,7 @@ class Map: clone._data = np.copy(self._data) return clone - def convert(self, converter): + def apply(self, converter): """ Converts a map by applying a function to each element. """ @@ -48,6 +48,12 @@ class Map: """ return self._data + def clone_array(self): + """ + Returns a copy of the inner array of the map. + """ + return np.array([[converter(self._data[i][j]) for i in range(self.height + 2)] for j in range(self.width + 2)]) + def __getitem__(self, index): (i, j) = index return self._data[i+1][j+1]