Skip to content

Instantly share code, notes, and snippets.

@lukmdo
Created November 22, 2013 18:26
Show Gist options
  • Save lukmdo/7604592 to your computer and use it in GitHub Desktop.
Save lukmdo/7604592 to your computer and use it in GitHub Desktop.
coderetreat

Run

python golgame.py
Ctrl + C to stop

There are some options too:

Usage: golgame.py [options]

Options:
  -h, --help            show this help message and exit
  -s CELL_SYMBOL, --symbol=CELL_SYMBOL
                        ASCI symbol for cell representation
  -r FRAME_RATE, --rate=FRAME_RATE
                        Interval between frames
  -n N_CELLS, --init-cells-number=N_CELLS
                        Number of cells to start the game

For more visit https://github.com/coreyhaines/coderetreat repository.

Links:

from collections import defaultdict
from time import sleep
from itertools import product
import curses
import random
class Cell(object):
def __init__(self, x, y):
self._x, self._y = x, y
@property
def position(self):
return (self._x, self._y)
def __gt__(self, other):
x1, y1 = self.position
x2, y2 = other.position
return (x1 > x2) and (y1 > y2)
def __lt__(self, other):
x1, y1 = self.position
x2, y2 = other.position
return x1 < x2 or y1 < y2
def __hash__(self):
return hash(self.position)
def __eq__(self, other):
return self.position == other.position
def __repr__(self):
return "Cell" + str(self.position)
class GameBoard(object):
def __init__(self, *cells):
self._cells = set(cells)
def __str__(self):
cells = self.cells
pos_map = dict([[c.position, c] for c in cells])
out = ""
for y in range(self.size, 0, -1):
out += "\n"
for x in range(self.size):
out += '*' if (x, y) in pos_map else ' '
return out
@property
def cells(self):
return self._cells
@cells.setter
def cells(self, items):
self._cells = set(items)
def _play(self, size=None):
self.size = size
while True:
yield self.get_next_tick()
def _get_neighbours_all(self, cell):
x, y = cell.position
positions = set(product(range(x - 1, x + 2), range(y - 1, y + 2))) - \
set([(x, y)])
return [Cell(x, y) for x, y in positions]
def get_next_tick(self):
living_cell_neighbors = defaultdict(list)
dead_cell_neighbors = defaultdict(list)
for living_cell in self.cells:
for cell in self._get_neighbours_all(living_cell):
if cell in self.cells:
living_cell_neighbors[living_cell].append(cell)
else:
dead_cell_neighbors[cell].append(living_cell)
next_tick_cells = [lcell for lcell in living_cell_neighbors if
len(living_cell_neighbors[lcell]) in (2, 3)]
next_tick_cells.extend([dcell for dcell in dead_cell_neighbors if
len(dead_cell_neighbors[dcell]) == 3])
self.cells = next_tick_cells
return self
def __eq__(self, other):
return self.cells == other.cells
def __repr__(self):
return "GameBoard" + str(tuple(self.cells))
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return type is None
class GameBoardNG(GameBoard):
def __init__(self, cells=[], width=None, height=None, n_cells=None):
self.width = width
self.height = height
self.n_cells = n_cells
super(GameBoardNG, self).__init__(*cells)
@property
def cells(self):
return self._cells
@cells.setter
def cells(self, items):
if not items and self.n_cells:
opt = xrange(1, self.n_cells + 1)
items = [Cell(x, y) for x, y in zip(
[x % self.width for x in random.sample(opt, self.n_cells)],
[y % self.height for y in random.sample(opt, self.n_cells)])]
self._cells = set(items)
class GameBoardCurses(GameBoardNG):
def __init__(self, cells=[], cell_symbol=None, frame_rate=None,
n_cells=None):
self.cell_symbol = cell_symbol
self.frame_rate = frame_rate
self.screen = curses.initscr()
width, height = self.screen.getmaxyx()
width, height = width - 1, height - 1 # include borders
super(GameBoardCurses, self).__init__(*cells,
width=width,
height=height,
n_cells=n_cells)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
if not type:
return True
if type is KeyboardInterrupt:
curses.endwin()
return True
return False
def play(self):
min_cell = Cell(0, 0)
max_cell = Cell(self.width, self.height)
for gb in self._play():
sleep(self.frame_rate)
self.screen.clear()
self.screen.border(0)
for cell in gb.cells:
if cell > min_cell and max_cell > cell:
x, y = cell.position
self.screen.addstr(x, y, self.cell_symbol)
self.screen.refresh()
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser(usage="usage: %prog [options]")
parser.add_option("-s", "--symbol", dest="cell_symbol",
default="X", type="string",
help="ASCI symbol for cell representation")
parser.add_option("-r", "--rate", dest="frame_rate",
default=0.2, type="float",
help="Interval between frames")
parser.add_option("-n", "--init-cells-number", dest="n_cells",
default=700, type="int",
help="Number of cells to start the game")
(options, args) = parser.parse_args()
with GameBoardCurses(cell_symbol=options.cell_symbol,
n_cells=options.n_cells,
frame_rate=options.frame_rate) as game:
game.play()
import unittest
from golgame import Cell
from golgame import GameBoard
class GolCreatures(object):
BLOCK = (Cell(2, 2), Cell(3, 2), Cell(2, 3), Cell(3, 3))
BLINKER = (Cell(2, 3), Cell(3, 3), Cell(4, 3))
BEEHIVE = (Cell(3, 2), Cell(4, 2), Cell(2, 3), Cell(5, 3), Cell(3, 4),
Cell(4, 4))
class TestGameBoard(unittest.TestCase):
def setUp(self):
self.empty_gb = GameBoard()
def test_get_cells(self):
c1 = Cell(10, 20)
c2 = Cell(1, 2)
gb = GameBoard(c1, c2)
self.assertItemsEqual(gb.cells, (c1, c2))
def test_get_next_tick(self):
gb = GameBoard()
self.assertEqual(gb.get_next_tick(), self.empty_gb,
"Expected Blank GameBoard")
gb = GameBoard(Cell(10, 10))
self.assertEqual(gb.get_next_tick(), self.empty_gb, "Alone")
gb = GameBoard(*GolCreatures.BLOCK)
self.assertEqual(gb.get_next_tick(), gb, "Block")
gb = GameBoard(*GolCreatures.BEEHIVE)
self.assertEqual(gb.get_next_tick(), gb, "Beehive")
gb = GameBoard(*GolCreatures.BLINKER)
self.assertEqual(gb.get_next_tick(), GameBoard(Cell(3, 2), Cell(3, 3),
Cell(3, 4)), "Blinker")
if __name__ == "__main__":
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment