Competitive multiplayer game of life
- Create a new repository from the template.
conda create -n <NAME> -c conda-forge python=3.10.*
conda activate <NAME>
git clone https://github.com/nvaytet/cholerama
git clone https://github.com/<USERNAME>/<MYBOTNAME>_bot.git
cd cholerama/
python -m pip install -e .
cd run/
ln -s ../../<MYBOTNAME>_bot .
python play.py
Conquer the largest surface on the board
- Bacterial evolution is governed by Conway’s Game of Life
- Begin on a small patch of board (256x256) with 100 cells
- Run 4000 iterations
- Winner is the one with most alive cells at the end
- Any live cell with fewer than two live neighbors dies (underpopulation)
- Any live cell with two or three live neighbors lives
- Any live cell with more than three live neighbors dies (overpopulation)
- Any dead cell with exactly three live neighbors spontaneously comes to life
- Multiplayer: the cell that comes to life takes the value of most common neighbor
- You start the game with 100 tokens
- 1 token = 1 cell
- Populate your 256x256 patch as you wish
- You get to keep the extra tokens
- Every iteration, you are free to place any number of tokens on an empty space inside your patch (you must still be alive)
- Every 20 iterations, you receive an additional token (if you are still alive)
- This equates to 200 additional tokens during a round
- Points given at the end of a round are the number of alive cells a player still has
- Bonus prize for peak board coverage reached over the course of the tournament
- Run 8 rounds and sum the scores
- Pick a name
- Pick a color (optional)
- Create a pattern with your 100 tokens: a list of (x, y) positions or a path to an image (white = 0, black = 1)
- An image smaller than 256x256 will anchor at the lower left corner of the patch
- Starting patches are randomized
import numpy as np
from cholerama import helpers, Positions
AUTHOR = "YeastieBoys" # This is your team name
class Bot:
def __init__(
self,
number: int,
name: str,
patch_location: Tuple[int, int],
patch_size: Tuple[int, int],
):
self.number = number # Mandatory: this is your number on the board
self.name = name # Mandatory: player name
self.color = None # Optional
self.rng = np.random.default_rng(SEED)
# If we make the pattern too sparse, it just dies quickly
xy = self.rng.integers(0, 12, size=(2, 100))
self.pattern = Positions(
x=xy[1] + patch_size[1] // 2, y=xy[0] + patch_size[0] // 2
)
# The pattern can also be just an image (0=white, 1=black)
# self.pattern = "mypattern.png"
- Iteration number (int)
- Current board and your own patch: numpy arrays with integer values. 0 means empty, other values correspond to players (
self.number
) - How many tokens you have at your disposal
- You can return a set of (x, y) positions corresponding to new alive cells to be placed on the board (integers)
- 1 cell costs 1 token
- The locations for new cells on the board must be empty and inside your patch (overflows will wrap around)
- The total number of additional tokens you'll receive during a round is 200
class Bot:
...
def iterate(self, iteration: int, board: np.ndarray, patch: np.ndarray, tokens: int):
if tokens >= 5:
# Pick a random empty region of size 3x3 inside my patch
empty_regions = helpers.find_empty_regions(patch, (3, 3))
nregions = len(empty_regions)
if nregions == 0:
return None
# Make a glider
ind = self.rng.integers(0, nregions)
x = np.array([1, 2, 0, 1, 2]) + empty_regions[ind, 1]
y = np.array([2, 1, 0, 0, 0]) + empty_regions[ind, 0]
return Positions(x=x, y=y)
- This is more about exploring the world of the Game of Life, rather than hardcore programming for 4 hours
- Spend time reading up about gliders, spaceships, guns, puffers, eaters, spacefillers...
- Change the
fps
(exceeding 30 is difficult) - Run in
headless
mode start multiple runs simultaneously - Use the provided Jupyter notebook