From de308443f4ed4e12cd18578af09b93d7d01e2a84 Mon Sep 17 00:00:00 2001 From: bthink Date: Fri, 12 Dec 2025 12:42:43 +0100 Subject: final week of 2025 --- 2025/aoc2025-d08.py | 69 ++++++++++++++++++++++++++++++++++++++++ 2025/aoc2025-d09.py | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2025/aoc2025-d10.py | 76 +++++++++++++++++++++++++++++++++++++++++++ 2025/aoc2025-d11.py | 35 ++++++++++++++++++++ 2025/aoc2025-d12.py | 39 +++++++++++++++++++++++ 5 files changed, 311 insertions(+) create mode 100644 2025/aoc2025-d08.py create mode 100644 2025/aoc2025-d09.py create mode 100644 2025/aoc2025-d10.py create mode 100644 2025/aoc2025-d11.py create mode 100644 2025/aoc2025-d12.py diff --git a/2025/aoc2025-d08.py b/2025/aoc2025-d08.py new file mode 100644 index 0000000..2e053eb --- /dev/null +++ b/2025/aoc2025-d08.py @@ -0,0 +1,69 @@ +#advent of code 2025 +#day 08 + +def getDistance(j1,j2): + jx1,jy1,jz1=j1; + jx2,jy2,jz2=j2; + euclid=(jx2-jx1)*(jx2-jx1) + (jy2-jy1)*(jy2-jy1) + (jz2-jz1)*(jz2-jz1); + #no real need to take square root since if a^2 > b^2 then a > b + #no negatives since it's distance + return euclid; +#parsing +boxes=[]; +limit=1000; #10 for example +PuzzleInput=open("08.in","r"); +for line in PuzzleInput: + boxes.append(tuple([int(p) for p in line.split(",")])); +PuzzleInput.close(); + +numberOfBoxes=len(boxes); +distances=set(); +for bi1,b1 in enumerate(boxes): + for bi2,b2 in enumerate(boxes): + if bi2==bi1:continue; + d1=getDistance(b1,b2); + distances.add((d1,tuple(sorted((b1,b2))) ) ); +distances=sorted(distances,key=lambda m: m[0]); + +circuits=dict(); +for di in range(len(distances)): + d,boxtuple=distances[di]; + box1,box2=boxtuple; + if box1 not in circuits and box2 not in circuits: + circuits[box1]=set([box1,box2]); #first box contains the circuit + circuits[box2]=box1; #second box links to first one + elif box1 in circuits and box2 not in circuits: + b3=box1; #find the box which has the circuit set assigned in dictionary + while type(circuits[b3])!=set: + b3=circuits[b3]; + circuits[b3].add(box2); + circuits[box2]=b3; + elif box2 in circuits and box1 not in circuits: + b4=box2; + while type(circuits[b4])!=set: + b4=circuits[b4]; + circuits[b4].add(box1); + circuits[box1]=b4; + elif box2 in circuits and box1 in circuits: + b3=box1; + while type(circuits[b3])!=set: + b3=circuits[b3]; + b4=box2; + while type(circuits[b4])!=set: + b4=circuits[b4]; + if b3==b4: continue; + circuits[b3].update(circuits[b4]); + circuits[b4]=b3; + + clustering=sorted([len(circuits[cluster]) for cluster in circuits if type(circuits[cluster])==set],reverse=True); + if clustering[0]==numberOfBoxes: + part2=box1[0]*box2[0]; + break; + + if di==limit: + part1=1; + for i in range(3): + part1*=clustering[i]; + +print("part 1 =",part1, part1==103488); +print("part 2 =",part2, part2==8759985540); diff --git a/2025/aoc2025-d09.py b/2025/aoc2025-d09.py new file mode 100644 index 0000000..df7be78 --- /dev/null +++ b/2025/aoc2025-d09.py @@ -0,0 +1,92 @@ +#advent of code 2025 +#day 09 +#bit slow +#tried adding comments but will probably forget how it works anyway + +tiles=[]; +Ymax=0; +Xmax=0; +Ymin=10000000; +Xmin=10000000; +PuzzleInput=open("09.in","r"); +for l in PuzzleInput: + t=tuple([int(v) for v in l.split(",")]); + tiles.append(t); + Xmax=max(Xmax,t[0]); + Ymax=max(Ymax,t[1]); + Xmin=min(Xmin,t[0]); + Ymin=min(Ymin,t[1]); +PuzzleInput.close(); + +part1=0; +green=set(); +for ci1,corner1 in enumerate(tiles): + x1,y1=corner1; + for ci2,corner2 in enumerate(tiles): + if ci1==ci2: continue; + x2,y2=corner2; + area=(abs(x1-x2)+1)*(abs(y1-y2)+1); + part1=max(part1,area); + +part2=0; +#create the perimiter of the figure ("green" set) +#check how big is a distance between each tile +#tiles are ordered +delta=[(1,0),(0,1)] +distancedTiles=[]; +test=0; +maxdist=0; +for t in range(len(tiles)): + tile1=tiles[t]; + tile2=tiles[(t+1)%len(tiles)]; + for i in range(2): + if tile1[i]==tile2[i]: continue; + dx,dy=delta[i]; + steps=tile2[i]-tile1[i]; + dd=1*(steps>0) -1*(steps<0); + for step in range(abs(steps)): + green.add((tile1[0]+dx*dd*step,tile1[1]+dy*dd*step)); + distancedTiles.append((abs(steps),tile1,tile2,i)); + maxdist=max(maxdist,abs(steps)); +#sort the distances from longest to shortest +distancedTiles=sorted(distancedTiles,key=lambda m: m[0],reverse=True); +#check if the candidate "dt" isn't an order of 10 lower compared to biggest distance +#the biggest area has to be along the longest edge +candidates=[dt for dt in distancedTiles if maxdist//dt[0]<10]; +for can_i in range(len(candidates)): + candidate=candidates[can_i]; + d,can1,can2,can_orient=candidate; + orient_1=candidates[(can_i)%len(candidates)][1][(can_orient+1)%2]; + orient_2=candidates[(can_i+1)%len(candidates)][1][(can_orient+1)%2]; + + if orient_1 > orient_2: + lim_1=orient_1; + lim_2=Ymax+1; + else: + lim_1=0; + lim_2=orient_1+1; + + can=sorted([can1,can2],key=lambda m:m[0])[1] + otherCandidates=[ocand for ocand in tiles if ocand[(can_orient+1)%2] in range(lim_1,lim_2)]; + for ocand in otherCandidates: + #check if the X edge isn't in the way of perimiter (the longest edge doesn't count) + checkX=True; + for s in range(1+min(ocand[0],can[0]),max(ocand[0],can[0]) -1): + if can[0]==s: continue; + if (s,ocand[1]) in green: + checkX=False; + break; + if not checkX: continue; + #check if the Y edge isn't in the way of perimiter + checkY=True; + for s in range(1+min(ocand[1],can[1]),max(ocand[1],can[1]) -1): + if (can[0],s) in green: + checkY=False; + break; + if not checkY: continue; + + area2=(abs(can[0]-ocand[0])+1)*(abs(can[1]-ocand[1])+1); + part2=max(part2,area2); + +print("part 1 =",part1); +print("part 2 =",part2); diff --git a/2025/aoc2025-d10.py b/2025/aoc2025-d10.py new file mode 100644 index 0000000..17cb090 --- /dev/null +++ b/2025/aoc2025-d10.py @@ -0,0 +1,76 @@ +#advent of code 2025 +#day 10 +#can probably rewrite it from scratch instead of using z3 +#will try later +#part 1 is way too slow as well + +from z3 import * +import heapq + +machineInstructions=[]; +PuzzleInput=open("10.in","r"); +for l in PuzzleInput: + l=l.strip(); + diagram, residue=l.split("] "); + diagram=list([1*(light=="#") for light in diagram.replace("[","")]) + buttons, joltage = residue.split(" {"); + joltage=list([int(jolt) for jolt in joltage.replace("}","").split(",")]); + buttons=[tuple([int(but) for but in button.replace(")","").replace("(","").split(",")]) for button in buttons.split(" ")]; + machineInstructions.append((diagram, buttons, joltage)); +PuzzleInput.close(); + +#part 1 +def findSequence(machinstr): + target,options,power=machinstr; #power unused + state=[0 for t in target]; + visited=list(); + queue=[]; + heapq.heappush(queue,(0,state,[0 for b in range(len(options))])); + while queue: + presses,currentState,prevButtons=heapq.heappop(queue); + if currentState==target: + return presses; + if prevButtons in visited: + continue; + visited.append(prevButtons); + + for o in range(len(options)): + newstate=[cs for cs in currentState]; + for s in options[o]: + newstate[s]=(newstate[s]+1)%2; + newbuttons=[prevButtons[b]+1*(b==o) for b in range(len(prevButtons))]; + heapq.heappush(queue,(presses+1,newstate,newbuttons)); + return 999999; + +def adjustPower(machinstr): + lights,options,power=machinstr; #lights unused + buttons=[[1*(b in but) for b in range(len(power))] for but in options]; + solver=z3.Optimize(); + xVector=[z3.Int(f'x{x}') for x in range(len(buttons))]; + powerVector=[z3.Int(f'p{p}') for p in range(len(power))]; + + for x in range(len(buttons)): + solver.add(z3.Int(f'x{x}')>=0); + + for p in range(len(powerVector)): + solver.add(powerVector[p]==power[p]); + + for p in range(len(power)): + solver.add(powerVector[p]==z3.Sum([xVector[x] for x in range(len(buttons)) if buttons[x][p]==1])); + + solver.minimize(z3.Sum(xVector)); + solver.check(); + model=solver.model(); + presses=[model[mult].as_long() for mult in xVector]; + score=sum(presses); + return score + + +part1=0; +part2=0; + +for mi,instr in enumerate(machineInstructions): + part1+=findSequence(instr); + part2+=adjustPower(instr); +print("part 1",part1); +print("part 2",part2); diff --git a/2025/aoc2025-d11.py b/2025/aoc2025-d11.py new file mode 100644 index 0000000..86af8aa --- /dev/null +++ b/2025/aoc2025-d11.py @@ -0,0 +1,35 @@ +#advent of code 2025 +#day 11 +#more reading for later, maybe there's a different algo than dfs/bfs +# https://en.wikipedia.org/wiki/Directed_acyclic_graph +#no idea why my format doesn't work +#below is format which was shamelessly stolen from someone else +#don't sue me +#will rewrite it later as a product +#possible paths svr-fft; possible paths fft-dac; possible paths dac-out + +from functools import cache + +connections=dict(); +PuzzleInput=open("11.in","r"); +for l in PuzzleInput: + vertex,nodes=l.strip().split(": "); + if vertex not in connections: connections[vertex]=set(); + connections[vertex].update(nodes.split()) + +@cache +def findpaths(pos,fft,dac): + if pos=="out": + return 1*fft*dac; + score=0; + fft_=fft or pos=="fft"; + dac_=dac or pos=="dac"; + for con in connections[pos]: + score+=findpaths(con,fft_,dac_); + return score; + +part1=findpaths("you",True,True); +part2=findpaths("svr",False,False); + +print("part 1 =",part1); +print("part 2 =",part2); diff --git a/2025/aoc2025-d12.py b/2025/aoc2025-d12.py new file mode 100644 index 0000000..725144c --- /dev/null +++ b/2025/aoc2025-d12.py @@ -0,0 +1,39 @@ +#advent of code 2025 +#day 12 + +part1=0; +gifts=[]; +trees=[]; +ID=None; +PuzzleInput=open("12.in","r"); +for line in PuzzleInput: + line=line.strip(); + if "x" in line: + dimensions, quantities=line.split(": "); + dimensions=tuple([int(d) for d in dimensions.split("x")]); + quantities=[int(q) for q in quantities.split(" ")]; + trees.append((dimensions,quantities)); + elif ID==None: + ID=int(line.replace(":","")); + gifts.append([]); + elif len(line)==0: + ID=None; + else: + gifts[ID].append(list(line)); + +def validateTree(tree,presents): + grid,reqs=tree; + space=grid[0]*grid[1]; + minX,minY=0,0; + for ID,r in enumerate(reqs): + pr=presents[ID]; + dimY=max([pr[j].count("#") for j in range(len(pr))]); + dimX=max( [sum([pr[j][i].count("#") for j in range(len(pr))]) for i in range(len(pr[0]))] ); + minX+=r*dimX; + minY+=r*dimY; + space-=r*dimX*dimY; + return space>0; + +for t in trees: + part1+=1*validateTree(t,gifts); +print("part 1 =",part1); -- cgit v1.2.3