-
Docker
-
Python >= 3.6
-
Python package tornado
pip install tornado
The game server can be run simply by running a Docker container
docker run -it --rm -p 8080:8080 nimatt/evg
After running this command you should have the game server running on your machine and the console showing
Now listening on: http://[::]:8080
Application started. Press Ctrl+C to shut down.
To view game in a browser, go to http://localhost:8080.
Note: the --rm
is so that the container instance is removed when it stops.
Each game is between two players. Each players moving its units, one unit at a time.
Each unit gets one opportunety to perform actions per turn. The order of the units are determined by their location on the playing field. They are ordered top to bottom, left to right.
With a scenario where units are placed like
------A---
----------
---B----C-
------D---
The units will move in the order A, B, C, D
A unit have two types of actions it can perform move and attack. Each turn it may perform these two actions once. Both actions are performed in a direction (up, down, left or right). A unit moves one step in the given direction, or performs an attack on the adjacent space in that direction.
Note: An attack will damage any unit occupying that space, friend or foe.
A unit is considered dead when its health reaches 0. The space it occupies is then considered empty.
The game is played by developing the logic controlling the units. This is done in the file player.py
. The file contains a function called get_actions
which should return an array of the actions the unit should perform.
So to only move up the function should return
[ Action('move', 'up') ]
To move right and the attack down
[ Action('move', 'right'), Action('attack', 'down') ]
It is also possible to attack first and then move
[ Action('attack', 'up'), Action('move', 'left') ]
To help you decide on what actions to perform, the get_actions
function is given the current game state with the following properties.
- empty_map
- Two dimensional list containing indication if a coordinate is empty or occupied (0,0 indicates the top left corner)
- floor_map
- Two dimensional list containing indication if a coordinate contains floor or wall (0,0 indicates the top left corner)
- unit
- Information regarding the unit that the function should return actions for
- units
- All units controlled by the player (including current and dead units)
- foes
- All units controlled by the advesary (including dead units)
In all maps and positions the origo is in the top left corner. X then increases to the right and Y downwards.
-----------------------
| X:0 | X:1 | X:2 | ...
| Y:0 | Y:0 | Y:0 | ...
-----------------
| X:0 | X:1 | ...
| Y:1 | Y:1 | ...
-----------
| X:0 | ...
| Y:2 | ...
-----------
| ...
| ...
There exist a few functions designed to make the task of developing the unit control logic a bit easier. These functions can be used freely and in any way you see that can benefit.
NOTE: Checking the distance to an occupied square will return None
since there is no path that makes it possible for the unit to move to the square.
There is no need to perform any special action to use the new version of the player.py
. Just save the file and any changes will be automatically picked up and used.
To set a great new team name, just update name
in the get_player_info
function and save the file.
A game ends when only one player has units left, or enough rounds have passed. If the game is ended due to sufficient amount of rounds, the player of which the sum of the units health is the highest. If the players units have exactly the same amount of health left, it is considered a draw and no points are awarded. At the end of each game, game_end
is called.
To start a game, you need at least two players registered. To achieve that without having two Python processes it is possible to just register more players using the same address. The easiest way to do this is to run .\registerPlayers.ps1
in PowerShell. This will register 4 players that are controlled by the player on address http://10.0.75.1:9080 which should be your single Python process, if you have not changed any ports and if you have standard settings on Docker.
It is of course possible to attach a debugger to the player code. However, if a breakpoint is hit during action evaluation and actions are not returned within 1 second. The unit will not perform any actions and the turn will pass on to the next unit.