Skip to content

Instantly share code, notes, and snippets.

@louisswarren

louisswarren/Makefile

Last active Mar 4, 2021
Embed
What would you like to do?
Cellular automata
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()
.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
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