pytron/README.md
2019-03-13 21:01:54 +01:00

4.8 KiB

Pytron

This program is a simple python game, made for implementing your own AIs.

Table of contents

How to download the game

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:

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:

    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:

    sudo apt install python3-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.

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.

For example, you can create a file myplayer.py at the root of this repository containing the following:

from snake.player import Player, Direction

class MyPlayer(Player):
    def __init__(self):
        super(MyPlayer, self).__init__()

    def action(self, game_map):
        # Do stuff
        return Direction.DOWN

and you can create an executable file containing the following:

#!/usr/bin/env python3

import contextlib
with contextlib.redirect_stdout(None):
    import pygame

from snake.map import Map
from snake.game import Game, PositionPlayer
from snake.window import Window
from snake.player import Player, Direction, ConstantPlayer, KeyboardPlayer

def main():
    pygame.init()

    width = 40
    height = 40

    game = Game(width, height, [
        PositionPlayer(1, KeyboardPlayer(Direction.RIGHT), [0, 0]),
        PositionPlayer(2, ConstantPlayer(Direction.LEFT), [width - 1, height - 1]),
    ])

    window = Window(game, 20)

    game.main_loop(window)

if __name__ == '__main__':
    main()

and it should work.

About map

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, 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:

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:

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:

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:

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:

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] = ...