#!/usr/bin/python3 """Generate arbitrary complete Wang tile sets, and tile with them. Specifically, I was thinking about the kinds of patterns that can be generated with simple complete Wang tile sets without backtracking. (You don’t need backtracking if your tileset is complete!) It occurred to me that you should be able to generate a Sierpinski triangle under the following rules: - We start with edge color 0 on the left and top edges of the area we’re tiling; we only attempt to place tiles down and to the right. - Right and bottom edges are always the same color. - That color is 1 if the left and top edges are the same, 0 if they are different. It turns out that with a single bit of edge color and the first two rules, that’s the only interesting pattern you can get; the other 16 patterns are all simpler. But what if the right and bottom edges can be different? Then you have 256 possible rules. It turns out that some of these are more interesting; in addition to variously oriented Sierpinskis in rules 45, 54, 99, 105, 135, 150, 195, 201, and 210, in this numbering, rules 62, 67, 73, 158, 227 (most clearly), and 233 seem to have a sort of vertical counter in them, and rules 61, 121, 131, 146, 199 (most clearly), and 214, have what looks like a horizontal counter. None of them produce chaotic behavior starting from zero initial conditions or a simple seed of 1 injected into the middle of the initial state; rules 60, 120, and 156 can be provoked to Sierpinskify by a seed, and rule 233 can be made to count differently. Right now this program is configured to use two bits per edge color, with 16 possible tile situations and 2⁶⁴ resulting deterministic rule sets. These rule sets include all kinds of behavior. """ import random def tile(ww, rule): "Rule takes top & left color; returns tile, bottom color, & right color." top = [0] * ww while True: row = [] left = 0 for xx in range(ww): tile, top[xx], left = rule(top[xx], left) row.append(tile) yield row def vis_rule(n): "Generate rule n. Top and left should be in {0, 1}." def rule(top, left): tile = (n >> (2 * top + 4 * left)) & 3 return tile, tile & 1, 1 if tile & 2 else 0 return rule def show_all_vis_rules(): for rule in range(256): print(rule) for ii, row in enumerate(tile(64, vis_rule(rule))): print(''.join(' |-#'[x] for x in row)) if ii == 64: break def vis_rule_2(n): "Generate rule n. Top and left should be in {0, 1, 2, 3}." def rule(top, left): tile = (n >> (4 * top + 8 * left)) & 15 return tile, tile & 3, (tile >> 2) & 3 return rule if __name__ == '__main__': rule = random.randrange(2**64) # rule = 12544031149567015362 # is interesting print(rule) for ii, row in enumerate(tile(128, vis_rule_2(rule))): print(''.join(' 123456789abcdef'[x] for x in row))