From 5c55af6ae0efeae489f0c96146ce5bbcfc11ae24 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Sat, 23 Dec 2023 18:59:54 +0100 Subject: [PATCH] Factorise some code into snippets.py --- 2023/day08.py | 19 +++++------------ 2023/day12.py | 21 +++++-------------- 2023/day18.py | 28 ++++--------------------- 2023/day21.py | 21 +++++-------------- aoc_utils/snippets.py | 48 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 70 deletions(-) create mode 100644 aoc_utils/snippets.py diff --git a/2023/day08.py b/2023/day08.py index dbd3dba..ee41961 100755 --- a/2023/day08.py +++ b/2023/day08.py @@ -3,6 +3,7 @@ Jour 08 du défi Advent Of Code pour l'année 2023 """ import os +import math def read_sample(): """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 != '' ] 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): instructions = sample[0] @@ -34,6 +22,7 @@ def parse_sample(sample): } return instructions, mappings + def number_steps(instructions, mappings, pos, untilZZZ=True): step = 0 instr = { @@ -44,6 +33,8 @@ def number_steps(instructions, mappings, pos, untilZZZ=True): step += 1 return step + + def part1(sample): """Partie 1 du défi""" instructions, mappings = parse_sample(sample) @@ -54,7 +45,7 @@ def part2(sample): instructions, mappings = parse_sample(sample) 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] - return lcm_of_list(steps) + return math.lcm(*steps) def main(): diff --git a/2023/day12.py b/2023/day12.py index d8743cc..4f0443d 100755 --- a/2023/day12.py +++ b/2023/day12.py @@ -3,8 +3,9 @@ Jour 12 du défi Advent Of Code pour l'année 2023 """ import os -from functools import cache, wraps -from time import time +from functools import cache + +from aoc_utils import decorators def read_sample(): """récupère les entrées depuis le fichier texte correspondant""" @@ -24,18 +25,6 @@ def parse_sample(sample): 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): @@ -114,7 +103,7 @@ def unfold(springs, counts): counts[i] = counts[i]*5 -@timing +@decorators.timeit def part1(sample): """Partie 1 du défi""" springs, counts = parse_sample(sample) @@ -125,7 +114,7 @@ def part1(sample): return sum(possibilities) -@timing +@decorators.timeit def part2(sample): """Partie 2 du défi""" springs, counts = parse_sample(sample) diff --git a/2023/day18.py b/2023/day18.py index 96d398e..f6a6ce7 100755 --- a/2023/day18.py +++ b/2023/day18.py @@ -4,6 +4,8 @@ Jour 18 du défi Advent Of Code pour l'année 2023 """ import os +from aoc_utils import snippets + directions = { "R": (0, 1), "L": (0, -1), @@ -107,29 +109,6 @@ def print_terrain(terrain): 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) @@ -140,7 +119,8 @@ 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) + points = [i[0] for i in terrain] + return snippets.area(points) def main(): diff --git a/2023/day21.py b/2023/day21.py index 94beda8..90f0b75 100755 --- a/2023/day21.py +++ b/2023/day21.py @@ -3,7 +3,8 @@ Jour 21 du défi Advent Of Code pour l'année 2023 """ import os -from aoc_utils.decorators import timeit + +from aoc_utils import decorators, snippets def read_sample(): """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 -def lagrange_interpolation(points, x0): - 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 +@decorators.timeit def part1(sample): """Partie 1 du défi""" return len(do_steps(sample, steps=64, ext=False)) -@timeit +@decorators.timeit def part2(sample): """Partie 2 du défi""" def challenge(steps): @@ -93,7 +82,7 @@ def part2(sample): (half_size+size, challenge(half_size+size)), (half_size+2*size, challenge(half_size+2*size)) ] - return lagrange_interpolation(points, 26501365) + return snippets.lagrange_interpolation(points, 26501365) diff --git a/aoc_utils/snippets.py b/aoc_utils/snippets.py new file mode 100644 index 0000000..fab4ff2 --- /dev/null +++ b/aoc_utils/snippets.py @@ -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())