From 99a7d62c30069a5ffe2210a72c7cf81e76a1f241 Mon Sep 17 00:00:00 2001 From: blenovo Date: Wed, 16 Jul 2025 18:55:48 +0200 Subject: summertime warmup session with 2020 event --- 2020/aoc2020-d01-1.py | 1 - 2020/aoc2020-d01.py | 22 ++++++++++++ 2020/aoc2020-d02.py | 22 ++++++++++++ 2020/aoc2020-d03.py | 29 ++++++++++++++++ 2020/aoc2020-d04.py | 42 +++++++++++++++++++++++ 2020/aoc2020-d05.py | 33 ++++++++++++++++++ 2020/aoc2020-d06.py | 22 ++++++++++++ 2020/aoc2020-d07.py | 48 ++++++++++++++++++++++++++ 2020/aoc2020-d08.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2020/aoc2020-d09.py | 55 ++++++++++++++++++++++++++++++ 2020/aoc2020-d10.py | 39 +++++++++++++++++++++ 11 files changed, 405 insertions(+), 1 deletion(-) delete mode 100644 2020/aoc2020-d01-1.py create mode 100644 2020/aoc2020-d01.py create mode 100644 2020/aoc2020-d02.py create mode 100644 2020/aoc2020-d03.py create mode 100644 2020/aoc2020-d04.py create mode 100644 2020/aoc2020-d05.py create mode 100644 2020/aoc2020-d06.py create mode 100644 2020/aoc2020-d07.py create mode 100644 2020/aoc2020-d08.py create mode 100644 2020/aoc2020-d09.py create mode 100644 2020/aoc2020-d10.py (limited to '2020') diff --git a/2020/aoc2020-d01-1.py b/2020/aoc2020-d01-1.py deleted file mode 100644 index 23d2abb..0000000 --- a/2020/aoc2020-d01-1.py +++ /dev/null @@ -1 +0,0 @@ -print("hello"); diff --git a/2020/aoc2020-d01.py b/2020/aoc2020-d01.py new file mode 100644 index 0000000..84cca45 --- /dev/null +++ b/2020/aoc2020-d01.py @@ -0,0 +1,22 @@ +#advent of code 2020 +#day 01 + +p1 = 0; +p2 = 0; +entries = []; +PuzzleInput = open("01.in","r"); +for l in PuzzleInput: entries.append(int(l)); +PuzzleInput.close(); +for e1 in entries: + for e2 in entries: + if e1 + e2 == 2020: + p1 = e1*e2; + for e3 in entries: + if e1 + e2 + e3 == 2020: + p2 = e1*e2*e3; + break; + if p2: break; + if p1 and p2: break; + +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d02.py b/2020/aoc2020-d02.py new file mode 100644 index 0000000..9871373 --- /dev/null +++ b/2020/aoc2020-d02.py @@ -0,0 +1,22 @@ +#advent of code 2020 +#day 02 + +p1 = 0; +p2 = 0; +PuzzleInput = open("02.in","r"); +for l in PuzzleInput: + rules, pwd = l.split(": "); + limits, letter = rules.split(" "); + lo, hi = limits.split("-"); + check = pwd.count(letter); + if int(lo) <= check and int(hi) >= check: + p1 += 1; + v1 = pwd[int(lo)-1] == letter; + v2 = pwd[int(hi)-1] == letter; + v3 = v1 + v2; + v4 = v1 != v2; + if v3 and v4: p2 += 1; +PuzzleInput.close(); + +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d03.py b/2020/aoc2020-d03.py new file mode 100644 index 0000000..aa485e0 --- /dev/null +++ b/2020/aoc2020-d03.py @@ -0,0 +1,29 @@ +#advent of code 2020 +#day 03 + +grid = dict(); +limY = 0; +limX = 0; +PuzzleInput = open("03.in","r"); +for y,line in enumerate(PuzzleInput): + for x, c in enumerate(line): + grid[(x,y)] = c; + limX = max(limX,x); + limY = max(limY,y); +PuzzleInput.close(); +slopes = [(1,1),(3,1),(5,1),(7,1),(1,2)]; +p1 = 0; +p2 = 1; +for slope in slopes: + stepX, stepY = slope; + MyPosX = 0; + MyPosY = 0; + trees = 0; + while MyPosY < limY : + MyPosX += stepX; + MyPosY += stepY; + if grid[(MyPosX%limX),MyPosY] == "#": trees +=1; + p2 *= trees; + if slope == (3,1): p1 += trees; +print("part 1 = ",p1); +print("part 2 = ",p2); diff --git a/2020/aoc2020-d04.py b/2020/aoc2020-d04.py new file mode 100644 index 0000000..22f044d --- /dev/null +++ b/2020/aoc2020-d04.py @@ -0,0 +1,42 @@ +#advent of code 2020 +#day 04 +import re + +PuzzleInput = open("04.in","r").read() +passports = PuzzleInput.split("\n\n"); +p1 = 0; +p2 = 0; +documents = dict(); +required = ["byr","iyr","eyr","hgt","hcl","ecl","pid"]; #puzzle description + +def part2(doc): + valid2 = True; + valid2 *= len(doc["byr"]) == 4 and int(doc["byr"]) >= 1920 and int(doc["byr"]) <= 2002; + valid2 *= len(doc["iyr"]) == 4 and int(doc["iyr"]) >= 2010 and int(doc["iyr"]) <= 2020; + valid2 *= len(doc["eyr"]) == 4 and int(doc["eyr"]) >= 2020 and int(doc["eyr"]) <= 2030; + valid2 *= doc["hgt"][-2:] == "cm" or doc["hgt"][-2:] == "in"; + if doc["hgt"][-2:] == "cm": + valid2 *= int(doc["hgt"][:-2]) >= 150 and int(doc["hgt"][:-2]) <= 193; + if doc["hgt"][-2:] == "in": + valid2 *= int(doc["hgt"][:-2]) >= 59 and int(doc["hgt"][:-2]) <= 76; + valid2 *= doc["hcl"][0] == "#"; + valid2 *= len(re.findall("[a-f]|[0-9]",doc["hcl"])) == 6; + valid2 *= doc["ecl"] in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]; + valid2 *= len(doc["pid"]) == 9; + return valid2; + +for i,p in enumerate(passports): + p = p.replace("\n"," ") + documents[i] = dict(); + for entry in p.split(" "): + if len(entry) == 0: continue; + k,v = entry.split(":"); + documents[i][k] = v; + valid = True; + for req in required: + valid *= req in documents[i]; + p1 += 1*valid; + if valid: p2 += 1*part2(documents[i]); + +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d05.py b/2020/aoc2020-d05.py new file mode 100644 index 0000000..ffc6ffb --- /dev/null +++ b/2020/aoc2020-d05.py @@ -0,0 +1,33 @@ +#advent of code 2020 +#day 05 +#examples = ["BFFFBBFRRR","FFFBBBFRRR","BBFFBBFRLL"]; +def partitioner(instr, limLow, limHigh, splitLow, splitHigh): + diff = limHigh - limLow + 1; + if instr == "": + return limLow; + elif instr[0] == splitLow: + return partitioner(instr[1:], limLow, limHigh-diff//2, splitLow, splitHigh); + elif instr[0] == splitHigh: + return partitioner(instr[1:], limLow+diff//2, limHigh, splitLow, splitHigh); + +p1 = 0; +AllSeats = []; +PuzzleInput = open("05.in","r"); + +for BoardingPass in PuzzleInput: + BP = BoardingPass.replace("\n",""); + row = partitioner(BP[:-3],0,127,"F","B"); + col = partitioner(BP[-3:],0,7,"L","R"); + seatID = row*8 + col; + p1 = max(p1,seatID) + AllSeats.append(seatID) +PuzzleInput.close(); + +AllSeats = sorted(AllSeats); +for n in range(1, len(AllSeats)): + if AllSeats[n] - AllSeats[n-1] != 1: + p2 = AllSeats[n-1] + 1; + break; + +print("part 1 = ",p1); +print("part 2 = ",p2); diff --git a/2020/aoc2020-d06.py b/2020/aoc2020-d06.py new file mode 100644 index 0000000..8f0df5c --- /dev/null +++ b/2020/aoc2020-d06.py @@ -0,0 +1,22 @@ +#advent of code 2020 +#day 06 +PuzzleInput = open("06.in","r").read(); +groups = PuzzleInput.split("\n\n"); +p1 = 0; +p2 = 0; + +for group in groups: + anyone = group.replace("\n",""); + p1 += len(set(list(anyone))); + everyone = group.split("\n"); + answers = []; + for e in everyone: + if len(e) == 0: continue; #some minor adjustment bc parsing + answers.append(set(list(e))) + total = answers[0]; #answers of the first guy (1st line) + for a in answers[1:]: + total = total.intersection(a); #shrink the set to duplicates only + p2 += len(total); + +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d07.py b/2020/aoc2020-d07.py new file mode 100644 index 0000000..4be155f --- /dev/null +++ b/2020/aoc2020-d07.py @@ -0,0 +1,48 @@ +#advent of code 2020 +#day 07 +#cool +PuzzleInput = open("07.in","r"); + +rules = {}; +target = "shinygold"; +queue = []; +options = set(); +#parse, removing filler wording and splitting bag names to dictionary +for line in PuzzleInput: + line = line.replace("\n","").replace(" bags","").replace(" bag","").replace("no other","1 no other")[:-1]; + rk, rv = line.split(" contain "); #rule key, rule value + rv = rv.split(", "); + rk = rk.replace(" ",""); + rules[rk] = dict(); + for rval in rv: + rv1,rv2,rv3 = rval.split(" "); + rules[rk][rv2+rv3] = int(rv1); + if target in rules[rk]: + queue.append(rk); + options.add(rk); +PuzzleInput.close(); +#part 1 +visited = []; +while queue: + bag = queue.pop(); + if bag in visited: continue; + visited.append(bag); + for rk in rules: + if bag in rules[rk]: + queue.append(rk); + options.add(rk); + +p1 = len(options); +#part 2 +queue = [(1,target)]; +AllBags = dict(); +while queue: + total, bag = queue.pop(); + for b in rules[bag]: + if b == "noother": continue; + AllBags[b] = AllBags.get(b,0) + total*rules[bag][b]; + queue.append((total*rules[bag][b], b)); + +p2 = sum([AllBags[bag] for bag in AllBags]); +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d08.py b/2020/aoc2020-d08.py new file mode 100644 index 0000000..8965514 --- /dev/null +++ b/2020/aoc2020-d08.py @@ -0,0 +1,93 @@ +#advent of code 2020 +#day 08 +#a little bit bruteforce-ish, +#for part 2 I mark instruction that are actually used by boot code +#then I loop over the marked instructions and replace them 1 by 1 until +#the infinite cycle is broken +#also the input kept getting broken and needed to change the parsing +#which isn't a hard bug, but an annoying one +#ALSO during rewriting I figured out that I don't need to calculate +#part 1 separately, it's already used during cycle detection +#although this might just be a coincidence; honestly I'm not confident +#in cycle detection puzzles + +BootCode = [] +PuzzleInput = open("08.in","r") +for x in PuzzleInput: + if len(x) == 0: continue; #please ignore it, I'm bad at parsing + instr, val = x.split(" "); + BootCode.append(x.replace("\n","")); +PuzzleInput.close(); + +index = 0; +accumulator = 0; +visited = set(); +#the "Im sure it works" method for part 1 +while True: + instr, val = BootCode[index].split(" "); + #order += 1; + if index in visited: break; + visited.add(index); + if instr == "nop": + index += 1; + elif instr == "acc": + accumulator += int(val); + index += 1; + elif instr == "jmp": + index += int(val); + +print("part 1 =",accumulator); + +index = 0; +accumulator = 0; +accVals = dict(); +p1 = None; +#the "it works for me but might be luck" method for part 1 +while index <= len(BootCode): + instr, val = BootCode[index].split(" "); + Current, Previous = accVals.get(index,(None,None)); + if Previous and Current and Previous%accumulator == Previous%accumulator: + p1 = Current; + break; + accVals[index] = (accumulator, Current); + if instr == "nop": + index += 1; + elif instr == "acc": + accumulator += int(val); + index += 1; + elif instr == "jmp": + index += int(val); + +print("part 1 =",p1); + +p2 = None; +for i in accVals: + if BootCode[i].split(" ")[0] == "acc": continue; + index = 0; + accumulator = 0; + accValsNested = dict(); + NoCycle = True; + while index < len(BootCode): + instr, val = BootCode[index].split(" "); + Current, Previous = accValsNested.get(index,(None,None)); + if Previous and Current and Previous%accumulator == Previous%accumulator: + NoCycle = False; + break; + accValsNested[index] = (accumulator, Current); + if index == i: #swap instructions + if instr == "nop": + instr = "jmp"; + elif instr == "jmp": + instr = "nop"; + if instr == "nop": + index += 1; + elif instr == "acc": + accumulator += int(val); + index += 1; + elif instr == "jmp": + index += int(val); + if NoCycle: + p2 = accumulator; + break; + +print("part 2 =", p2); diff --git a/2020/aoc2020-d09.py b/2020/aoc2020-d09.py new file mode 100644 index 0000000..26c1c61 --- /dev/null +++ b/2020/aoc2020-d09.py @@ -0,0 +1,55 @@ +#advent of code 2020 +#day 09 +#genuinely surprised the simple solution worked +#shamelessly googled the code for combinations, +#didn't feel like implementing it +#if i reversed the "visited" list the runtime could be faster but w/e + +def PossibleCombs(n,k): + combinations = []; + if k==1: return n; + for i in range(len(n)): + head = n[i:i+1] + tail = PossibleCombs(n[i+1:],k-1); + for j in range(len(tail)): + if type(tail[j]) == int: + comb = head + [tail[j]] + else: + comb = head + tail[j]; + combinations.append(comb); + return combinations; + +p1 = None; +limit = 25; +numbers = []; +PuzzleInput = open("09.in","r"); +for line in PuzzleInput: numbers.append(int(line)); +PuzzleInput.close(); +previous = numbers[:limit]; +counter = limit -1; + +for n in numbers[limit:]: + counter += 1; + found = False; + for combo in PossibleCombs(previous,2): + if n == sum(combo): + previous = previous[1:] + [n]; + found = True; + break; + if not found: + p1 = n; + break; + +visited = numbers[:counter]; +for i,n in enumerate(visited): + subsum = 0 + n; + subcounter = 0 + i; + while subsum < p1: + subcounter += 1; + subsum += visited[subcounter]; + if subsum == p1: + p2 = min(visited[i:subcounter]) + max(visited[i:subcounter]) ; + break; + +print("part 1 =",p1); +print("part 2 =",p2); diff --git a/2020/aoc2020-d10.py b/2020/aoc2020-d10.py new file mode 100644 index 0000000..a86b976 --- /dev/null +++ b/2020/aoc2020-d10.py @@ -0,0 +1,39 @@ +#advent of code 2020 +#day 10 +#very similar (if not identical) to towels puzzle, 2024-d19 +#memorize previous paths and just sum up the valid paths for each adapter +#although this one i think is easier due to no duplicates +#and working on numbers instead of characters +bag = []; +PuzzleInput = open("10.in","r"); +for num in PuzzleInput: bag.append(int(num)); +PuzzleInput.close(); +#first and last items are from puzzle description +bag = [0] + [x for x in sorted(bag)] + [max(bag) +3]; +connections = dict(); +connections[1] = 0; +connections[2] = 0; +connections[3] = 0; +#since there are no duplicates and all adapters must be connected +#we can just check against the previous value for part 1; +for index in range(1,len(bag)): + adapter1 = bag[index]; + adapter2 = bag[index-1]; + diff = adapter1 - adapter2; + connections[diff] += 1; + +p1 = connections[1] * connections[3]; + +p2 = 0; +options = dict(); +options[0] = 1; +for index in range(1,len(bag)): + previous = bag[:index]; + possible = [x for x in previous if bag[index] - x <=3]; + options[bag[index]] = 0; + for poss in possible: + options[bag[index]] += options[poss]; + +p2 = options[max(bag)]; +print("part 1 =",p1); +print("part 2 =",p2); -- cgit v1.2.3