Last active
November 30, 2021 04:16
-
-
Save louisswarren/aaec24795b9463957d01508632f6fb66 to your computer and use it in GitHub Desktop.
Cellular automata
This file contains hidden or 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
from collections import defaultdict | |
import sys | |
from svg import * | |
def log(*a, **k): | |
print(*a, **k, file=sys.stderr) | |
ROWS = 16 | |
STOP_AFTER = ROWS | |
COLS = ROWS*2-1 | |
BOXSIZE = 16 | |
HEADER_HEIGHT = BOXSIZE * ROWS * (3/4) | |
NOM_WIDTH = COLS * BOXSIZE + 1 + 20 | |
NOM_HEIGHT = NOM_WIDTH // 2 ** 0.5 | |
NOM_YBIAS = NOM_HEIGHT - (ROWS * BOXSIZE + 10) | |
IMG_HEIGHT = 1024 | |
IMG_WIDTH = IMG_HEIGHT / NOM_HEIGHT * NOM_WIDTH | |
RULE_GAP = 2 | |
RULE_MGAP = 3 | |
RULE_MARGIN = 2 | |
if len(sys.argv) > 1: | |
rule = int(sys.argv[1]) | |
else: | |
rule = 30 | |
# Basic header | |
svg_header() | |
svg_open(width=IMG_WIDTH, height=IMG_HEIGHT, | |
x_bias=-(NOM_WIDTH-1)/2-1, y_bias=-NOM_YBIAS+12, | |
xw=NOM_WIDTH+1, yh=NOM_HEIGHT+1) | |
def draw_box(x, y, value=None, scale=1): | |
svg_rect((x*scale, y*scale), scale*BOXSIZE, scale*BOXSIZE, | |
fill="black" if value else "white", | |
stroke="grey", stroke_width=scale) | |
def draw_cell(row, col, value=None, scale=1): | |
draw_box(BOXSIZE*(col-0.5), BOXSIZE*row, | |
value=value, scale=scale) | |
#def draw_rule(x, y, n): | |
# scale = COLS / (4*3 + 3*RULE_GAP + 2*RULE_MARGIN) | |
# draw_box((x - 1.5)*BOXSIZE, y * BOXSIZE , n & 4 != 0 , scale) | |
# draw_box((x - 0.5)*BOXSIZE, y * BOXSIZE , n & 2 != 0 , scale) | |
# draw_box((x + 0.5)*BOXSIZE, y * BOXSIZE , n & 1 != 0 , scale) | |
# draw_box((x - 0.5)*BOXSIZE, (y + 1) * BOXSIZE, rule & (1 << n) != 0, scale) | |
# | |
#draw_rule(-(3 + RULE_MGAP)/2 - 3 - RULE_GAP, -7, 7) | |
#draw_rule(-(3 + RULE_MGAP)/2 , -7, 6) | |
#draw_rule( (3 + RULE_MGAP)/2 , -7, 5) | |
#draw_rule( (3 + RULE_MGAP)/2 + 3 + RULE_GAP, -7, 4) | |
#draw_rule(-(3 + RULE_MGAP)/2 - 3 - RULE_GAP, -3, 3) | |
#draw_rule(-(3 + RULE_MGAP)/2 , -3, 2) | |
#draw_rule( (3 + RULE_MGAP)/2 , -3, 1) | |
#draw_rule( (3 + RULE_MGAP)/2 + 3 + RULE_GAP, -3, 0) | |
def draw_rule(row, col, n): | |
draw_cell(row, col - 1, n & 4 != 0) | |
draw_cell(row, col, n & 2 != 0) | |
draw_cell(row, col + 1, n & 1 != 0) | |
draw_cell(row + 1, col, rule & (1 << n) != 0) | |
draw_rule(-4, -14, 7) | |
draw_rule(-4, -10, 6) | |
draw_rule(-4, -6, 5) | |
draw_rule(-4, -2, 4) | |
draw_rule(-4, 2, 3) | |
draw_rule(-4, 6, 2) | |
draw_rule(-4, 10, 1) | |
draw_rule(-4, 14, 0) | |
cells = defaultdict(lambda: False) | |
cells[(0,0)] = True | |
draw_cell(0, 0, cells[(0,0)]) | |
for j in range(1, ROWS): | |
if j >= STOP_AFTER: | |
for i in range(-j, j+1): | |
draw_cell(j, i, False) | |
continue | |
for i in range(-j, j+1): | |
prev = 4 * cells[(j-1, i-1)] | |
prev += 2 * cells[(j-1, i )] | |
prev += 1 * cells[(j-1, i+1)] | |
cells[(j,i)] = rule & (1 << prev) != 0 | |
draw_cell(j, i, cells[(j,i)]) | |
# Footer | |
svg_close() |
This file contains hidden or 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
.PHONY: test | |
test: 027.png | |
.PHONY: all | |
all: | |
$(MAKE) -j 4 $$(for i in $$(seq -w 0 255); do echo -n "$$i.png "; done) | |
%.png: %.svg | |
convert $^ $@ | |
%.svg: cell.py svg.py | |
python3 $< $* > $@ | |
.PHONY: clean | |
clean: | |
rm -f *.png *.svg *.mp4 |
This file contains hidden or 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
def xml(tag, _xml_tag_is_a_singleton=True, **options): | |
s = f'<{tag}' | |
kw_attrib = lambda x: x.replace('_', '-') | |
if options: | |
s += ' ' | |
s += ' '.join(f'{kw_attrib(k)}="{str(v)}"' for k, v in options.items()) | |
if _xml_tag_is_a_singleton: | |
s += ' />' | |
else: | |
s += '>' | |
print(s) | |
def xml_open(*args, **kwargs): | |
xml(*args, **kwargs, _xml_tag_is_a_singleton=False) | |
def xml_close(tag): | |
print(f'</{tag}>') | |
def svg_header(): | |
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>' | |
def svg_open(width, height, x_bias, y_bias, xw, yh): | |
vb = f'{x_bias} {y_bias} {xw} {yh}' | |
ns = 'http://www.w3.org/2000/svg' | |
xml_open('svg', width=width, height=height, viewBox=vb, xmlns=ns) | |
def svg_close(): | |
xml_close('svg') | |
def svg_poly(*points, **opts): | |
point_str = ' '.join(f'{x},{y}' for x, y in points) | |
xml('polyline', points=point_str, **opts) | |
def svg_circle(point, radius, **opts): | |
xml('circle', cx=point[0], cy=point[1], r=radius, **opts) | |
def svg_line(p1, p2, **opts): | |
xml('line', x1=p1[0], y1=p1[1], x2=p2[0], y2=p2[1], **opts) | |
def svg_rect(p, width, height, x_radius=0, y_radius=0, **opts): | |
xml('rect', x=p[0], y=p[1], width=width, height=height, | |
rx=x_radius, ry=y_radius, **opts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment