summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--1.py2
-rw-r--r--2.py18
-rw-r--r--3.py23
-rw-r--r--4.py9
-rw-r--r--5.py29
-rw-r--r--6.py8
-rw-r--r--7.py93
7 files changed, 182 insertions, 0 deletions
diff --git a/1.py b/1.py
new file mode 100644
index 0000000..54a243b
--- /dev/null
+++ b/1.py
@@ -0,0 +1,2 @@
+print(max(sum(int(n) for n in group.split('\n')) for group in open('1.in').read().rstrip().split('\n\n')))
+print(sum(sorted(sum(int(n) for n in group.split('\n')) for group in open('1.in').read().rstrip().split('\n\n'))[-3:]))
diff --git a/2.py b/2.py
new file mode 100644
index 0000000..abcd27f
--- /dev/null
+++ b/2.py
@@ -0,0 +1,18 @@
+with open('2.in') as f:
+ inp = []
+ for line in f:
+ a, b = line.rstrip().split()
+ inp.append((ord(a) - ord('A'), ord(b) - ord('X')))
+def shape_score(me):
+ return me + 1
+def outcome_score(opp, me):
+ return (3 - opp + me + 1) % 3 * 3
+def p1(opp, me):
+ return shape_score(me) + outcome_score(opp, me)
+print(sum(p1(a, b) for a, b in inp))
+def shape_for_outcome(opp, outcome):
+ return (3 + opp + outcome + 2) % 3
+def p2(opp, outcome):
+ me = shape_for_outcome(opp, outcome)
+ return p1(opp, me)
+print(sum(p2(a, b) for a, b in inp))
diff --git a/3.py b/3.py
new file mode 100644
index 0000000..e7bb2d1
--- /dev/null
+++ b/3.py
@@ -0,0 +1,23 @@
+with open('3.in') as f:
+ rucksacks = [line.rstrip() for line in f]
+
+def priority(itm):
+ if itm.islower():
+ return ord(common) - ord('a') + 1
+ else:
+ return ord(common) - ord('A') + 27
+
+total = 0
+for rucksack in rucksacks:
+ half = len(rucksack) // 2
+ a, b = set(rucksack[:half]), set(rucksack[half:])
+ common = set.intersection(a, b).pop()
+ total += priority(common)
+print(total)
+
+total = 0
+for i in range(0, len(rucksacks), 3):
+ a, b, c = map(set, rucksacks[i:i+3])
+ common = set.intersection(a, set.intersection(b, c)).pop()
+ total += priority(common)
+print(total)
diff --git a/4.py b/4.py
new file mode 100644
index 0000000..3279e7e
--- /dev/null
+++ b/4.py
@@ -0,0 +1,9 @@
+with open('4.in') as f:
+ inp = [tuple(tuple(map(int, elf.split('-'))) for elf in line.rstrip().split(',')) for line in f]
+def fully_contains(a, b):
+ return b[0] >= a[0] and b[1] <= a[1] or a[0] >= b[0] and a[1] <= b[1]
+def overlaps(a, b):
+ return b[0] <= a[0] <= b[1] or b[0] <= a[1] <= b[1] or \
+ a[0] <= b[0] <= a[1] # or a[0] <= b[1] <= a[1]
+print(sum(fully_contains(a, b) for a, b in inp))
+print(sum(overlaps(a, b) for a, b in inp))
diff --git a/5.py b/5.py
new file mode 100644
index 0000000..d375f74
--- /dev/null
+++ b/5.py
@@ -0,0 +1,29 @@
+from copy import deepcopy
+with open('5.in.test') as f:
+ stacks, instructions = f.read().rstrip().split('\n\n')
+layers = stacks.split('\n')
+stacks = [list() for _ in range((len(layers[-1]) + 1) // 4)]
+for layer in reversed(layers[:-1]):
+ for i in range(len(stacks)):
+ c = layer[i * 4 + 1]
+ if c != ' ':
+ stacks[i].append(c)
+instructions = [i.split(' ') for i in instructions.split('\n')]
+instructions = [tuple(int(i) for i in (i[1], i[3], i[5])) for i in instructions]
+def part1(stacks, instructions):
+ stacks = deepcopy(stacks)
+ for count, src, dst in instructions:
+ for _ in range(count):
+ stacks[dst-1].append(stacks[src-1].pop())
+ return ''.join(s[-1] for s in stacks)
+def part2(stacks, instructions):
+ stacks = deepcopy(stacks)
+ for count, src, dst in instructions:
+ tmp = list()
+ for _ in range(count):
+ tmp.append(stacks[src-1].pop())
+ for _ in range(count):
+ stacks[dst-1].append(tmp.pop())
+ return ''.join(s[-1] for s in stacks)
+print(part1(stacks, instructions))
+print(part2(stacks, instructions))
diff --git a/6.py b/6.py
new file mode 100644
index 0000000..5c3a3d0
--- /dev/null
+++ b/6.py
@@ -0,0 +1,8 @@
+with open('6.in') as f:
+ inp = f.read().rstrip()
+def solve(inp, n):
+ for i in range(n, len(inp)):
+ if len(set(inp[i-n:i])) == n:
+ return i
+print(solve(inp, 4))
+print(solve(inp, 14))
diff --git a/7.py b/7.py
new file mode 100644
index 0000000..22150f0
--- /dev/null
+++ b/7.py
@@ -0,0 +1,93 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+@dataclass
+class File:
+ size: int
+
+@dataclass
+class Directory:
+ up: Directory
+ entries: dict[str, File|Directory]
+ def __init__(self, up=None):
+ self.up = up if up else self
+ self.entries = dict()
+ def __getitem__(self, key):
+ match key:
+ case '..':
+ return self.up
+ case '.':
+ return self
+ case d:
+ return self.entries[d]
+ def __setitem__(self, key, value):
+ self.entries[key] = value
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+with open('7.in.test') as f:
+ inp = [tuple(line.rstrip().split()) for line in f]
+root = Directory()
+pwd = root
+for line in inp:
+ match line:
+ case ['$', 'cd', d]:
+ match d:
+ case '/': pwd = root
+ case d:
+ pwd = pwd[d]
+ assert(isinstance(pwd, Directory))
+ case ['$', 'ls']:
+ continue
+ case ['dir', name]:
+ pwd[name] = Directory(pwd)
+ case [size, name]:
+ pwd[name] = File(int(size))
+
+dirsizes = dict()
+def getsize(d: Directory, path=tuple()) -> int:
+ if path in dirsizes:
+ return dirsizes[path]
+ size = 0
+ for k, e in d.entries.items():
+ match e:
+ case File(s):
+ size += s
+ case Directory(_, _) as d:
+ size += getsize(d, path + (k,))
+ dirsizes[size] = size
+ return size
+
+def part1(root):
+ answer = 0
+ def solve(d, path=tuple()):
+ nonlocal answer
+ for k, e in d.entries.items():
+ if isinstance(e, Directory):
+ solve(e, path + (k,))
+ size = getsize(d, path)
+ if size <= 100000:
+ answer += size
+ solve(root)
+ return answer
+def part2(root):
+ used = getsize(root)
+ unused = 70000000 - used
+ need = 30000000 - unused
+ smallest = used
+ def solve(d, path=tuple()):
+ nonlocal smallest
+ for k, e in d.entries.items():
+ if isinstance(e, Directory):
+ solve(e, path + (k,))
+ size = getsize(d, path)
+ if size >= need and size < smallest:
+ smallest = size
+ solve(root)
+ return smallest
+print(part1(root))
+print(part2(root))