generated from public/aoc_template
Day 12 - delete brute force approach
This commit is contained in:
parent
2d5553e1c3
commit
e4aff38d54
212
day12_bf.py
212
day12_bf.py
@ -1,212 +0,0 @@
|
|||||||
import re
|
|
||||||
from tools.aoc import AOCDay
|
|
||||||
from tools.int_seq import triangular
|
|
||||||
from typing import Any, Iterable
|
|
||||||
|
|
||||||
|
|
||||||
def is_Valid(springs: str, groups: list[int]) -> bool:
|
|
||||||
foo = []
|
|
||||||
h_count = 0
|
|
||||||
for c in springs:
|
|
||||||
if c == "#":
|
|
||||||
h_count += 1
|
|
||||||
elif h_count > 0:
|
|
||||||
foo.append(h_count)
|
|
||||||
h_count = 0
|
|
||||||
|
|
||||||
if h_count > 0:
|
|
||||||
foo.append(h_count)
|
|
||||||
|
|
||||||
return foo == groups
|
|
||||||
|
|
||||||
|
|
||||||
def sums(length: int, total_sum: int) -> Iterable[tuple]:
|
|
||||||
if length == 1:
|
|
||||||
yield (total_sum,)
|
|
||||||
else:
|
|
||||||
for v in range(total_sum + 1):
|
|
||||||
for p in sums(length - 1, total_sum - v):
|
|
||||||
yield (v,) + p
|
|
||||||
|
|
||||||
|
|
||||||
def get_options(groups: list[int], fill: list[int]) -> Iterable[str]:
|
|
||||||
missing_len = sum(fill)
|
|
||||||
# print("fill_len", len(fill), "miss_len", missing_len)
|
|
||||||
for opt in sums(len(fill), missing_len):
|
|
||||||
ret = ""
|
|
||||||
for i, c in enumerate(opt):
|
|
||||||
if 0 < i < len(fill) - 1 and c == 0:
|
|
||||||
break
|
|
||||||
ret += " " * c
|
|
||||||
if i < len(groups):
|
|
||||||
ret += "#" * groups[i]
|
|
||||||
else:
|
|
||||||
yield ret
|
|
||||||
|
|
||||||
|
|
||||||
def get_arrangements(springs: str, groups: list[int]) -> int:
|
|
||||||
arrangements = 0
|
|
||||||
springs = springs.replace(".", " ")
|
|
||||||
|
|
||||||
after_fill = len(springs) - sum(groups) - len(groups) + 1
|
|
||||||
if after_fill == 0:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
fill = [0] + [1] * (len(groups) - 1) + [after_fill]
|
|
||||||
p = re.compile(springs.replace("?", "."))
|
|
||||||
for s in get_options(groups, fill):
|
|
||||||
if p.match(s):
|
|
||||||
arrangements += 1
|
|
||||||
|
|
||||||
return arrangements
|
|
||||||
|
|
||||||
|
|
||||||
def _get_arrangements(springs: str, groups: list[int]):
|
|
||||||
springs, not_found = clean_springs(springs, groups)
|
|
||||||
# print("not_found", not_found)
|
|
||||||
open_groups = get_open_groups(springs)
|
|
||||||
to_determine = []
|
|
||||||
for start, group_str in open_groups:
|
|
||||||
# print("look in", group_str, "for", [groups[x] for x in not_found])
|
|
||||||
assigned = []
|
|
||||||
for need in list(not_found):
|
|
||||||
# print("check", need, groups[need])
|
|
||||||
if groups[need] > len(group_str):
|
|
||||||
continue
|
|
||||||
elif not assigned or sum(assigned) + len(assigned) + groups[need] <= len(group_str):
|
|
||||||
assigned.append(groups[need])
|
|
||||||
not_found = not_found[1:]
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
# print("append", assigned)
|
|
||||||
if assigned:
|
|
||||||
to_determine.append((group_str, assigned))
|
|
||||||
|
|
||||||
arrangements = 1
|
|
||||||
for group_str, values in to_determine:
|
|
||||||
if len(values) == 1 and len(group_str) == values[0]:
|
|
||||||
continue
|
|
||||||
elif sum(values) + len(values) - 1 == len(group_str):
|
|
||||||
continue
|
|
||||||
elif len(values) == 1:
|
|
||||||
arrangements *= len(group_str) - values[0] + 1
|
|
||||||
else:
|
|
||||||
arrangements *= triangular(len(group_str) - (sum(values) + len(values) - 1) + 1)
|
|
||||||
# print(
|
|
||||||
# group_str,
|
|
||||||
# "with",
|
|
||||||
# values,
|
|
||||||
# "has multiple options:",
|
|
||||||
# triangular(len(group_str) - (sum(values) + len(values) - 1) + 1),
|
|
||||||
# )
|
|
||||||
|
|
||||||
if arrangements < 0:
|
|
||||||
# print(springs, groups, to_determine)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
return arrangements
|
|
||||||
|
|
||||||
|
|
||||||
def clean_springs(springs: str, groups: list[int]) -> (str, list[int]):
|
|
||||||
hashes = []
|
|
||||||
start = None
|
|
||||||
c_size = 0
|
|
||||||
for i, c in enumerate(springs):
|
|
||||||
if c == "#":
|
|
||||||
if start is None:
|
|
||||||
start = i
|
|
||||||
c_size += 1
|
|
||||||
else:
|
|
||||||
if start is not None:
|
|
||||||
hashes.append((start, c_size))
|
|
||||||
start = None
|
|
||||||
c_size = 0
|
|
||||||
|
|
||||||
if start is not None:
|
|
||||||
hashes.append((start, c_size))
|
|
||||||
|
|
||||||
# print("cleaning", springs, "with hashes", hashes, "and groups", groups)
|
|
||||||
found = []
|
|
||||||
for i, s in enumerate(groups):
|
|
||||||
for h in hashes:
|
|
||||||
if h[0] >= sum(groups[:i]) + i and h[0] <= len(springs) - (sum(groups[i:]) + len(groups) - i) + 1:
|
|
||||||
# print(h[0], ">", sum(groups[:i]) + i)
|
|
||||||
# print(h[0], "<", len(springs) - (sum(groups[i:]) + len(groups) - i) + 1)
|
|
||||||
if h[1] == s:
|
|
||||||
found.append(i)
|
|
||||||
if i == 0:
|
|
||||||
springs = "#" * h[1] + "." + springs[h[0] + h[1] + 1 :]
|
|
||||||
elif i == len(springs) - 1:
|
|
||||||
springs = springs[: -(h[0] + h[1] + 1)] + "." + "#" * h[1]
|
|
||||||
else:
|
|
||||||
springs = springs[: h[0] - 1] + "." + "#" * h[1] + "." + springs[h[0] + h[1] + 1 :]
|
|
||||||
# print("found index", i, "value", groups[i], "at", h[0], "new springs", springs)
|
|
||||||
break
|
|
||||||
|
|
||||||
# print("cleaned springs", springs, "found", found)
|
|
||||||
|
|
||||||
return springs, [x for x in range(len(groups)) if x not in found]
|
|
||||||
|
|
||||||
|
|
||||||
def get_open_groups(springs: str) -> list[tuple[int, str]]:
|
|
||||||
open_groups = []
|
|
||||||
start = None
|
|
||||||
group_str = ""
|
|
||||||
for i, c in enumerate(springs):
|
|
||||||
if c == ".":
|
|
||||||
if "?" in group_str:
|
|
||||||
open_groups.append((start, group_str))
|
|
||||||
start = None
|
|
||||||
group_str = ""
|
|
||||||
else:
|
|
||||||
if start is None:
|
|
||||||
start = i
|
|
||||||
group_str += c
|
|
||||||
|
|
||||||
if "?" in group_str:
|
|
||||||
open_groups.append((start, group_str))
|
|
||||||
|
|
||||||
return open_groups
|
|
||||||
|
|
||||||
|
|
||||||
class Day(AOCDay):
|
|
||||||
inputs = [
|
|
||||||
[
|
|
||||||
(21, "input12_test"),
|
|
||||||
(6981, "input12"),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
(525152, "input12_test"),
|
|
||||||
(None, "input12"),
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
def part1(self) -> Any:
|
|
||||||
ans = 0
|
|
||||||
for line in self.getInput():
|
|
||||||
springs, groups = line.split()
|
|
||||||
groups = list(map(int, groups.split(",")))
|
|
||||||
f = get_arrangements(springs, groups)
|
|
||||||
print("RESULT", springs, "=>", f)
|
|
||||||
ans += f
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def part2(self) -> Any:
|
|
||||||
return ""
|
|
||||||
ans = 0
|
|
||||||
for i, line in enumerate(self.getInput()):
|
|
||||||
springs, groups = line.split()
|
|
||||||
groups = list(map(int, groups.split(",")))
|
|
||||||
springs = "?".join([springs] * 5)
|
|
||||||
groups = groups * 5
|
|
||||||
f = get_arrangements(springs, groups)
|
|
||||||
print(i + 1, "/", len(self.input), "=>", f)
|
|
||||||
ans += f
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
day = Day(2023, 12)
|
|
||||||
day.run(verbose=True)
|
|
||||||
Loading…
Reference in New Issue
Block a user