gists/lsca/lsca.uni.py
2019-03-11 06:09:07 +01:00

84 lines
1.7 KiB
Python

#!/usr/bin/env python3
import sys
import numpy as np
def lament(*args, **kwargs):
return print(*args, file=sys.stderr, **kwargs)
def colorize(x):
return x * 17 % 256
def render(row, scale):
grays = colorize(row)
if scale > 1:
grays = np.repeat(grays, scale)
line = " ".join(str(x) for x in grays)
for y in range(scale):
print(line)
def limit(row): # in-place
row[row < 0] = 0
row[row > 15] = 15
return row
def initialize(width):
row = np.zeros(width, int)
value = 0
for i in range(width):
if np.random.randint(8) == 0: # only change values occasionally
value = np.random.randint(16)
row[i] = value
limit(row)
return row
name, args = sys.argv[0], sys.argv[1:]
if len(args) == 0:
rule_lut = None
elif len(args) == 16:
rule_lut = [int(x.strip(",")) for x in args]
else:
lament(f"usage: {name}")
lament(f"usage: {name} {{rules 1 through 16}}")
sys.exit(1)
scale = 3
width, height = 960 // scale, 960 // scale
if rule_lut is None:
rule_lut = np.random.randint(-2, 2 + 1, size=(4, 4))
lament(" ".join(f"{x:+2}" for x in rule_lut.flat))
else:
rule_lut = np.array(rule_lut).reshape(4, 4)
print("P2") # magic code for an ascii Portable GrayMap (PGM) file
print(width * scale, height * scale)
print(255) # maximum color value
row = initialize(width)
for i in range(height):
# left, center, right:
L = np.roll(row, 1)
C = row.copy()
R = np.roll(row, -1)
diffusion = (L + C + C + R + 2) // 4
# v = [0,1,2,3,1,0,3,2,2,3,0,1,3,2,1,0][V]
y = (L ^ (L >> 2)) % 4
x = (R ^ (R >> 2)) % 4
delta = rule_lut[y, x]
row = diffusion + delta
limit(row)
render(row, scale)