Add 2023 day 12 ':]
This commit is contained in:
parent
b28f4986a7
commit
b5c262097a
148
2023/day12.py
Executable file
148
2023/day12.py
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""
|
||||||
|
Jour 12 du défi Advent Of Code pour l'année 2023
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from functools import cache, wraps
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
def read_sample():
|
||||||
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
|
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day12.txt")
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
sample = f.read().split('\n')
|
||||||
|
sample = [ i for i in sample if i != '' ]
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sample(sample):
|
||||||
|
springs = []
|
||||||
|
counts = []
|
||||||
|
for i in range(len(sample)):
|
||||||
|
springs.append(sample[i].split(" ")[0])
|
||||||
|
counts.append([int(i) for i in sample[i].split(" ")[1].split(",")])
|
||||||
|
return springs, counts
|
||||||
|
|
||||||
|
|
||||||
|
def timing(f):
|
||||||
|
@wraps(f)
|
||||||
|
def wrap(*args, **kw):
|
||||||
|
ts = time()
|
||||||
|
result = f(*args, **kw)
|
||||||
|
te = time()
|
||||||
|
print('> %s: %2.4f sec' % \
|
||||||
|
(f.__name__, te-ts))
|
||||||
|
return result
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
|
def nb_poss(spring, count):
|
||||||
|
def check_new_elem(elem, size, count):
|
||||||
|
if size > len(count):
|
||||||
|
return False
|
||||||
|
if elem != count[size-1]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def nb_poss_rec(actual_count_size, cur, pos, first):
|
||||||
|
"""
|
||||||
|
actual_count_size: already added elements
|
||||||
|
cur: current number of # in the spring pos
|
||||||
|
pos: current position in the spring
|
||||||
|
first: first elem of the upcoming spring
|
||||||
|
"""
|
||||||
|
# While loop for first elem
|
||||||
|
if pos < len(spring) and first != '?':
|
||||||
|
if first == '.':
|
||||||
|
if cur > 0:
|
||||||
|
actual_count_size += 1
|
||||||
|
if not check_new_elem(cur, actual_count_size, count):
|
||||||
|
return 0
|
||||||
|
cur = 0
|
||||||
|
elif first == '#':
|
||||||
|
cur += 1
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
# Exactly the same loop for the other elems
|
||||||
|
while pos < len(spring) and spring[pos] != '?':
|
||||||
|
if spring[pos] == '.':
|
||||||
|
if cur > 0:
|
||||||
|
actual_count_size += 1
|
||||||
|
if not check_new_elem(cur, actual_count_size, count):
|
||||||
|
return 0
|
||||||
|
cur = 0
|
||||||
|
elif spring[pos] == '#':
|
||||||
|
cur += 1
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
# spring ends with # ?
|
||||||
|
if pos == len(spring) and cur > 0:
|
||||||
|
actual_count_size += 1
|
||||||
|
if not check_new_elem(cur, actual_count_size, count):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# End of spring ?
|
||||||
|
if pos >= len(spring):
|
||||||
|
if len(count) == actual_count_size:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Debugging
|
||||||
|
if spring[pos] != '?':
|
||||||
|
print("weird", spring, count, actual_count_size, pos, spring[pos], len(spring))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Recursive calls
|
||||||
|
if spring[pos] == '?':
|
||||||
|
if cur > 0:
|
||||||
|
if len(count) > actual_count_size:
|
||||||
|
if cur == count[actual_count_size]:
|
||||||
|
return nb_poss_rec(actual_count_size, cur, pos, '.') # break the #### with a .
|
||||||
|
elif cur < count[actual_count_size]:
|
||||||
|
return nb_poss_rec(actual_count_size, cur, pos, '#') # continue with #
|
||||||
|
else:
|
||||||
|
return 0 # not possible
|
||||||
|
return nb_poss_rec(actual_count_size, cur, pos, '.') + nb_poss_rec(actual_count_size, cur, pos, '#')
|
||||||
|
|
||||||
|
return nb_poss_rec(0, 0, 0, spring[0])
|
||||||
|
|
||||||
|
|
||||||
|
def unfold(springs, counts):
|
||||||
|
for i in range(len(springs)):
|
||||||
|
springs[i] = '?'.join([springs[i]]*5)
|
||||||
|
counts[i] = counts[i]*5
|
||||||
|
|
||||||
|
|
||||||
|
@timing
|
||||||
|
def part1(sample):
|
||||||
|
"""Partie 1 du défi"""
|
||||||
|
springs, counts = parse_sample(sample)
|
||||||
|
possibilities = []
|
||||||
|
for i in range(len(springs)):
|
||||||
|
possibilities.append(nb_poss(springs[i], counts[i]))
|
||||||
|
|
||||||
|
return sum(possibilities)
|
||||||
|
|
||||||
|
|
||||||
|
@timing
|
||||||
|
def part2(sample):
|
||||||
|
"""Partie 2 du défi"""
|
||||||
|
springs, counts = parse_sample(sample)
|
||||||
|
unfold(springs, counts)
|
||||||
|
|
||||||
|
possibilities = []
|
||||||
|
for i in range(len(springs)):
|
||||||
|
possibilities.append(nb_poss(springs[i], counts[i]))
|
||||||
|
|
||||||
|
return sum(possibilities)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Fonction principale"""
|
||||||
|
sample = read_sample()
|
||||||
|
print(f"part1: {part1(sample)}")
|
||||||
|
print(f"part2: {part2(sample)}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user