Compare commits
No commits in common. "cfb9d7a0ca5a1a4e400c743a117c3a5499b3c094" and "fac4dbb77af0cd5b21f7c80913a32d7bae9d6e95" have entirely different histories.
cfb9d7a0ca
...
fac4dbb77a
153
2023/day18.py
153
2023/day18.py
@ -1,153 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
"""
|
|
||||||
Jour 18 du défi Advent Of Code pour l'année 2023
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
|
|
||||||
directions = {
|
|
||||||
"R": (0, 1),
|
|
||||||
"L": (0, -1),
|
|
||||||
"U": (-1, 0),
|
|
||||||
"D": (1, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
dir_col = ['R', 'D', 'L', 'U']
|
|
||||||
|
|
||||||
def read_sample():
|
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
|
||||||
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day18.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, new_method=False):
|
|
||||||
if new_method:
|
|
||||||
def parse_instr(c):
|
|
||||||
c = c.replace("(", '').replace(")", '')
|
|
||||||
dir_t = dir_col[int(c[-1])]
|
|
||||||
length = int(c[1:-1], 16)
|
|
||||||
return dir_t, length, c
|
|
||||||
|
|
||||||
|
|
||||||
return [parse_instr(c) for (a, b, c) in [j.split(" ") for j in sample]]
|
|
||||||
return [(a, int(b), c) for (a, b, c) in [j.split(" ") for j in sample]]
|
|
||||||
|
|
||||||
|
|
||||||
def voisins(i, j):
|
|
||||||
return {(i+a, j+b) for (a, b) in directions.values()}
|
|
||||||
|
|
||||||
|
|
||||||
def dig(data, only_edges=False):
|
|
||||||
terrain = []
|
|
||||||
pos = (0, 0)
|
|
||||||
for dir_t, length, color in data:
|
|
||||||
if only_edges:
|
|
||||||
terrain.append((pos, color))
|
|
||||||
pos = (pos[0]+directions[dir_t][0]*length, pos[1]+directions[dir_t][1]*length)
|
|
||||||
else:
|
|
||||||
for i in range(length):
|
|
||||||
terrain.append((pos, color))
|
|
||||||
pos = (pos[0]+directions[dir_t][0], pos[1]+directions[dir_t][1])
|
|
||||||
|
|
||||||
new_terrain = {t[0] for t in terrain}
|
|
||||||
min_x = min((i[1] for i in new_terrain))
|
|
||||||
min_y = min((i[0] for i in new_terrain))
|
|
||||||
return [((i-min_y, j-min_x), color) for ((i, j), color) in terrain]
|
|
||||||
|
|
||||||
|
|
||||||
def count_holes(terrain):
|
|
||||||
new_terrain = {t[0] for t in terrain}
|
|
||||||
max_y = max((i[1] for i in new_terrain))+1
|
|
||||||
max_x = max((i[0] for i in new_terrain))+1
|
|
||||||
|
|
||||||
flow = set()
|
|
||||||
|
|
||||||
def has_hole(i, j):
|
|
||||||
cpt = 0
|
|
||||||
for k in range(j):
|
|
||||||
if (i, k) in new_terrain:
|
|
||||||
cpt += 1
|
|
||||||
if cpt == 1:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
for i in range(max_x):
|
|
||||||
for j in range(max_y):
|
|
||||||
if has_hole(i, j) and (i, j) not in new_terrain:
|
|
||||||
flow.add((i, j))
|
|
||||||
|
|
||||||
modif = True
|
|
||||||
while modif:
|
|
||||||
modif = False
|
|
||||||
for i in range(max_x):
|
|
||||||
for j in range(max_y):
|
|
||||||
if ((i, j) not in flow and len(voisins(i, j) & flow) > 0):
|
|
||||||
if (i, j) not in new_terrain:
|
|
||||||
modif = True
|
|
||||||
flow.add((i, j))
|
|
||||||
|
|
||||||
#print_terrain({(i, '0') for i in flow|new_terrain})
|
|
||||||
return len(flow|new_terrain)
|
|
||||||
|
|
||||||
|
|
||||||
def print_terrain(terrain):
|
|
||||||
new_terrain = {t[0] for t in terrain}
|
|
||||||
max_x = max((i[1] for i in new_terrain))
|
|
||||||
max_y = max((i[0] for i in new_terrain))
|
|
||||||
|
|
||||||
for i in range(max_y+1):
|
|
||||||
for j in range(max_x+1):
|
|
||||||
if (i, j) in new_terrain:
|
|
||||||
print('#', end='')
|
|
||||||
else:
|
|
||||||
print('.', end='')
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def border(data):
|
|
||||||
return(sum((i[1] for i in data)))
|
|
||||||
|
|
||||||
# https://www.tutorialspoint.com/program-to-find-area-of-a-polygon-in-python
|
|
||||||
def getInfo(x1, y1, x2, y2):
|
|
||||||
return x1*y2 - y1*x2
|
|
||||||
|
|
||||||
def solve(data):
|
|
||||||
points = [t[0] for t in data]
|
|
||||||
N = len(points)
|
|
||||||
firstx, firsty = points[0]
|
|
||||||
prevx, prevy = firstx, firsty
|
|
||||||
res = 0
|
|
||||||
|
|
||||||
for i in range(1, N):
|
|
||||||
nextx, nexty = points[i]
|
|
||||||
res = res + getInfo(prevx,prevy,nextx,nexty)
|
|
||||||
prevx = nextx
|
|
||||||
prevy = nexty
|
|
||||||
res = res + getInfo(prevx,prevy,firstx,firsty)
|
|
||||||
return abs(res)/2.0
|
|
||||||
|
|
||||||
|
|
||||||
def part1(sample):
|
|
||||||
"""Partie 1 du défi"""
|
|
||||||
data = parse_sample(sample, new_method=False)
|
|
||||||
terrain = dig(data)
|
|
||||||
return count_holes(terrain)
|
|
||||||
|
|
||||||
def part2(sample):
|
|
||||||
"""Partie 2 du défi"""
|
|
||||||
data = parse_sample(sample, new_method=True)
|
|
||||||
terrain = dig(data, only_edges=True)
|
|
||||||
return int(solve(terrain)+border(data)//2 +1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Fonction principale"""
|
|
||||||
sample = read_sample()
|
|
||||||
print(f"part1: {part1(sample)}")
|
|
||||||
print(f"part2: {part2(sample)}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
135
2023/day19.py
135
2023/day19.py
@ -1,135 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
"""
|
|
||||||
Jour 19 du défi Advent Of Code pour l'année 2023
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
|
|
||||||
def read_sample():
|
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
|
||||||
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day19.txt")
|
|
||||||
with open(filename, 'r') as f:
|
|
||||||
sample = f.read()
|
|
||||||
return sample
|
|
||||||
|
|
||||||
def parse_sample(sample):
|
|
||||||
def parse_wf(wf):
|
|
||||||
name = wf.split("{")[0]
|
|
||||||
content = wf.split("{")[1].split("}")[0].split(",")
|
|
||||||
return name, content
|
|
||||||
|
|
||||||
def parse_part(part):
|
|
||||||
content = part.split("{")[1].split("}")[0].split(",")
|
|
||||||
dico = {p.split("=")[0]: int(p.split("=")[1]) for p in content}
|
|
||||||
return dico
|
|
||||||
|
|
||||||
workflows, parts, = sample.split("\n\n")
|
|
||||||
workflows = [parse_wf(i) for i in workflows.split("\n") if i != '']
|
|
||||||
workflows = {i[0]: i[1] for i in workflows}
|
|
||||||
parts = [parse_part(i) for i in parts.split("\n") if i != '']
|
|
||||||
return workflows, parts
|
|
||||||
|
|
||||||
|
|
||||||
def process(part, workflows, start="in"):
|
|
||||||
def goto(instr):
|
|
||||||
if instr == "A":
|
|
||||||
return True
|
|
||||||
if instr == "R":
|
|
||||||
return False
|
|
||||||
return process(part, workflows, start=instr)
|
|
||||||
|
|
||||||
def ceval(expr):
|
|
||||||
if '>' in expr:
|
|
||||||
a, b, = expr.split('>')
|
|
||||||
return part[a] > int(b)
|
|
||||||
if '<' in expr:
|
|
||||||
a, b, = expr.split('<')
|
|
||||||
return part[a] < int(b)
|
|
||||||
|
|
||||||
for instr in workflows[start]:
|
|
||||||
if ':' in instr:
|
|
||||||
if ceval(instr.split(":")[0]):
|
|
||||||
return goto(instr.split(":")[1])
|
|
||||||
else:
|
|
||||||
return goto(instr)
|
|
||||||
return goto("R")
|
|
||||||
|
|
||||||
|
|
||||||
def process2(part, workflows, start="in"):
|
|
||||||
def sizeof(part):
|
|
||||||
prod = 1
|
|
||||||
for i in part.values():
|
|
||||||
prod *= i[1]-i[0]+1
|
|
||||||
return prod
|
|
||||||
|
|
||||||
def goto(instr, part):
|
|
||||||
if instr == "A":
|
|
||||||
return sizeof(part) # taille de l'instance
|
|
||||||
if instr == "R":
|
|
||||||
return 0
|
|
||||||
return process2(part, workflows, start=instr)
|
|
||||||
|
|
||||||
def apply_flows(part, flows):
|
|
||||||
if not flows:
|
|
||||||
raise NotImplementedError
|
|
||||||
instr, *next_flows = flows
|
|
||||||
|
|
||||||
if ":" not in instr:
|
|
||||||
return goto(instr, part)
|
|
||||||
|
|
||||||
expr = instr.split(":")[0]
|
|
||||||
action = instr.split(":")[1]
|
|
||||||
if '>' in expr:
|
|
||||||
a, b, = expr.split('>')
|
|
||||||
if part[a][0] > int(b):
|
|
||||||
return goto(action, part)
|
|
||||||
if part[a][1] <= int(b):
|
|
||||||
return apply_flows(part, next_flows)
|
|
||||||
|
|
||||||
left = part.copy()
|
|
||||||
right = part.copy()
|
|
||||||
left[a] = (part[a][0], int(b))
|
|
||||||
right[a] = (int(b)+1, part[a][1])
|
|
||||||
return goto(action, right)+apply_flows(left, next_flows)
|
|
||||||
|
|
||||||
if '<' in expr:
|
|
||||||
a, b, = expr.split('<')
|
|
||||||
if part[a][1] < int(b):
|
|
||||||
return goto(action, part)
|
|
||||||
if part[a][0] >= int(b):
|
|
||||||
return apply_flows(part, next_flows)
|
|
||||||
|
|
||||||
left = part.copy()
|
|
||||||
right = part.copy()
|
|
||||||
left[a] = (part[a][0], int(b)-1)
|
|
||||||
right[a] = (int(b), part[a][1])
|
|
||||||
return goto(action, left)+apply_flows(right, next_flows)
|
|
||||||
|
|
||||||
return apply_flows(part, workflows[start])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def part1(sample):
|
|
||||||
"""Partie 1 du défi"""
|
|
||||||
workflows, parts = parse_sample(sample)
|
|
||||||
somme = 0
|
|
||||||
for part in parts:
|
|
||||||
if process(part, workflows):
|
|
||||||
somme += part["x"]+part["m"]+part["a"]+part["s"]
|
|
||||||
return somme
|
|
||||||
|
|
||||||
|
|
||||||
def part2(sample):
|
|
||||||
"""Partie 2 du défi"""
|
|
||||||
workflows, _ = parse_sample(sample)
|
|
||||||
|
|
||||||
return process2({"x":(1, 4000), "m":(1, 4000), "a":(1, 4000), "s":(1, 4000)}, workflows)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Fonction principale"""
|
|
||||||
sample = read_sample()
|
|
||||||
print(f"part1: {part1(sample)}")
|
|
||||||
print(f"part2: {part2(sample)}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Loading…
x
Reference in New Issue
Block a user