76 lines
2.1 KiB
Python
Executable file
76 lines
2.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import itertools
|
|
import sys
|
|
from copy import deepcopy
|
|
from typing import Iterable, List, Tuple, cast
|
|
|
|
Paper = List[List[bool]]
|
|
Instruction = Tuple[str, int]
|
|
|
|
|
|
def solve(input: List[str]) -> None:
|
|
def transpose(paper: Paper) -> Paper:
|
|
return cast(Paper, list(zip(*paper)))
|
|
|
|
def fold_along_y(paper: Paper, y: int) -> Paper:
|
|
assert not any(paper[y]) # Sanity check
|
|
assert y >= len(paper) // 2 # Ensure that we can actually fold the paper
|
|
|
|
paper = deepcopy(paper)
|
|
for i, j in zip(itertools.count(y, -1), range(y, len(paper))):
|
|
paper[i] = [(dot_i or dot_j) for dot_i, dot_j in zip(paper[i], paper[j])]
|
|
|
|
paper = paper[:y]
|
|
return paper
|
|
|
|
def fold_along_x(paper: Paper, x: int) -> Paper:
|
|
return transpose(fold_along_y(transpose(paper), x))
|
|
|
|
def do_folds(paper: Paper, instructions: Iterable[Instruction]) -> Paper:
|
|
for axis, n in instructions:
|
|
if axis == "x":
|
|
paper = fold_along_x(paper, n)
|
|
elif axis == "y":
|
|
paper = fold_along_y(paper, n)
|
|
else:
|
|
assert False # Sanity check
|
|
|
|
return paper
|
|
|
|
def parse() -> Tuple[Paper, List[Instruction]]:
|
|
paper_part = itertools.takewhile(lambda s: s != "", input)
|
|
fold_part = itertools.islice(
|
|
itertools.dropwhile(lambda s: s != "", input), 1, None
|
|
)
|
|
|
|
points = {(int(x), int(y)) for x, y in map(lambda s: s.split(","), paper_part)}
|
|
folds = [
|
|
(axis[-1], int(n)) for axis, n in map(lambda s: s.split("="), fold_part)
|
|
]
|
|
|
|
width, height = max(p[0] for p in points), max(p[1] for p in points)
|
|
|
|
paper = [
|
|
[(x, y) in points for x in range(width + 1)] for y in range(height + 1)
|
|
]
|
|
|
|
return paper, folds
|
|
|
|
def dump(paper: Paper) -> None:
|
|
for line in paper:
|
|
print("".join("#" if dot else "." for dot in line))
|
|
|
|
paper, instructions = parse()
|
|
|
|
dump(do_folds(paper, instructions))
|
|
|
|
|
|
def main() -> None:
|
|
input = [line.strip() for line in sys.stdin.readlines()]
|
|
solve(input)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|