solution.py
3.3 kB · python · 115 lines
1FLIP = str.maketrans("01", "10")2HEIGHT = 3 ** 0.5 / 234# BINARY56def mrlygram(number: int):7 a = "0"8 b = "101"9 c = "11111"10 d = "0011100"11 rows = number12 bottom = []13 cursor = 014 for index in range(rows):15 cursor = cursor % 8 + 116 match cursor:17 case 1 | 8:18 center = a19 alternate = d20 case 2 | 7:21 center = b22 alternate = c23 case 3 | 6:24 center = c25 alternate = b26 case 4 | 5:27 center = d28 alternate = a29 binary = center30 target = 4 * number - 1 - (2 * index)31 while len(binary) < target:32 binary = alternate + binary + alternate33 binary = center + binary + center34 while len(binary) != target:35 binary = binary[1:-1]36 bottom.append(binary)37 top = bottom.copy()38 top.reverse()39 binary = top + bottom40 if number % 4 == 1:41 binary = [row.translate(FLIP) for row in binary]42 return binary4344# COORDINATES4546def coordinates(binary):47 width = max(len(row) for row in binary)48 cells = []49 for y, row in enumerate(binary):50 padded = row51 while len(padded) < width:52 padded = "-" + padded + "-"53 for x, cell in enumerate(padded):54 kind = {"1": "fill", "0": "void", "-": "grid"}[cell]55 cells.append({"type": kind, "x": x + 1, "y": y + 1})56 return cells5758# POINTS5960def points(cells):61 triangles = []62 north = True63 for cell in cells:64 left = (cell["x"] - 1) / 265 y = cell["y"]66 if north:67 triangle = [(left, y), (left + 0.5, y - 1), (left + 1, y)]68 else:69 triangle = [(left, y - 1), (left + 0.5, y), (left + 1, y - 1)]70 triangles.append({"type": cell["type"], "points": triangle})71 north = not north72 return triangles7374# SVG7576def svg(triangles, scale=50):77 width = max(x for t in triangles for x, y in t["points"]) * scale78 height = max(y for t in triangles for x, y in t["points"]) * HEIGHT * scale79 shapes = []80 for triangle in triangles:81 if triangle["type"] == "grid":82 continue83 corners = " ".join("%g,%g" % (x * scale, y * HEIGHT * scale) for x, y in triangle["points"])84 color = "black" if triangle["type"] == "fill" else "white"85 shapes.append('<polygon points="%s" fill="%s"/>' % (corners, color))86 header = '<svg xmlns="http://www.w3.org/2000/svg" width="%g" height="%g">' % (width, height)87 return "\n".join([header] + shapes + ["</svg>"])8889# PRINT9091def pretty_print(binary):92 target = 093 for row in binary:94 if len(row) > target:95 target = len(row)96 print("-" * target)97 for row in binary:98 count = len(row)99 while len(row) < target:100 row = "-" + row101 row = row + "-"102 print(f"{row} ({count})")103 print("-" * target)104105if __name__ == "__main__":106 import sys107 number = int(sys.argv[1]) if len(sys.argv) > 1 else 7108 if number < 1 or number % 2 == 0:109 sys.exit("odd numbers only")110 binary = mrlygram(number)111 pretty_print(binary)112 name = f"mrlygram-{number}.svg"113 with open(name, "w") as f:114 f.write(svg(points(coordinates(binary))) + "\n")115 print(f"wrote {name}")