solution.py
3.3 kB · python · 117 lines
1from lib.paths import data23FLIP = str.maketrans("01", "10")4HEIGHT = 3 ** 0.5 / 256# BINARY78def mrlygram(number: int):9 a = "0"10 b = "101"11 c = "11111"12 d = "0011100"13 rows = number14 bottom = []15 cursor = 016 for index in range(rows):17 cursor = cursor % 8 + 118 match cursor:19 case 1 | 8:20 center = a21 alternate = d22 case 2 | 7:23 center = b24 alternate = c25 case 3 | 6:26 center = c27 alternate = b28 case 4 | 5:29 center = d30 alternate = a31 binary = center32 target = 4 * number - 1 - (2 * index)33 while len(binary) < target:34 binary = alternate + binary + alternate35 binary = center + binary + center36 while len(binary) != target:37 binary = binary[1:-1]38 bottom.append(binary)39 top = bottom.copy()40 top.reverse()41 binary = top + bottom42 if number % 4 == 1:43 binary = [row.translate(FLIP) for row in binary]44 return binary4546# COORDINATES4748def coordinates(binary):49 width = max(len(row) for row in binary)50 cells = []51 for y, row in enumerate(binary):52 padded = row53 while len(padded) < width:54 padded = "-" + padded + "-"55 for x, cell in enumerate(padded):56 kind = {"1": "fill", "0": "void", "-": "grid"}[cell]57 cells.append({"type": kind, "x": x + 1, "y": y + 1})58 return cells5960# POINTS6162def points(cells):63 triangles = []64 north = True65 for cell in cells:66 left = (cell["x"] - 1) / 267 y = cell["y"]68 if north:69 triangle = [(left, y), (left + 0.5, y - 1), (left + 1, y)]70 else:71 triangle = [(left, y - 1), (left + 0.5, y), (left + 1, y - 1)]72 triangles.append({"type": cell["type"], "points": triangle})73 north = not north74 return triangles7576# SVG7778def svg(triangles, scale=50):79 width = max(x for t in triangles for x, y in t["points"]) * scale80 height = max(y for t in triangles for x, y in t["points"]) * HEIGHT * scale81 shapes = []82 for triangle in triangles:83 if triangle["type"] == "grid":84 continue85 corners = " ".join("%g,%g" % (x * scale, y * HEIGHT * scale) for x, y in triangle["points"])86 color = "black" if triangle["type"] == "fill" else "white"87 shapes.append('<polygon points="%s" fill="%s"/>' % (corners, color))88 header = '<svg xmlns="http://www.w3.org/2000/svg" width="%g" height="%g">' % (width, height)89 return "\n".join([header] + shapes + ["</svg>"])9091# PRINT9293def pretty_print(binary):94 target = 095 for row in binary:96 if len(row) > target:97 target = len(row)98 print("-" * target)99 for row in binary:100 count = len(row)101 while len(row) < target:102 row = "-" + row103 row = row + "-"104 print(f"{row} ({count})")105 print("-" * target)106107if __name__ == "__main__":108 import sys109 number = int(sys.argv[1]) if len(sys.argv) > 1 else 7110 if number < 1 or number % 2 == 0:111 sys.exit("odd numbers only")112 binary = mrlygram(number)113 pretty_print(binary)114 path = data(f"mrlygram-{number}.svg")115 with open(path, "w") as f:116 f.write(svg(points(coordinates(binary))) + "\n")117 print(f"wrote {path}")