Compare commits

...

3 commits

Author SHA1 Message Date
Bruno BELANYI d2e2d79d71 2023: d12: ex2: add solution 2023-12-12 19:29:49 +01:00
Bruno BELANYI 15b8b5aaeb 2023: d12: ex2: add input 2023-12-12 19:29:49 +01:00
Bruno BELANYI 70fdb4e606 2023: d12: ex1: add solution 2023-12-12 19:29:49 +01:00
3 changed files with 1104 additions and 0 deletions

47
2023/d12/ex1/ex1.py Executable file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env python
import functools
import sys
def solve(input: list[str]) -> int:
def parse(input: list[str]) -> list[tuple[str, tuple[int, ...]]]:
return [
(record, tuple(map(int, groups.split(","))))
for record, groups in map(str.split, input)
]
@functools.cache
def solve_line(record: str, groups: tuple[int, ...]) -> int:
# Empty string must have no groups left, or it's not a solve
if len(record) == 0:
return 1 if len(groups) == 0 else 0
# Empty groups must not contain any broken spring, or it's not a solve
if len(groups) == 0:
return 1 if all(c in (".", "?") for c in record) else 0
# Skip working springs
if record[0] == ".":
return solve_line(record[1:], groups)
# Try with a '.' (and discard it directly), or a '#' for the unknown springs
if record[0] == "?":
return solve_line(record[1:], groups) + solve_line("#" + record[1:], groups)
# We start with a '#', check that the group is long enough
if len(record) < groups[0] or any(c == "." for c in record[: groups[0]]):
return 0
# And check that we _can_ separate the group from the next one
if len(record) > groups[0] and record[groups[0]] == "#":
return 0
# Now recurse
return solve_line(record[groups[0] + 1 :], groups[1:])
lines = parse(input)
return sum(solve_line(record, groups) for record, groups in lines)
def main() -> None:
input = sys.stdin.read().splitlines()
print(solve(input))
if __name__ == "__main__":
main()

57
2023/d12/ex2/ex2.py Executable file
View file

@ -0,0 +1,57 @@
#!/usr/bin/env python
import functools
import itertools
import sys
Line = tuple[str, tuple[int, ...]]
def solve(input: list[str]) -> int:
def parse(input: list[str]) -> list[Line]:
return [
(record, tuple(map(int, groups.split(","))))
for record, groups in map(str.split, input)
]
def unfold(lines: list[Line]) -> list[Line]:
return [
("?".join(itertools.repeat(record, 5)), groups * 5)
for record, groups in lines
]
@functools.cache
def solve_line(record: str, groups: tuple[int, ...]) -> int:
# Empty string must have no groups left, or it's not a solve
if len(record) == 0:
return 1 if len(groups) == 0 else 0
# Empty groups must not contain any broken spring, or it's not a solve
if len(groups) == 0:
return 1 if all(c in (".", "?") for c in record) else 0
# Skip working springs
if record[0] == ".":
return solve_line(record[1:], groups)
# Try with a '.' (and discard it directly), or a '#' for the unknown springs
if record[0] == "?":
return solve_line(record[1:], groups) + solve_line("#" + record[1:], groups)
# We start with a '#', check that the group is long enough
if len(record) < groups[0] or any(c == "." for c in record[: groups[0]]):
return 0
# And check that we _can_ separate the group from the next one
if len(record) > groups[0] and record[groups[0]] == "#":
return 0
# Now recurse
return solve_line(record[groups[0] + 1 :], groups[1:])
lines = parse(input)
lines = unfold(lines)
return sum(solve_line(record, groups) for record, groups in lines)
def main() -> None:
input = sys.stdin.read().splitlines()
print(solve(input))
if __name__ == "__main__":
main()

1000
2023/d12/ex2/input Normal file

File diff suppressed because it is too large Load diff