🌟 Advent of Code (AoC) 2023 🌟

PermalÀnk
Datavetare ★
●

Dag: 20
SprÄk: Python

Har haft klar separation mellan del 1 och del 2 alla andra dagar, men blev tillrÀckligt mycket enklare att köra bÄda samtidigt för att göra ett avsteg denna gÄng...

from collections import deque from math import lcm def parse_configuration(input): modules, inputs = {}, {} for line in input.split("\n"): action, targets = line.split(" -> ") outs = targets.split(", ") modules[action] = outs for out in outs: action = action[1:] if action[0] in "&%" else action inputs[out] = inputs.get(out, []) + [action] config = {} for action, targets in modules.items(): if action[0] == "%": # flip-flop {action: [target, STATE]} config[action[1:]] = [targets, False] elif action[0] == "&": # conjunction {action: [target, {INPUTS_NAME_TO_STATE}]} config[action[1:]] = [targets, {input: False for input in inputs[action[1:]]}] else: # broadcaster config[action] = [targets, None] return config def push_button(config, numButtonPresses, rxFanInFirstFalsePulses): pendingPulses = deque() pendingPulses.append(("button", False, "broadcaster")) lowPulses, highPules = 0, 0 while pendingPulses: sender, inLevel, action = pendingPulses.popleft() if inLevel: highPules += 1 else: lowPulses += 1 if action not in config: continue outputs, state = config[action] if state is None: # broadcaster outLevel = inLevel elif isinstance(state, bool): # flip-flop if inLevel is False: outLevel = not state config[action][1] = outLevel else: continue else: # conjunction state[sender] = inLevel outLevel = not all(state.values()) if inLevel and "rx" in outputs and sender not in rxFanInFirstFalsePulses: rxFanInFirstFalsePulses[sender] = numButtonPresses for output in outputs: pendingPulses.append((action, outLevel, output)) return lowPulses, highPules def run_config(config): lowPulses, highPules = 0, 0 buttonPresses = 0 rxFanInFirstFalsePulses = {} while len(rxFanInFirstFalsePulses) < 4: buttonPresses += 1 pulses = push_button(config, buttonPresses, rxFanInFirstFalsePulses) if buttonPresses <= 1000: lowPulses += pulses[0] highPules += pulses[1] return lowPulses * highPules, lcm(*rxFanInFirstFalsePulses.values()) def solve(input): config = parse_configuration(input) pulseProduct, minButtonPresses = run_config(config) print(pulseProduct) print(minButtonPresses) if __name__ == "__main__": solve(open("input/day20.txt").read())

Dold text
edit: min input visualiserad...
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem
●

Dag 19 (Del 1 & 2)
SprÄk: Java
GitHub

Del 2 var ganska klurig, kunde inte anvÀnda del 1 för del 2, sÄ jag gjorde om hela programmet.

Ligger lite efter, Àr fortfarande lite förvirrad frÄn dag 17. Har aldrig implemeterat Dijkstra förrut.. sÄ det gick inte sÄ bra.

PermalÀnk
Datavetare ★
●

Dag: 21
SprÄk: Python

Fattade att man behövde rÀkna ut nÄgon typ av formel för del 2, redan lÄga hundratals steg tar flertalet sekunder att berÀkna och Àr uppenbart frÄn problemstÀllningen att komplexiteten Àr O(N2) för "brute-force".

Vet inte om det finns andra lösningar, enda jag kunde komma pÄ Àr berÀkna en kvadratisk funktion (arean pÄ ytan som de positioner man kan befinna sig efter N steg ökar kvadratiskt). Problemet med det Àr att en sÄdan anpassning Àr specifik för varje step modulus storleken pÄ trÀdgÄrden...

Man fÄr rÀkna ut hur mÄnga steg som behövs frÄn still start till man befinner sig pÄ en punkt dÀr det Àr en jÀmn multipel av "storleken pÄ trÀdgÄrden" steg till slutmÄlet pÄ 26501365 steg.

GÄr att förstÄ lite bÀttre om man ritar en bild pÄ de tre första "storleken pÄ trÀdgÄrden" steg

Första N=64

Andra N=196

Tredje N=327

