"""Enumerate flattened redstone delay-chains for a given total delay.""" import argparse import sys from typing import NamedTuple class Comp(NamedTuple): delay: int priority: int blocks: tuple # Append custom subcomponents here, e.g. Comp(6, -1, ("-", "R2", "C")). COMPONENTS = [ Comp(8, -3, ("R4",)), Comp(6, -3, ("R3",)), Comp(4, -3, ("R2",)), Comp(2, -3, ("R1",)), Comp(8, -1, ("-", "R4")), Comp(6, -1, ("-", "R3")), Comp(4, -1, ("-", "R2")), Comp(2, -1, ("C",)), Comp(2, -1, ("-", "R1")), Comp(2, 0, ("-", "C")), ] assert all(c.blocks for c in COMPONENTS), "components must have >= 1 block" _ORDERED = sorted(COMPONENTS, key=lambda c: (c.priority, -c.delay)) def _canon(comps): seen = {} for c in comps: seen.setdefault((c.priority, c.delay), c) return list(seen.values()) HEAD = _canon([c for c in _ORDERED if c.blocks[0] == "-"]) BODY = _canon(_ORDERED) def chains(total: int): for c in HEAD: if c.delay > total: continue if total == c.delay: yield c.blocks else: for rest in _body(total - c.delay): yield c.blocks + rest def _body(remaining: int): for c in BODY: if c.delay > remaining: continue if remaining == c.delay: yield c.blocks else: for rest in _body(remaining - c.delay): yield c.blocks + rest def main(): ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("total", type=int, help="total delay to enumerate") ap.add_argument("count", nargs="*", type=int, help="total element count") args = ap.parse_args() tileset = chains(args.total) if args.count: tileset = (chain for chain in tileset if len(chain) in args.count) tileset = list(tileset) for chain in tileset: print(*chain) print(len(tileset), "chains", file=sys.stderr) if __name__ == "__main__": main()