From 94d71c90713ba9a779071a42005080d827a64d52 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Fri, 1 Dec 2023 10:54:02 +0100 Subject: [PATCH] Add 2022 --- 2022/day13.py | 91 +++++++++++++++++++++++++ 2022/day14.py | 116 ++++++++++++++++++++++++++++++++ 2022/day15.py | 159 ++++++++++++++++++++++++++++++++++++++++++++ 2022/day16.py | 77 ++++++++++++++++++++++ 2022/day18.py | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2022/day21.py | 140 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 762 insertions(+) create mode 100755 2022/day13.py create mode 100755 2022/day14.py create mode 100755 2022/day15.py create mode 100755 2022/day16.py create mode 100755 2022/day18.py create mode 100755 2022/day21.py diff --git a/2022/day13.py b/2022/day13.py new file mode 100755 index 0000000..e8c75c5 --- /dev/null +++ b/2022/day13.py @@ -0,0 +1,91 @@ +#!/usr/bin/python3 +""" +Jour 13 du défi Advent Of Code pour l'année 2022 +""" +import functools + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day13.txt', 'r') as f: + sample = f.read().split('\n\n') + sample = [ [eval(j) for j in i.split('\n') if j != ''] for i in sample if i != '' ] + return sample + +def is_right_order(elem1, elem2): + if type(elem1) == type(0) and type(elem2) == type(0): # two ints + if elem1 == elem2: + return None + return elem1 < elem2 + + if type(elem1) == type([]) and type(elem2) == type([]): # two lists + if len(elem1) == 0: + return True + + for i in range(len(elem1)): + if i > len(elem2)-1: + return False # Out + + order = is_right_order(elem1[i], elem2[i]) + if order is not None: + return order + + return is_right_order(len(elem1), len(elem2)) + + if type(elem1) == type(0) and type(elem2) == type([]): + return is_right_order([elem1], elem2) + + if type(elem2) == type(0) and type(elem1) == type([]): + return is_right_order(elem1, [elem2]) + + + + +def part1(sample): + """Partie 1 du défi""" + somme = 0 + for i in range(len(sample)): + order = is_right_order(sample[i][0], sample[i][1]) + if order is None: + order = True + if order: + somme += i+1 + return somme + +def part2(sample): + """Partie 2 du défi""" + n_sample = [] + for i in sample: + for j in i: + n_sample.append(j) + n_sample.append([[2]]) + n_sample.append([[6]]) + def comparaison(x, y): + order = is_right_order(x, y) + if order is None: + return 0 + if order: + return 1 + return -1 + + keys = functools.cmp_to_key(comparaison) + n_sample = sorted(n_sample, key=keys) + n_sample.reverse() + + tot = 1 + for ind in range(len(n_sample)): + i = n_sample[ind] + if len(i)==1 and isinstance(i[0], list) and len(i[0])==1 and i[0][0]==2: + tot *= ind+1 + elif len(i)==1 and isinstance(i[0], list) and len(i[0])==1 and i[0][0]==6: + tot *= ind+1 + return tot + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(read_sample())}") + print(f"part2: {part2(read_sample())}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/2022/day14.py b/2022/day14.py new file mode 100755 index 0000000..375a766 --- /dev/null +++ b/2022/day14.py @@ -0,0 +1,116 @@ +#!/usr/bin/python3 +""" +Jour 14 du défi Advent Of Code pour l'année 2022 +""" + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day14.txt', 'r') as f: + sample = f.read().split('\n') + sample = [ [eval(j) for j in i.split(" -> ")] for i in sample if i != '' ] + return [[(j[1], j[0]) for j in i] for i in sample] + +def create_map(sample): + maxi_0 = max([max([j[0] for j in i]) for i in sample])+1 + maxi_1 = max([max([j[1] for j in i]) for i in sample])+120 + + map_ = [['.' for _ in range(maxi_1)] for _ in range(maxi_0)] + for line in sample: + for i in range(len(line)-1): + if line[i][0] == line[i+1][0]: + for j in range(min(line[i][1], line[i+1][1]), max(line[i][1], line[i+1][1])+1): + map_[line[i][0]][j] = '#' + else: + for j in range(min(line[i][0], line[i+1][0]), max(line[i][0], line[i+1][0])+1): + map_[j][line[i][1]] = '#' + return map_ + +def print_map(map_, sample): + mini = min([min([j[1] for j in i]) for i in sample])-15 + for i in range(len(map_)): + print(i, "".join(map_[i][mini:])) + +def make_sand_fall(map_, sand_source): + sand_pos = sand_source + while(sand_pos[0] >= 0 and sand_pos[0] < len(map_) and sand_pos[1] >= 0 and sand_pos[1] < len(map_[0])): + try: + if map_[sand_pos[0]+1][sand_pos[1]] == '.': + sand_pos = (sand_pos[0]+1, sand_pos[1]) + elif map_[sand_pos[0]+1][sand_pos[1]-1] == '.': + sand_pos = (sand_pos[0]+1, sand_pos[1]-1) + elif map_[sand_pos[0]+1][sand_pos[1]+1] == '.': + sand_pos = (sand_pos[0]+1, sand_pos[1]+1) + else: + map_[sand_pos[0]][sand_pos[1]] = 'o' + return True + except: + return False + + return False + + +def part1(sample): + """Partie 1 du défi""" + map_ = create_map(sample) + sand_source = (0,500) + + test = True + while (test): + test = make_sand_fall(map_, sand_source) + + #print_map(map_, sample) + + cpt = 0 + for k in map_: + for j in k: + if j == 'o': + cpt += 1 + return cpt + + +def create_map2(sample): + maxi_0 = max([max([j[0] for j in i]) for i in sample])+3 + maxi_1 = max([max([j[1] for j in i]) for i in sample])+1+maxi_0 # +maxi0 car put tomber sur les bords + + map_ = [['.' for _ in range(maxi_1)] for _ in range(maxi_0)] + for line in sample: + for i in range(len(line)-1): + if line[i][0] == line[i+1][0]: + for j in range(min(line[i][1], line[i+1][1]), max(line[i][1], line[i+1][1])+1): + map_[line[i][0]][j] = '#' + else: + for j in range(min(line[i][0], line[i+1][0]), max(line[i][0], line[i+1][0])+1): + map_[j][line[i][1]] = '#' + + for i in range(len(map_[0])): + map_[-1][i] = '#' + return map_ + + +def part2(sample): + """Partie 2 du défi""" + map_ = create_map2(sample) + + sand_source = (0,500) + test = True + while (test and map_[sand_source[0]][sand_source[1]] == '.'): + test = make_sand_fall(map_, sand_source) + + print_map(map_, sample) + + cpt = 0 + for k in map_: + for j in k: + if j == 'o': + cpt += 1 + return cpt + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(sample)}")# 1409 too low # 1515 too high + print(f"part2: {part2(sample)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/2022/day15.py b/2022/day15.py new file mode 100755 index 0000000..6d53378 --- /dev/null +++ b/2022/day15.py @@ -0,0 +1,159 @@ +#!/usr/bin/python3 +""" +Jour 15 du défi Advent Of Code pour l'année 2022 +""" +from tqdm import tqdm + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day15.txt', 'r') as f: + sample = f.read().split('\n') + sample = [ i for i in sample if i != '' ] + return sample + + +def parse_sample(sample): + sensors = [] + for line in sample: + spl = line.split(", ") + tmp1 = int(spl[0].split("x=")[1]) + tmp2 = int(spl[1].split("y=")[1].split(":")[0]) + tmp3 = int(spl[1].split("x=")[1]) + tmp4 = int(spl[2].split("y=")[1].split(":")[0]) + sensors.append(((tmp1, tmp2), (tmp3, tmp4))) + return sensors + + +def intersection(seg1, seg2): + seg = [] + for line in seg1: + added = False + for line2 in seg2: + if line[0] >= line2[0] and line[1] <= line2[1]: + added = True + seg.append(line) + break + if not added: + for line2 in seg2: + if line[0] <= line2[1]: + seg.append((max(line2[0], line[0]), min(line[1], line2[1]))) + elif line[1] >= line2[0]: + None#yet + + return seg + +def overlapping_segment(a, b): + x = max(a[0], b[0]) + y = min(a[1], b[1]) + return x,y + + +def find_overlaps(r, b): + retVal = [] + ri = 0 + bi = 0 + while (ri < len(r)) and (bi < len(b)): + s = overlapping_segment(r[ri], b[bi]) + if s[0] < s[1]: + retVal.append([ri, bi]) + if r[ri][1] == s[1]: + ri += 1 + if b[bi][1] == s[1]: + bi += bi + 1 + return retVal + + +def taille_seg(segment): + taille = 0 + for i in segment: + taille += i[1]-i[0]+1 + return taille + +def manhattan(x, y): + return abs(x[0]-y[0]) + abs(x[1]-y[1]) + +def create_map(sensors): + maxi_x = max([x[0]+manhattan(x, y) for (x, y) in sensors]) + maxi_y = max([x[1]+manhattan(x, y) for (x, y) in sensors]) + + map_ = [['.' for _ in range(maxi_y)] for _ in range(maxi_x)] + for i in range(len(map_)): + for j in range(len(map_[0])): + for sensor in sensors: + if manhattan(sensor[0], sensor[1]) > manhattan(sensor[0], (i, j)): + map_[i][j] = '#' + + return map_ + + +def part1(sample): + """Partie 1 du défi""" + sensors = parse_sample(sample) + + maxi_y = max([x[1]+manhattan(x, y) for (x, y) in sensors]) + mini_y = min([x[1]-manhattan(x, y) for (x, y) in sensors]) + cpt = 0 + j = 10 + j=2000000 + seg = [(mini_y, maxi_y)] + for sensor in sensors: + d = manhattan(sensor[0], sensor[1]) + if d+sensor[0][0] >= j: + a = sensor[0][0] - j + d + print(seg) + print([(mini_y, sensor[0][1]-a), (sensor[0][1]+a, maxi_y)]) + seg = find_overlaps(seg, [(mini_y, sensor[0][1]-a), (sensor[0][1]+a, maxi_y)]) + print("=>",seg) + + if sensor[0][0]-d <= j: + a = -sensor[0][0] + j + d + #print([(mini_y, sensor[0][1]-a), (sensor[0][1]+a, maxi_y)]) + seg = find_overlaps(seg, [(mini_y, sensor[0][1]-a), (sensor[0][1]+a, maxi_y)]) + + print(seg, taille_seg(seg)) + taille = taille_seg(seg) + + + """ + for i in range(mini_y, maxi_y): + for sensor in sensors: + if manhattan(sensor[0], sensor[1]) >= manhattan(sensor[0], (i, j)): + if True not in [ a==i and b==j for ((_, _), (a, b)) in sensors ]: + cpt += 1 + break + """ + return (maxi_y-mini_y)-taille + +def part2(sample): + """Partie 2 du défi""" + sensors = parse_sample(sample) + + maxi = 4000000 + #maxi = 20 + + dists = {} + for i in range(len(sensors)): + dists[i] = manhattan(sensors[i][0], sensors[i][1]) + + for i in tqdm(range(maxi)): + for j in range(maxi): + test = True + for k in range(len(sensors)): + if test: + if dists[k] >= manhattan(sensors[k][0], (i, j)): + test = False + + if test: + return (i, j) + + + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(sample)}") + print(f"part2: {part2(read_sample())}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/2022/day16.py b/2022/day16.py new file mode 100755 index 0000000..379d75f --- /dev/null +++ b/2022/day16.py @@ -0,0 +1,77 @@ +#!/usr/bin/python3 +""" +Jour 16 du défi Advent Of Code pour l'année 2022 +""" +import copy + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day16.txt', 'r') as f: + sample = f.read().split('\n') + sample = [ i for i in sample if i != '' ] + data = [] + for line in sample: + split = line.split(" ") + "Valve AA has flow rate=0; tunnels lead to valves DD, II, BB" + valve_nb = split[1] + flow_rate = int(split[4].split("=")[-1].split(";")[0]) + lead_to = " ".join(split[9:]).split(", ") + data.append((valve_nb, flow_rate, lead_to)) + return data + + +def floyd_warshall(valves): + dist = {v: {u: int(1e9) for u in valves} for v in valves} + for v in valves: + dist[v][v] = 0 + for u in valves[v]["lead_to"]: + dist[v][u] = 1 + for k in valves: + for i in valves: + for j in valves: + dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]) + return dist + + +def part1(sample): + """Partie 1 du défi""" + data = {} + for i in sample: + data[i[0]] = {"enabled":False, "flow_rate": i[1], "lead_to": i[2]} + + distances = floyd_warshall(data) + non_zero = [v for v in data if data[v]["flow_rate"] > 0] + + def generate_open_options(pos, opened, time_left): + for next in non_zero: + if next not in opened and distances[pos][next] <= time_left: + opened.append(next) + yield from generate_open_options( + next, opened, time_left - distances[pos][next] - 1 + ) + opened.pop() + yield copy.copy(opened) + + def get_order_score(open_order, time_left): + now, ans = "AA", 0 + for pos in open_order: + time_left -= distances[now][pos] + 1 + ans += data[pos]["flow_rate"] * time_left + now = pos + return ans + + return max(get_order_score(ordre, 30) for ordre in generate_open_options("AA", [], 30)) + +def part2(sample): + """Partie 2 du défi""" + return NotImplementedError + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(sample)}") + print(f"part2: {part2(sample)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/2022/day18.py b/2022/day18.py new file mode 100755 index 0000000..2079e96 --- /dev/null +++ b/2022/day18.py @@ -0,0 +1,179 @@ +#!/usr/bin/python3 +""" +Jour 18 du défi Advent Of Code pour l'année 2022 +""" +import copy + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day18.txt', 'r') as f: + #with open('test.txt', 'r') as f: + sample = f.read().split('\n') + sample = [ (int(i.split(",")[0]), int(i.split(",")[1]), int(i.split(",")[2])) for i in sample if i != '' ] + return sample + +def nb_voisins(cube, sample): + vois = 0 + if (cube[0]-1, cube[1], cube[2]) in sample: + vois += 1 + if (cube[0]+1, cube[1], cube[2]) in sample: + vois += 1 + if (cube[0], cube[1]-1, cube[2]) in sample: + vois += 1 + if (cube[0], cube[1]+1, cube[2]) in sample: + vois += 1 + if (cube[0], cube[1], cube[2]-1) in sample: + vois += 1 + if (cube[0], cube[1], cube[2]+1) in sample: + vois += 1 + + return vois + + +def nb_voisins2(cube, sample, carte, num): + vois = 0 + x, y, z = cube + if (x-1, y, z) in sample and carte[x-1][y][z] == num: + vois += 1 + if (x+1, y, z) in sample and carte[x+1][y][z] == num: + vois += 1 + if (x, y-1, z) in sample and carte[x][y-1][z] == num: + vois += 1 + if (x, y+1, z) in sample and carte[x][y+1][z] == num: + vois += 1 + if (x, y, z-1) in sample and carte[x][y][z-1] == num: + vois += 1 + if (x, y, z+1) in sample and carte[x][y][z+1] == num: + vois += 1 + + return vois + + +def part1(sample): + """Partie 1 du défi""" + sides = 6*len(sample) + for cube in sample: + sides -= nb_voisins(cube, sample) + return sides + + + +def print_cubes(sample, carte=None): + min_x, max_x = 0, max([i[0] for i in sample])+2 + min_y, max_y = 0, max([i[1] for i in sample])+2 + min_z, max_z = 0, max([i[2] for i in sample])+2 + + for z in range(min_z, max_z): + print(f"\n--- Couche {z} ---\n") + for y in range(min_x, max_x): + for x in range(min_x, max_x): + if carte is not None and carte[x][y][z] == 2: + print("%", end="") + elif (x, y, z) in sample: + print("#", end="") + elif carte is not None and carte[x][y][z] == 1: + print('.', end="") + else: + print(" ", end="") + print() + + +def init_propagation(carte): + for x in range(len(carte)): + for y in range(len(carte[0])): + for z in range(len(carte[0][0])): + if x == 0 or y == 0 or z == 0 or x == len(carte)-1 or y == len(carte[0])-1 or z == len(carte[0][0])-1: + carte[x][y][z] = 1 + + +def propagation(cart, sample): + carte = copy.deepcopy(cart) + modif = False + for x in range(len(carte)): + for y in range(len(carte[0])): + for z in range(len(carte[0][0])): + bon = False + if not(x == 0 or y == 0 or z == 0 or x == len(carte)-1 or y == len(carte[0])-1 or z == len(carte[0][0])-1 or cart[x][y][z] != 0): + if cart[x-1][y][z]==1: + bon = True + elif cart[x+1][y][z]==1: + bon = True + elif cart[x][y+1][z]==1: + bon = True + elif cart[x][y-1][z]==1: + bon = True + elif cart[x][y][z+1]==1: + bon = True + elif cart[x][y][z+1]==1: + bon = True + if bon: + if (x, y, z) in sample: + carte[x][y][z] = 2 + else: + carte[x][y][z] = 1 + modif = True + return modif, carte + + +def part2(sample): + """Partie 2 du défi, simule l'eau qui se propage""" + min_x, max_x = 0, max([i[0] for i in sample])+2 + min_y, max_y = 0, max([i[1] for i in sample])+2 + min_z, max_z = 0, max([i[2] for i in sample])+2 + carte = [[[0 for z in range(min_z, max_z)] for y in range(min_y, max_y)] for x in range(min_x, max_x)] + + init_propagation(carte) + test, carte = propagation(carte, sample) + while(test): + test, carte = propagation(carte, sample) + None + + sides = part1(sample) + for x in range(len(carte)): + for y in range(len(carte[0])): + for z in range(len(carte[0][0])): + if carte[x][y][z] == 0: + sides -= nb_voisins2((x, y, z), sample, carte, 2) + + return sides + + + +def is_exterior(cube, sample): + if nb_voisins(cube, sample) == 6: + return False + if cube[0] == min([i[0] for i in sample if (i[1], i[2])==(cube[1], cube[2])]): + return True + if cube[0] == max([i[0] for i in sample if (i[1], i[2])==(cube[1], cube[2])]): + return True + if cube[1] == min([i[1] for i in sample if (i[0], i[2])==(cube[0], cube[2])]): + return True + if cube[1] == max([i[1] for i in sample if (i[0], i[2])==(cube[0], cube[2])]): + return True + if cube[2] == min([i[2] for i in sample if (i[0], i[1])==(cube[0], cube[1])]): + return True + if cube[2] == max([i[2] for i in sample if (i[0], i[1])==(cube[0], cube[1])]): + return True + + return False + +def part2_old(sample): + """Partie 2 du défi""" + """Ne regarde que les extrema, omet des résultats""" + sides = 6*len(sample) + for cube in sample: + if not is_exterior(cube, sample): + sides -= 6 + else: + sides -= nb_voisins(cube, sample) + return sides + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(sample)}") + print(f"part2: {part2(sample)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/2022/day21.py b/2022/day21.py new file mode 100755 index 0000000..e833b19 --- /dev/null +++ b/2022/day21.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 +""" +Jour 21 du défi Advent Of Code pour l'année 2022 +""" +from tqdm import tqdm + +def read_sample(): + """récupère les entrées depuis le fichier texte correspondant""" + with open('inputs/day21.txt', 'r') as f: + #with open('test.txt', 'r') as f: + sample = f.read().split('\n') + sample = [ Monkey(i) for i in sample if i != '' ] + return sample + + + +class Monkey(): + def __init__(self, data): + self.name = data.split(": ")[0] + self.has_yelled = False + self.value = -1 + if len(data.split(": ")[1].split(" ")) == 1: + self.dependencies = [] + self.operation = lambda x : int(data.split(": ")[1]) + + else: + self.dependencies = [data.split(": ")[1].split(" ")[0], data.split(": ")[1].split(" ")[2]] + self.operator = data.split(': ')[1].split(' ')[1] + self.operation = lambda deps: eval(f"deps[0] {data.split(': ')[1].split(' ')[1]} deps[1]") + + def evaluate(self, data): + if len(self.dependencies) == 0: + self.has_yelled = True + self.value = self.operation(0) + return + + for name in self.dependencies: + monkey = data[name] + if not monkey.has_yelled: + monkey.evaluate(data) + + self.has_yelled = True + self.value = self.operation((data[self.dependencies[0]].value, data[self.dependencies[1]].value)) + + def get_recursive_dependencies(self, data): + if len(self.dependencies) == 0: + return [self.name] + + return data[self.dependencies[0]].get_recursive_dependencies(data) + data[self.dependencies[1]].get_recursive_dependencies(data) + [self.name] + + def find_value(self, value, name, data): + if self.name == name: + return int(value) + + if name in data[data[self.name].dependencies[0]].get_recursive_dependencies(data): + change_me = data[data[self.name].dependencies[0]] + other = data[data[self.name].dependencies[1]] + else: + change_me = data[data[self.name].dependencies[1]] + other = data[data[self.name].dependencies[0]] + + other.evaluate(data) + if self.operator == '*': + return int(change_me.find_value(value/other.value, name, data)) + if self.operator == '+': + return int(change_me.find_value(value-other.value, name, data)) + + if change_me.name == data[data[self.name].dependencies[1]]: + if self.operator == '/': + return int(change_me.find_value(other.value/value, name, data)) + if self.operator == '-': + return int(change_me.find_value(other.value-value, name, data)) + + if self.operator == '/': + return int(change_me.find_value(other.value*value, name, data)) # Not really) + if self.operator == '-': + return int(change_me.find_value(other.value+value, name, data)) + + + +def part1(sample): + """Partie 1 du défi""" + data = {} + for monkey in sample: + data[monkey.name] = monkey + + data["root"].evaluate(data) + return data["root"].value + + + +def part2_brute(): + """Partie 2 du défi""" + """Relativement lent, mais l'approche par brute force finit par fonctionner""" + for i in tqdm(range(3876907167494-5, 3876907167494+5)): + sample = read_sample() + data = {} + for monkey in sample: + data[monkey.name] = monkey + + data["humn"].value = i + data["humn"].has_yelled = True + + data[data["root"].dependencies[0]].evaluate(data) + data[data["root"].dependencies[1]].evaluate(data) + if data[data["root"].dependencies[0]].value == data[data["root"].dependencies[1]].value: + return i + + return NotImplementedError + +def part2(sample): + """Partie 2 du défi""" + """Ne fonctionne pas""" + + data = {} + for monkey in sample: + data[monkey.name] = monkey + + + if "humn" in data[data["root"].dependencies[0]].get_recursive_dependencies(data): + humn = data[data["root"].dependencies[0]] + other = data[data["root"].dependencies[1]] + else: + humn = data[data["root"].dependencies[1]] + other = data[data["root"].dependencies[0]] + + other.evaluate(data) + return humn.find_value(other.value, "humn", data) + + + +def main(): + """Fonction principale""" + sample = read_sample() + print(f"part1: {part1(sample)}") + print(f"part2: {part2(read_sample())}") + print(f"part2 bruteforce: {part2_brute()}") + +if __name__ == "__main__": + main() \ No newline at end of file