import numpy as np def print_garden(garden, positions, fn): d = len(garden) r = (-d*2, d*3, 1) with open(fn, "w") as f: f.write(f"P2\n# {fn}\n{r[1]-r[0]} {r[1]-r[0]}\n3\n") for y in range(*r): for x in range(*r): if (x, y) in positions: f.write("1") elif tile(garden, (x, y)) == "#": f.write("0") else: f.write("3") f.write(" ") f.write("\n") def parse_garden(input): garden = input.split("\n") for y, row in enumerate(garden): x = row.find("S") if x >= 0: start = (x, y) garden[y] = row.replace("S", ".") break return garden, start def garden_plots_reached(garden, start, stepsToRecord): positions = set() reachable = set() positions.add(start) numPositions = [] for step in range(1, 1 + max(stepsToRecord)): for position in positions: for adjacentPosition in adj(position): if adjacentPosition not in reachable and tile(garden, adjacentPosition) != "#": reachable.add(adjacentPosition) positions, reachable = reachable, positions if step in stepsToRecord: numPositions.append(len(positions)) print_garden(garden, positions, f"step{step}.pgm") return numPositions def adj(pos): for dX, dY in [(-1, 0), (0, 1), (1, 0), (0, -1)]: yield (pos[0] + dX, pos[1] + dY) def tile(garden, position): x, y = position dim = len(garden) return garden[y % dim][x % dim] def garden_plots_reached_predict(garden, start, steps): # PlotReached(fullGardensToPass) = a + b * fullGardensToPass + c * fullGardensToPass^2 gardenSize = len(garden) fullGardensToPass = steps // gardenSize stepsToEvenMultipleOfFullGardens = steps % gardenSize # Calculate number of steps for the first 3 full garden extensions, minimum needed to uniquely fix a, b and c samples = list(range(3)) A = np.matrix(list([1, s, s**2] for s in samples)) Y = garden_plots_reached( garden, start, [stepsToEvenMultipleOfFullGardens + gardenSize * s for s in samples]) X = np.linalg.solve(A, np.array(Y)).astype(np.int64).tolist() a, b, c = X return a + b * fullGardensToPass + c * fullGardensToPass**2 def solve(input): garden, start = parse_garden(input) print(garden_plots_reached(garden, start, [64])[0]) print(garden_plots_reached_predict(garden, start, 26501365)) if __name__ == "__main__": solve(open("input/day21.txt").read())

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Hedersmedlem ★
●

Dag: 24, del 1
SprÄk: Python (med numpy)
Lösning:

import re import operator import itertools import numpy as np def is_in_future(curr, initial_pos, vel): x_comp = operator.lt if vel[0] < 0 else operator.gt y_comp = operator.lt if vel[1] < 0 else operator.gt return x_comp(curr[0], initial_pos[0]) and y_comp(curr[1], initial_pos[1]) def solve(lines): num_regex = re.compile(r'(-?\d+)') equations = [] for line in lines: px, py, pz, vx, vy, vz = map(int, num_regex.findall(line)) # Calculate the equation for this line (y = mx + b) # 20x is to fix floating-point rounding issues; 1x gives a too low answer eq = np.polynomial.Polynomial.fit([px, px + 20*vx], [py, py + 20*vy], deg=1).convert() equations.append((eq, (px, py), (vx, vy))) num_collisions = 0 for ((a, initial_a, vel_a), (b, initial_b, vel_b)) in itertools.combinations(equations, 2): roots = (a - b).roots() if roots.size == 0: continue x = roots[0] y = a(x) min_pos = 200000000000000 max_pos = 400000000000000 if min_pos <= x <= max_pos and min_pos <= y <= max_pos: if is_in_future((x, y), initial_a, vel_a) and is_in_future((x, y), initial_b, vel_b): num_collisions += 1 return (num_collisions, 0) if __name__=='__main__': lines = open('data/day24.txt').read().splitlines() part1, part2 = solve(lines) print(f"Part 1: {part1}")

Dold text

Surt, min algoritm var i princip korrekt rÀtt lÀnge, men jag fick samma felaktiga svar under typ en timmes felsökning pga flyttalens under... grrr.

Detaljer samt frÄga (ang matten, och/eller numpy):

Jag tog (px, py) man fick frÄn problemet samt (px + vx, py + vy) som en till punkt, sedan rÀknade jag ut linjens ekvation frÄn de tvÄ punkterna... det gav ett svar som sÄg rimligt ut, och visade sig vara inom 0.06% frÄn rÀtt, men ÀndÄ fel.
Att helt enkelt ta (px + 4*vx, py + 4*vy) som andra punkt gav rÀtt svar.

Jag Àr dock rÀtt övertygad om att det gÄr att lösa snyggare, men detta Àr andra gÄngen jag kör numpy nÄgonsin. Har nÄgon nÄgot tips?

Dold text

Del 2 ger jag mig inte ens pÄ förrÀn julfirandet Àr klart.

Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
NAS: 6700K/16GB/Debian+ZFS | Backup (offsite): 9600K/16GB/Debian+ZFS