Compare commits
3 Commits
e5ba1cc940
...
15b4f24087
Author | SHA1 | Date | |
---|---|---|---|
15b4f24087 | |||
ee031bdf67 | |||
5c55af6ae0 |
130
2022/day17.py
130
2022/day17.py
@ -1,136 +1,20 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
"""
|
"""
|
||||||
Jour 17 du défi Advent Of Code pour l'année 2022
|
Jour 17 du défi Advent Of Code pour l'année 2022
|
||||||
<!-- NE FONCTIONNE PAS --!>
|
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
PRINT = True
|
|
||||||
ROCKS = [
|
|
||||||
[
|
|
||||||
["@", "@", "@", "@"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[".", "@", "."],
|
|
||||||
["@", "@", "@"],
|
|
||||||
[".", "@", "."]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[".", ".", "@"],
|
|
||||||
[".", ".", "@"],
|
|
||||||
["@", "@", "@"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["@"],
|
|
||||||
["@"],
|
|
||||||
["@"],
|
|
||||||
["@"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["@", "@"],
|
|
||||||
["@", "@"],
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def read_sample():
|
def read_sample():
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
with open('inputs/day17.txt', 'r') as f:
|
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day17.txt")
|
||||||
return f.read()
|
with open(filename, 'r') as f:
|
||||||
|
sample = f.read().split('\n')
|
||||||
|
sample = [ i for i in sample if i != '' ]
|
||||||
def print_puzzle(heights, rock, left_down_corner):
|
return sample
|
||||||
if not PRINT:
|
|
||||||
return
|
|
||||||
for i in range(len(rock)):
|
|
||||||
print("|"+"."*left_down_corner[1]+"".join(rock[i])+"."*(7-len(rock[i])-left_down_corner[1])+"|")
|
|
||||||
for i in range(left_down_corner[0]-max(heights)):
|
|
||||||
print("|"+"."*7+"|")
|
|
||||||
for i in range(max(heights)):
|
|
||||||
print("|", end="")
|
|
||||||
for j in range(len(heights)):
|
|
||||||
if heights[j] >= (max(heights)-i):
|
|
||||||
print("#", end="")
|
|
||||||
else:
|
|
||||||
print(".", end="")
|
|
||||||
print("|")
|
|
||||||
print("+"+"-"*7+"+")
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def gas_jet(direction, pos, rock, largeur):
|
|
||||||
if direction == '>':
|
|
||||||
if pos[1]+max([len(j) for j in rock]) < largeur: #Move
|
|
||||||
pos = (pos[0], pos[1]+1)
|
|
||||||
print("Move right:")
|
|
||||||
else:
|
|
||||||
print("Failed to move right:")
|
|
||||||
else:
|
|
||||||
if pos[1] > 0: #Move
|
|
||||||
pos = (pos[0], pos[1]-1)
|
|
||||||
print("Move left:")
|
|
||||||
else:
|
|
||||||
print("Failed to move left:")
|
|
||||||
return pos
|
|
||||||
|
|
||||||
def part1(sample):
|
def part1(sample):
|
||||||
"""Partie 1 du défi"""
|
"""Partie 1 du défi"""
|
||||||
largeur = 7
|
return NotImplementedError
|
||||||
heights = [0 for i in range(largeur)]
|
|
||||||
stream_pos = 0
|
|
||||||
for i in range(2022):
|
|
||||||
print(f"rock {i}")
|
|
||||||
rock = ROCKS[(i)%len(ROCKS)]
|
|
||||||
|
|
||||||
left_down_corner = (max(heights)+3, 2)
|
|
||||||
falling = True
|
|
||||||
while falling:
|
|
||||||
|
|
||||||
left_down_corner = gas_jet(sample[stream_pos%len(sample)], left_down_corner, rock, largeur)
|
|
||||||
stream_pos += 1
|
|
||||||
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
|
|
||||||
print("falls 1 unit:")
|
|
||||||
left_down_corner = (left_down_corner[0]-1, left_down_corner[1])
|
|
||||||
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
# Check si en bas
|
|
||||||
if left_down_corner[0] <= 0:
|
|
||||||
falling = False
|
|
||||||
elif left_down_corner[0] <= max(heights)+1:
|
|
||||||
print("Potentially blocked")
|
|
||||||
for j in range(len(rock[0])):
|
|
||||||
print(f"trying on rock[*][{j}]")
|
|
||||||
if (len(rock)-1) - max([k for k in range(len(rock)) if rock[k][j] != '.']) + left_down_corner[0] == heights[j+left_down_corner[1]]:
|
|
||||||
falling = False
|
|
||||||
print("blocked")
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
if falling:
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
|
|
||||||
left_down_corner = gas_jet(sample[stream_pos%len(sample)], left_down_corner, rock, largeur)
|
|
||||||
stream_pos += 1
|
|
||||||
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
for j in range(len(rock[0])):
|
|
||||||
(len(rock)-1) - max([k for k in range(len(rock)) if rock[k][j] != '.']) + left_down_corner[0]
|
|
||||||
print(j+left_down_corner[1], left_down_corner[0], 1+min([k for k in range(len(rock)) if rock[k][j] != '.']))
|
|
||||||
|
|
||||||
if heights[j+left_down_corner[1]] > left_down_corner[0] + len(rock)-(min([k for k in range(len(rock)) if rock[k][j] != '.'])):
|
|
||||||
print(heights[j+left_down_corner[1]], left_down_corner[0] + len(rock)-(min([k for k in range(len(rock)) if rock[k][j] != '.'])), "Error!")
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
print(heights)
|
|
||||||
print(left_down_corner)
|
|
||||||
print(len(rock))
|
|
||||||
print(min([k for k in range(len(rock)) if rock[k][j] != '.']))
|
|
||||||
raise Exception
|
|
||||||
heights[j+left_down_corner[1]] = left_down_corner[0] + len(rock)-(min([k for k in range(len(rock)) if rock[k][j] != '.']))
|
|
||||||
|
|
||||||
print("## ignore rock:")
|
|
||||||
print_puzzle(heights, rock, left_down_corner)
|
|
||||||
return max(heights)
|
|
||||||
|
|
||||||
def part2(sample):
|
def part2(sample):
|
||||||
"""Partie 2 du défi"""
|
"""Partie 2 du défi"""
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
Jour 08 du défi Advent Of Code pour l'année 2023
|
Jour 08 du défi Advent Of Code pour l'année 2023
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import math
|
||||||
|
|
||||||
def read_sample():
|
def read_sample():
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
@ -12,19 +13,6 @@ def read_sample():
|
|||||||
sample = [ i for i in sample if i != '' ]
|
sample = [ i for i in sample if i != '' ]
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
def gcd(a, b):
|
|
||||||
while b:
|
|
||||||
a, b = b, a % b
|
|
||||||
return a
|
|
||||||
|
|
||||||
def lcm(a, b):
|
|
||||||
return (a * b) // gcd(a, b)
|
|
||||||
|
|
||||||
def lcm_of_list(numbers):
|
|
||||||
result = 1
|
|
||||||
for num in numbers:
|
|
||||||
result = lcm(result, num)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def parse_sample(sample):
|
def parse_sample(sample):
|
||||||
instructions = sample[0]
|
instructions = sample[0]
|
||||||
@ -34,6 +22,7 @@ def parse_sample(sample):
|
|||||||
}
|
}
|
||||||
return instructions, mappings
|
return instructions, mappings
|
||||||
|
|
||||||
|
|
||||||
def number_steps(instructions, mappings, pos, untilZZZ=True):
|
def number_steps(instructions, mappings, pos, untilZZZ=True):
|
||||||
step = 0
|
step = 0
|
||||||
instr = {
|
instr = {
|
||||||
@ -44,6 +33,8 @@ def number_steps(instructions, mappings, pos, untilZZZ=True):
|
|||||||
step += 1
|
step += 1
|
||||||
return step
|
return step
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def part1(sample):
|
def part1(sample):
|
||||||
"""Partie 1 du défi"""
|
"""Partie 1 du défi"""
|
||||||
instructions, mappings = parse_sample(sample)
|
instructions, mappings = parse_sample(sample)
|
||||||
@ -54,7 +45,7 @@ def part2(sample):
|
|||||||
instructions, mappings = parse_sample(sample)
|
instructions, mappings = parse_sample(sample)
|
||||||
a_ending = [i for i in mappings.keys() if i[-1] == 'A']
|
a_ending = [i for i in mappings.keys() if i[-1] == 'A']
|
||||||
steps = [number_steps(instructions, mappings, i, untilZZZ=False) for i in a_ending]
|
steps = [number_steps(instructions, mappings, i, untilZZZ=False) for i in a_ending]
|
||||||
return lcm_of_list(steps)
|
return math.lcm(*steps)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
Jour 12 du défi Advent Of Code pour l'année 2023
|
Jour 12 du défi Advent Of Code pour l'année 2023
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from functools import cache, wraps
|
from functools import cache
|
||||||
from time import time
|
|
||||||
|
from aoc_utils import decorators
|
||||||
|
|
||||||
def read_sample():
|
def read_sample():
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
@ -24,18 +25,6 @@ def parse_sample(sample):
|
|||||||
return springs, counts
|
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 nb_poss(spring, count):
|
||||||
def check_new_elem(elem, size, count):
|
def check_new_elem(elem, size, count):
|
||||||
if size > len(count):
|
if size > len(count):
|
||||||
@ -114,7 +103,7 @@ def unfold(springs, counts):
|
|||||||
counts[i] = counts[i]*5
|
counts[i] = counts[i]*5
|
||||||
|
|
||||||
|
|
||||||
@timing
|
@decorators.timeit
|
||||||
def part1(sample):
|
def part1(sample):
|
||||||
"""Partie 1 du défi"""
|
"""Partie 1 du défi"""
|
||||||
springs, counts = parse_sample(sample)
|
springs, counts = parse_sample(sample)
|
||||||
@ -125,7 +114,7 @@ def part1(sample):
|
|||||||
return sum(possibilities)
|
return sum(possibilities)
|
||||||
|
|
||||||
|
|
||||||
@timing
|
@decorators.timeit
|
||||||
def part2(sample):
|
def part2(sample):
|
||||||
"""Partie 2 du défi"""
|
"""Partie 2 du défi"""
|
||||||
springs, counts = parse_sample(sample)
|
springs, counts = parse_sample(sample)
|
||||||
|
@ -4,6 +4,8 @@ Jour 18 du défi Advent Of Code pour l'année 2023
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from aoc_utils import snippets
|
||||||
|
|
||||||
directions = {
|
directions = {
|
||||||
"R": (0, 1),
|
"R": (0, 1),
|
||||||
"L": (0, -1),
|
"L": (0, -1),
|
||||||
@ -107,29 +109,6 @@ def print_terrain(terrain):
|
|||||||
print()
|
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):
|
def part1(sample):
|
||||||
"""Partie 1 du défi"""
|
"""Partie 1 du défi"""
|
||||||
data = parse_sample(sample, new_method=False)
|
data = parse_sample(sample, new_method=False)
|
||||||
@ -140,7 +119,8 @@ def part2(sample):
|
|||||||
"""Partie 2 du défi"""
|
"""Partie 2 du défi"""
|
||||||
data = parse_sample(sample, new_method=True)
|
data = parse_sample(sample, new_method=True)
|
||||||
terrain = dig(data, only_edges=True)
|
terrain = dig(data, only_edges=True)
|
||||||
return int(solve(terrain)+border(data)//2 +1)
|
points = [i[0] for i in terrain]
|
||||||
|
return snippets.area(points)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
Jour 21 du défi Advent Of Code pour l'année 2023
|
Jour 21 du défi Advent Of Code pour l'année 2023
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from aoc_utils.decorators import timeit
|
|
||||||
|
from aoc_utils import decorators, snippets
|
||||||
|
|
||||||
def read_sample():
|
def read_sample():
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
@ -62,24 +63,12 @@ def do_steps(sample, steps=26501365, ext=False):
|
|||||||
return pos_ts
|
return pos_ts
|
||||||
|
|
||||||
|
|
||||||
def lagrange_interpolation(points, x0):
|
@decorators.timeit
|
||||||
result = 0
|
|
||||||
for i in range(len(points)):
|
|
||||||
temp = points[i][1]
|
|
||||||
for j in range(len(points)):
|
|
||||||
if j != i:
|
|
||||||
temp *= (x0 - points[j][0]) / (points[i][0] - points[j][0])
|
|
||||||
|
|
||||||
result += temp
|
|
||||||
|
|
||||||
return int(result)
|
|
||||||
|
|
||||||
@timeit
|
|
||||||
def part1(sample):
|
def part1(sample):
|
||||||
"""Partie 1 du défi"""
|
"""Partie 1 du défi"""
|
||||||
return len(do_steps(sample, steps=64, ext=False))
|
return len(do_steps(sample, steps=64, ext=False))
|
||||||
|
|
||||||
@timeit
|
@decorators.timeit
|
||||||
def part2(sample):
|
def part2(sample):
|
||||||
"""Partie 2 du défi"""
|
"""Partie 2 du défi"""
|
||||||
def challenge(steps):
|
def challenge(steps):
|
||||||
@ -93,7 +82,7 @@ def part2(sample):
|
|||||||
(half_size+size, challenge(half_size+size)),
|
(half_size+size, challenge(half_size+size)),
|
||||||
(half_size+2*size, challenge(half_size+2*size))
|
(half_size+2*size, challenge(half_size+2*size))
|
||||||
]
|
]
|
||||||
return lagrange_interpolation(points, 26501365)
|
return snippets.lagrange_interpolation(points, 26501365)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import os
|
|||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from aoc_utils.intervals import Interval
|
||||||
|
|
||||||
def read_sample():
|
def read_sample():
|
||||||
"""récupère les entrées depuis le fichier texte correspondant"""
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day22.txt")
|
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day22.txt")
|
||||||
@ -22,37 +24,25 @@ class Brick:
|
|||||||
coords = text.split("~")
|
coords = text.split("~")
|
||||||
coords = (coords[0].split(','), coords[1].split(','))
|
coords = (coords[0].split(','), coords[1].split(','))
|
||||||
|
|
||||||
self.x0 = int(coords[0][0])
|
self.x = Interval(int(coords[0][0]), int(coords[1][0]))
|
||||||
self.y0 = int(coords[0][1])
|
self.y = Interval(int(coords[0][1]), int(coords[1][1]))
|
||||||
self.z0 = int(coords[0][2])
|
self.z = Interval(int(coords[0][2]), int(coords[1][2]))
|
||||||
|
|
||||||
self.x1 = int(coords[1][0])
|
|
||||||
self.y1 = int(coords[1][1])
|
|
||||||
self.z1 = int(coords[1][2])
|
|
||||||
|
|
||||||
self.label = random.choice(string.ascii_letters)
|
self.label = random.choice(string.ascii_letters)
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"[{self.label}]{self.x0},{self.y0},{self.z0}~{self.x1},{self.y1},{self.z1}"
|
return f"[{self.label}]{self.x.low},{self.y.low},{self.z.low}~{self.x.up},{self.y.up},{self.z.up}"
|
||||||
#return self.text+f"[{self.label}] [h:{self.z0}]"
|
#return self.text+f"[{self.label}] [h:{self.z.low}]"
|
||||||
|
|
||||||
def supported_by(self, brick):
|
def supported_by(self, brick):
|
||||||
def intersect(interval1, interval2):
|
if brick.z.up == self.z.low-1:
|
||||||
if interval2[0] > interval1[1] or interval1[0] > interval2[1]:
|
if self.x.intersect(brick.x) and self.y.intersect(brick.y):
|
||||||
return None
|
|
||||||
new_min = max(interval1[0], interval2[0])
|
|
||||||
new_max = min(interval1[1], interval2[1])
|
|
||||||
return [new_min, new_max]
|
|
||||||
|
|
||||||
if brick.z1 == self.z0-1:
|
|
||||||
if intersect([self.x0, self.x1], [brick.x0, brick.x1]) is not None \
|
|
||||||
and intersect([self.y0, self.y1], [brick.y0, brick.y1]) is not None:
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def can_fall(self, bricks):
|
def can_fall(self, bricks):
|
||||||
if self.z0 == 1:
|
if self.z.low == 1:
|
||||||
return False
|
return False
|
||||||
for brick in bricks:
|
for brick in bricks:
|
||||||
if brick != self and self.supported_by(brick):
|
if brick != self and self.supported_by(brick):
|
||||||
@ -61,27 +51,20 @@ class Brick:
|
|||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
# Assuming your class has a constructor that accepts the same parameters
|
# Assuming your class has a constructor that accepts the same parameters
|
||||||
copie = Brick(f"{self.x0},{self.y0},{self.z0}~{self.x1},{self.y1},{self.z1}")
|
copie = Brick(f"{self.x.low},{self.y.low},{self.z.low}~{self.x.up},{self.y.up},{self.z.up}")
|
||||||
copie.label = self.label
|
copie.label = self.label
|
||||||
return copie
|
return copie
|
||||||
|
|
||||||
def intersect(interval1, interval2):
|
|
||||||
if interval2[0] > interval1[1] or interval1[0] > interval2[1]:
|
|
||||||
return None
|
|
||||||
new_min = max(interval1[0], interval2[0])
|
|
||||||
new_max = min(interval1[1], interval2[1])
|
|
||||||
return [new_min, new_max]
|
|
||||||
|
|
||||||
|
|
||||||
def print_pile(bricks):
|
def print_pile(bricks):
|
||||||
def occupied(x, z):
|
def occupied(x, z):
|
||||||
for b in bricks:
|
for b in bricks:
|
||||||
if b.x0 <= x and x <= b.x1 and b.z0 <= z and z <= b.z1:
|
if b.x.low <= x and x <= b.x.up and b.z.low <= z and z <= b.z.up:
|
||||||
return b
|
return b
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for z in reversed(range(max((b.z1 for b in bricks))+1)):
|
for z in reversed(range(max((b.z.up for b in bricks))+1)):
|
||||||
for x in range(max((b.x1 for b in bricks))+1):
|
for x in range(max((b.x.up for b in bricks))+1):
|
||||||
occ = occupied(x, z)
|
occ = occupied(x, z)
|
||||||
if occ:
|
if occ:
|
||||||
print(occ.label, end="")
|
print(occ.label, end="")
|
||||||
@ -93,7 +76,7 @@ def print_pile(bricks):
|
|||||||
def fall(bricks, count="z"):
|
def fall(bricks, count="z"):
|
||||||
fallen = 0
|
fallen = 0
|
||||||
has_fallen = False
|
has_fallen = False
|
||||||
bricks.sort(key=lambda b: b.z1)
|
bricks.sort(key=lambda b: b.z.up)
|
||||||
for brick in bricks:
|
for brick in bricks:
|
||||||
has_fallen = False
|
has_fallen = False
|
||||||
while brick.can_fall(bricks):
|
while brick.can_fall(bricks):
|
||||||
@ -101,8 +84,8 @@ def fall(bricks, count="z"):
|
|||||||
fallen += 1
|
fallen += 1
|
||||||
|
|
||||||
has_fallen = True
|
has_fallen = True
|
||||||
brick.z0 -= 1
|
brick.z.low -= 1
|
||||||
brick.z1 -= 1
|
brick.z.up -= 1
|
||||||
|
|
||||||
if count != "z" and has_fallen:
|
if count != "z" and has_fallen:
|
||||||
fallen += 1
|
fallen += 1
|
||||||
|
92
2023/day24.py
Executable file
92
2023/day24.py
Executable file
@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""
|
||||||
|
Jour 24 du défi Advent Of Code pour l'année 2023
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import z3
|
||||||
|
|
||||||
|
def read_sample():
|
||||||
|
"""récupère les entrées depuis le fichier texte correspondant"""
|
||||||
|
filename = os.path.join(os.path.dirname(__file__ ), "inputs", "day24.txt")
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
sample = f.read().split('\n')
|
||||||
|
sample = [ i for i in sample if i != '' ]
|
||||||
|
return sample
|
||||||
|
|
||||||
|
class Hailstone:
|
||||||
|
def __init__(self, text):
|
||||||
|
self.px = int(text.split(" @ ")[0].split(", ")[0])
|
||||||
|
self.py = int(text.split(" @ ")[0].split(", ")[1])
|
||||||
|
self.pz = int(text.split(" @ ")[0].split(", ")[2])
|
||||||
|
|
||||||
|
self.dx = int(text.split(" @ ")[1].split(", ")[0])
|
||||||
|
self.dy = int(text.split(" @ ")[1].split(", ")[1])
|
||||||
|
self.dz = int(text.split(" @ ")[1].split(", ")[2])
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.px}, {self.py}, {self.pz} @ {self.dx}, {self.dy}, {self.dz}"
|
||||||
|
|
||||||
|
|
||||||
|
def intersection(h1, h2):
|
||||||
|
try:
|
||||||
|
# ax+b
|
||||||
|
# cx+d
|
||||||
|
b, a = h1.py - (h1.px/h1.dx)*h1.dy, h1.dy/h1.dx
|
||||||
|
d, c = h2.py - (h2.px/h2.dx)*h2.dy, h2.dy/h2.dx
|
||||||
|
|
||||||
|
x = (d - b) / (a - c)
|
||||||
|
y = a*x+b
|
||||||
|
|
||||||
|
if (x-h1.px)/h1.dx < 0:
|
||||||
|
return None
|
||||||
|
if (x-h2.px)/h2.dx < 0:
|
||||||
|
return None
|
||||||
|
except ZeroDivisionError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def part1(sample, left=200000000000000, right=400000000000000):
|
||||||
|
"""Partie 1 du défi"""
|
||||||
|
hailstones = [Hailstone(i) for i in sample]
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for i in range(len(hailstones)):
|
||||||
|
for j in range(i):
|
||||||
|
res = intersection(hailstones[i], hailstones[j])
|
||||||
|
if res is not None:
|
||||||
|
x, y = res
|
||||||
|
if left <= x and x <= right and left <= y and y <= right:
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
def part2(sample):
|
||||||
|
"""Partie 2 du défi"""
|
||||||
|
hailstones = [Hailstone(i) for i in sample]
|
||||||
|
|
||||||
|
px, py, pz, dx, dy, dz = z3.Ints("px py pz dx dy dz")
|
||||||
|
collision = [z3.Int("t"+str(i)) for i in range(len(hailstones))]
|
||||||
|
solver = z3.Solver()
|
||||||
|
for i in range(len(hailstones)):
|
||||||
|
h = hailstones[i]
|
||||||
|
solver.add(px + dx*collision[i] == h.px + h.dx*collision[i])
|
||||||
|
solver.add(py + dy*collision[i] == h.py + h.dy*collision[i])
|
||||||
|
solver.add(pz + dz*collision[i] == h.pz + h.dz*collision[i])
|
||||||
|
|
||||||
|
solver.check()
|
||||||
|
|
||||||
|
|
||||||
|
return solver.model().evaluate(px + py + pz)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Fonction principale"""
|
||||||
|
sample = read_sample()
|
||||||
|
print(f"part1: {part1(sample)}")
|
||||||
|
print(f"part2: {part2(sample)}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
31
aoc_utils/intervals.py
Normal file
31
aoc_utils/intervals.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
class Interval:
|
||||||
|
"""Définit des intervalles de $\\mathbb{R}$"""
|
||||||
|
def __init__(self, a: float, b: float) -> None:
|
||||||
|
assert a <= b
|
||||||
|
|
||||||
|
self.low = a
|
||||||
|
self.up = b
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
if self.up == self.low:
|
||||||
|
return '{'+str(self.up)+'}'
|
||||||
|
return f"[{self.low}, {self.up}]"
|
||||||
|
|
||||||
|
def __len__(self) -> float:
|
||||||
|
return self.up - self.low
|
||||||
|
|
||||||
|
def __contains__(self, item: float) -> bool:
|
||||||
|
return self.low <= item and item <= self.up
|
||||||
|
|
||||||
|
def __eq__(self, interval):
|
||||||
|
return self.low == interval.low and self.up == interval.up
|
||||||
|
|
||||||
|
def intersect(self, interval) -> bool:
|
||||||
|
return not (interval.low > self.up or self.low > interval.up)
|
||||||
|
|
||||||
|
def intersection(self, interval):
|
||||||
|
if interval.low > self.up or self.low > interval.up:
|
||||||
|
return None
|
||||||
|
new_min = max(self.low, interval.low)
|
||||||
|
new_max = min(self.up, interval.up)
|
||||||
|
return Interval(new_min, new_max)
|
48
aoc_utils/snippets.py
Normal file
48
aoc_utils/snippets.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
Nb = TypeVar("Nb", int, float)
|
||||||
|
|
||||||
|
|
||||||
|
def lagrange_interpolation(points: list[tuple[Nb, Nb]], x0: Nb) -> int:
|
||||||
|
result = 0
|
||||||
|
for i in range(len(points)):
|
||||||
|
temp = points[i][1]
|
||||||
|
for j in range(len(points)):
|
||||||
|
if j != i:
|
||||||
|
temp *= (x0 - points[j][0]) / (points[i][0] - points[j][0])
|
||||||
|
|
||||||
|
result += temp
|
||||||
|
|
||||||
|
return int(result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def area(points: list[tuple[Nb, Nb]], count_border: bool=True) -> int:
|
||||||
|
def distance(p1: tuple[Nb, Nb], p2: tuple[Nb, Nb]) -> float:
|
||||||
|
return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
|
||||||
|
|
||||||
|
def get_info(x1: Nb, y1: Nb, x2: Nb, y2: Nb) -> Nb:
|
||||||
|
return x1*y2 - y1*x2
|
||||||
|
|
||||||
|
def inner_area() -> float:
|
||||||
|
first_x, first_y = points[0]
|
||||||
|
prev_x, prev_y = first_x, first_y
|
||||||
|
res = 0
|
||||||
|
|
||||||
|
for i in range(len(points)-1):
|
||||||
|
next_x, next_y = points[i+1]
|
||||||
|
res = res + get_info(prev_x, prev_y, next_x, next_y)
|
||||||
|
prev_x = next_x
|
||||||
|
prev_y = next_y
|
||||||
|
res = res + get_info(prev_x, prev_y, first_x, first_y)
|
||||||
|
return abs(res)/2.0
|
||||||
|
|
||||||
|
def border() -> float:
|
||||||
|
distances = [distance(points[i], points[i+1]) for i in range(len(points)-1)]
|
||||||
|
distances.append(distance(points[-1], points[0]))
|
||||||
|
return sum(distances)
|
||||||
|
|
||||||
|
if count_border:
|
||||||
|
return int(inner_area()+border()//2 +1)
|
||||||
|
|
||||||
|
return int(inner_area())
|
Loading…
x
Reference in New Issue
Block a user