This repository has been archived by the owner on Dec 16, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
60f391b
commit 6453fa2
Showing
2 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
(import grid) | ||
(import-from functools reduce) | ||
(import-from operator add) | ||
|
||
|
||
(def *world* (grid.Torus 10 10)) | ||
|
||
|
||
(defun sum (ns) | ||
(reduce add ns)) | ||
|
||
|
||
(defun set! (world x y value) | ||
(setv (get world (, x y)) value)) | ||
|
||
|
||
(defun get! (world x y) | ||
(get *world* (, x y))) | ||
|
||
|
||
(defun neighbours (world x y) | ||
(sum (list-comp | ||
(get! world (+ x dx) (+ y dy)) | ||
(dx [-1 0 1] | ||
dy [-1 0 1]) | ||
(!= (, (+ x dx) (+ y dy)) (, x y))))) | ||
|
||
|
||
(defun step (world) | ||
(let ((new-world (.copy grid.Torus world))) | ||
(for (x (range new-world.width)) | ||
(for (y (range new-world.height)) | ||
(let ((cell (get! new-world x y)) | ||
(ns (neighbours world x y))) | ||
(if (= cell 1) | ||
(cond ((< ns 2) (set! new-world x y 0)) | ||
((or (= ns 2) (= ns 3)) (set! new-world x y 1)) | ||
((> ns 3) (set! new-world x y 0))) | ||
(cond ((= ns 3) (set! new-world x y 1)) | ||
(True (set! new-world x y 0))))))) | ||
new-world)) | ||
|
||
|
||
|
||
;; Create a glider... | ||
(set! *world* 4 2 1) | ||
(set! *world* 5 3 1) | ||
(set! *world* 3 4 1) | ||
(set! *world* 4 4 1) | ||
(set! *world* 5 4 1) | ||
|
||
;; Cycle through once... | ||
(for (_ (range 5)) | ||
(.pprint grid.Torus *world*) | ||
(setv *world* (step *world*)) | ||
(print)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
from collections import Mapping | ||
from copy import deepcopy | ||
|
||
|
||
class Grid(Mapping): | ||
""" | ||
A Grid is a two-dimensional data-structure. | ||
>>> g = Grid(5, 5) | ||
>>> Grid.pprint(g) | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
>>> g[0, 0] = 1 | ||
>>> g[4, 4] = 1 | ||
>>> Grid.pprint(g) | ||
1 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 0 | ||
0 0 0 0 1 | ||
The height and width of the grid are inclusive while the indexing | ||
begins at zero. Access to elements of the grid are provided via | ||
the Mapping interface. Internally the elements are stored in a | ||
flat array and can be any Python object. The default element is | ||
the integer 0, but can be specified via the 'value' parameter to | ||
the Grid's constructor: | ||
>>> g = Grid(3, 3, value=".") | ||
>>> Grid.pprint(g) | ||
. . . | ||
. . . | ||
. . . | ||
There are helpful static methods available for copying grids, | ||
creating grids from arrays, and pretty printing grids. | ||
>>> w = h = 3 | ||
>>> world = [0, 0, 0, | ||
... 1, 0, 1, | ||
... 0, 1, 0] | ||
>>> g = Grid.from_array(w, h, world) | ||
>>> Grid.pprint(g) | ||
0 0 0 | ||
1 0 1 | ||
0 1 0 | ||
Care must be taken when creating Grids from arrays to ensure that | ||
the proper dimensions are passed in. The only assertion this | ||
method makes is that the product of the width and height are the | ||
same as the length of the input array. | ||
Grids can be compared for equality: | ||
>>> g1 = Grid(3, 3) | ||
>>> g2 = Grid(3, 3) | ||
>>> g1[0, 0] = 1 | ||
>>> g2[0, 0] = 1 | ||
>>> g3 = Grid(3, 3) | ||
>>> g1 == g2 | ||
True | ||
>>> g1 == g3 | ||
False | ||
""" | ||
|
||
def __init__(self, width, height, value=0): | ||
self.width = width | ||
self.height = height | ||
self._grid = [value for _ in range(width * height)] | ||
|
||
@classmethod | ||
def copy(cls, other): | ||
g = cls(other.width, other.height) | ||
g._grid = deepcopy(other._grid) | ||
return g | ||
|
||
@classmethod | ||
def from_array(cls, width, height, arr, copy=True): | ||
assert len(arr) == width * height, ("Array dimensions do not " | ||
"match length of array.") | ||
g = cls(width, height) | ||
a = deepcopy(arr) if copy else arr | ||
g._grid = a | ||
return g | ||
|
||
@staticmethod | ||
def pprint(grid): | ||
for y in range(grid.height): | ||
print(" ".join(str(grid[x, y]) for | ||
x in range(grid.width))) | ||
|
||
def _is_valid_location(self, x, y): | ||
if x < 0 or x > self.width - 1: | ||
return False | ||
if y < 0 or y > self.height - 1: | ||
return False | ||
return True | ||
|
||
def __len__(self): | ||
return self.width * self.height | ||
|
||
def __eq__(self, other): | ||
assert isinstance(other, Grid) | ||
return self._grid == other._grid | ||
|
||
def __iter__(self): | ||
return iter(self._grid) | ||
|
||
def __contains__(self, value): | ||
return value in self._grid | ||
|
||
def __getitem__(self, *args): | ||
if not self._is_valid_location(*args[0]): | ||
raise KeyError("({0}, {1}) is an invalid co-ordinate".format( | ||
*args[0])) | ||
try: | ||
return self._grid[args[0][1] * self.height + args[0][0]] | ||
except IndexError: | ||
raise KeyError("({0}, {1}) is an invalid co-ordinate".format( | ||
*args[0])) | ||
|
||
def __setitem__(self, *args): | ||
if not self._is_valid_location(*args[0]): | ||
raise KeyError("({0}, {1}) is an invalid co-ordinate".format( | ||
*args[0])) | ||
try: | ||
self._grid[args[0][1] * self.height + args[0][0]] = args[1] | ||
except IndexError: | ||
raise KeyError("({0}, {1}) is an invalid co-ordinate".format( | ||
*args[0])) | ||
|
||
|
||
class Torus(Grid): | ||
""" | ||
A grid whose edges are connected. | ||
>>> w = h = 3 | ||
>>> world = [0, 1, 0, | ||
... 0, 0, 0, | ||
... 0, 2, 0] | ||
>>> t = Torus.from_array(w, h, world) | ||
>>> Torus.pprint(t) | ||
0 1 0 | ||
0 0 0 | ||
0 2 0 | ||
>>> t[1, 0] | ||
1 | ||
>>> t[1, -1] | ||
2 | ||
>>> t[4, 0] | ||
1 | ||
""" | ||
|
||
def __getitem__(self, *args): | ||
x = args[0][0] % self.width | ||
y = args[0][1] % self.height | ||
|
||
return self._grid[y * self.height + x] | ||
|
||
def __setitem__(self, *args): | ||
x = args[0][0] % self.width | ||
y = args[0][1] % self.height | ||
|
||
self._grid[y * self.height + x] = args[1] | ||
|
||
|
||
if __name__ == "__main__": | ||
import doctest | ||
doctest.testmod() |