Initial commit
This commit is contained in:
commit
529ef7b6a8
|
@ -0,0 +1 @@
|
|||
book
|
|
@ -0,0 +1,5 @@
|
|||
[book]
|
||||
authors = ["Thomas Forgione"]
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "Pytron"
|
|
@ -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
|
|
@ -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)
|
||||
```
|
|
@ -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
|
||||
```
|
|
@ -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)
|
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
|
@ -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.
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
# Writing an AI
|
Loading…
Reference in New Issue