Files
wireless-docs/chains.py
2026-10-02 12:14:26 -04:00

83 lines
2.0 KiB
Python

"""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()