Initial commit

This commit is contained in:
Thomas Forgione 2019-05-22 10:59:27 +02:00
commit 529ef7b6a8
No known key found for this signature in database
GPG Key ID: 203DAEA747F48F41
11 changed files with 318 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
book

5
book.toml Normal file
View File

@ -0,0 +1,5 @@
[book]
authors = ["Thomas Forgione"]
multilingual = false
src = "src"
title = "Pytron"

51
src/Game.md Normal file
View File

@ -0,0 +1,51 @@
# The Game module
The `Game` class is probably the most important class in this architecture,
since it is the class you will get as a parameter in your AI. Your AI will need
to analyse the game in order to take a decision that will make it win.
It contains the size of the game, the [Map](/wiki/Map)s of each step of the
game, the players, and can run.
Before detailling the content of the `Game` class, we first need to describe
some other classes in the same module.
## The `PositionPlayer` class
*Yes, this is a really poor name, but I had no imagination for that one...*
Basically, this class contains the things that the game needs to know about the
player:
- the `player` attribute is the one corresponding to the player described in
the [player section](/wiki/Player) (which serves the purpose of the AI)
- the `position` attribute is the current position of the player
- the `id` is a number (between 1 and 2) that allows the game to know which
player we are talking about
- the `alive` attribute is a boolean which allows the game to know if the
player is still alive so it can know if the game ended and which player
has won
It also contains two methods, `head` and `body` which returns the tile the
corresponding to the head or the body of the given player.
## The `HistoryElement` class
This class desribes the elements you will find in the game history. It contains
the directions that were given by the players, and the state of the map after
the turn.
## And finally, the `Game` class
This class contains:
- the width and height of the game, which are integers
- the history of the states of the game, which is an array of
`HistoryElement`s that we described in the previous section
- the `PositionPlayer`s of the game (in the `pps` attribute), which is an
array of `PositionPlayer` described previously
- the `winner` which is initialized to `None`, at the begining of the game,
but will be 1 or 2 if player 1 or 2 won the game
It also contains a few methods:
- `map`, which returns the current map of the game
- `next_frame` which advances one step in the game and updates the history
- `main_loop`, that runs the game until it's finished

121
src/Map.md Normal file
View File

@ -0,0 +1,121 @@
# 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)
```

43
src/Player.md Normal file
View File

@ -0,0 +1,43 @@
# The `Player` class
The only thing the `player` module contains is the `Player` class.
Your AI will basically be a class that will extend the `Player` class.
Since your AI is not interactive, the only method you have to implement is the
`action` method. This method takes as parameters `self`, of course, and also:
- `map`, which is the current map of the game
- `id` which is the id of your player (because the map refers to player 1 and
2 but you don't know if you're player one or two)
You can refer to the [game page of the wiki](/wiki/Game) to have more
information about this class.
This function will return a `Direction`. It is a python enum that you can use
directly, like in
```python
return Direction.UP
```
or with an integer, like in
```python
i = 2
return Direction(i) # returns Direction.RIGHT
```
Your class may then look like this:
``` python
class MyMonsterAI(Player):
def __init__(self):
super(MyMonsterAI, self).__init__()
def action(self, map, id):
# Analyse the map
# Do many computations
# Make a sacrifice to the gods of tron
# Return a direction
return Direction.UP
```

7
src/SUMMARY.md Normal file
View File

@ -0,0 +1,7 @@
# Summary
[Pytron](./intro.md)
- [Getting started](./getting-started.md)
- [Writing an AI](./writing-an-ai.md)
- [Uploading your AI on pytron-web](./pytron-web.md)

BIN
src/assets/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

38
src/getting-started.md Normal file
View File

@ -0,0 +1,38 @@
# How to download the game
The first step is to clone the repository:
``` sh
git clone https://gitea.tforgione.fr/tforgione/pytron
```
Then, ensure you have `python` and `pygame` installed. You can test you have
everything by executing the following command:
```
python -c "import pygame"
```
- if you get a `python: command not found`, it means you don't have
`python`, you can install it on ubuntu like so:
``` sh
sudo apt install python
```
- 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 python-pip
sudo pip3 install pygame
```
# How to play the game
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.

6
src/intro.md Normal file
View File

@ -0,0 +1,6 @@
# Welcome to Pytron's wiki
This program is a simple python game, made for implementing your own AIs.
![Screenshot of the game](/assets/screenshot.png)

45
src/pytron-web.md Normal file
View File

@ -0,0 +1,45 @@
# About Pytron-web
[Pytron-web](http://pytron.tforgione.fr) is a website where you can upload your
AI and see it compete with other AIs from other people.
On the index of the site, you can see the leaderboard, as well as the results
of all battles.
Note that this website is hosted on an N7 server, so you won't be able to
access it if you're not on the N7 local network (you can still use it through
the VPN).
### Battle system
All the possible battles are done: each AI will have to battle each other AI.
For each pair of AIs, 100 battles will be launched, on a predetermined,
symmetric set of initial positions.
The size of the map for this is 10x10, so you need to make sure that your AI
will work with those sizes.
### How to upload your AI
There are two ways to upload your AI:
##### [On the website](https://pytron.tforgione.fr/upload/)
You will have to enter the name of your AI and upload a ZIP archive of your AI.
This archive must contain a file named `ai.py` which must contain a class `Ai`
which must have a constructor that takes no arguments. It may also contain some
other files, that will be placed next to the `ai.py` file on the server.
##### With the upload script
In the `pytron` repository, there is a script named `upload` which will allow
you to upload your AI.
It assumes that your AIs are stored in the `ais` directory, at the root of the
repository. Each AI must be in its own directory, and must contain a file named
`ai.py` which must contain a class `Ai` which must have a constructor that
takes no arguments.
This script is interactive, you can launch it by typing
``` bash
./upload
```
and it will look for AIs. If it doesn't find any AI, it will print an error
message, and if it finds many, it will ask you which one you want to upload.
It will then process to create the archive and upload it to the server itself.

1
src/writing-an-ai.md Normal file
View File

@ -0,0 +1 @@
# Writing an AI