Format files

This commit is contained in:
Anders Englöf Ytterström 2025-05-06 20:14:58 +02:00
parent fcbeb4bfdd
commit 5b754381b0
46 changed files with 391 additions and 329 deletions

View file

@ -7,8 +7,9 @@ except ValueError:
name = None name = None
if day_no and name: if day_no and name:
with open('solutions/day_{}.py'.format(day_no.zfill(2)), 'w') as s: with open("solutions/day_{}.py".format(day_no.zfill(2)), "w") as s:
s.write(''' s.write(
"""
from solutions import BaseSolution from solutions import BaseSolution
@ -28,9 +29,14 @@ class Solution(BaseSolution):
if __name__ == '__main__': if __name__ == '__main__':
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()
'''.strip().format(day=day_no, day_no=day_no.zfill(2), name=name) + '\n') """.strip().format(
with open('tests/day_{}_tests.py'.format(day_no.zfill(2)), 'w') as t: day=day_no, day_no=day_no.zfill(2), name=name
t.write(''' )
+ "\n"
)
with open("tests/day_{}_tests.py".format(day_no.zfill(2)), "w") as t:
t.write(
"""
import unittest import unittest
from solutions.day_{day_no} import Solution from solutions.day_{day_no} import Solution
@ -46,18 +52,24 @@ class Day{day_no}TestCase(unittest.TestCase):
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
'''.strip().format(day_no=day_no.zfill(2)) + '\n') """.strip().format(
with open('inputs/{}.txt'.format(day_no.zfill(2)), 'w') as i: day_no=day_no.zfill(2)
i.write('') )
+ "\n"
)
with open("inputs/{}.txt".format(day_no.zfill(2)), "w") as i:
i.write("")
exit(0) exit(0)
print('\nAdvent of Code 2017' print(
'\n###################' "\nAdvent of Code 2017" "\n###################" "\n\nby Anders Ytterström (@madr)"
'\n\nby Anders Ytterström (@madr)') )
for i in [str(n).zfill(2) for n in range(1, 26)]: for i in [str(n).zfill(2) for n in range(1, 26)]:
try: try:
solution = __import__('solutions.day_{}'.format(i), globals(), locals(), ['Solution'], 0).Solution() solution = __import__(
"solutions.day_{}".format(i), globals(), locals(), ["Solution"], 0
).Solution()
solution.show_results() solution.show_results()
except IOError: except IOError:
pass pass

View file

@ -4,20 +4,22 @@ class BaseSolution:
trim_input = True trim_input = True
def parse_input(self, filename): def parse_input(self, filename):
filepath = './inputs/{}'.format(filename) filepath = "./inputs/{}".format(filename)
with open(filepath, 'r') as f: with open(filepath, "r") as f:
self.puzzle_input = f.read() self.puzzle_input = f.read()
if self.trim_input: if self.trim_input:
self.puzzle_input = self.puzzle_input.strip() self.puzzle_input = self.puzzle_input.strip()
def show_results(self): def show_results(self):
self.parse_input(self.input_file) self.parse_input(self.input_file)
print('\n\n{}\n{}\n\nPart 1: {}\nPart 2: {}'.format( print(
str(self), "\n\n{}\n{}\n\nPart 1: {}\nPart 2: {}".format(
'-' * len(str(self)), str(self),
self.solve(self.puzzle_input), "-" * len(str(self)),
self.solve_again(self.puzzle_input), self.solve(self.puzzle_input),
)) self.solve_again(self.puzzle_input),
)
)
def solve(self, puzzle_input): def solve(self, puzzle_input):
raise NotImplemented raise NotImplemented

View file

@ -2,21 +2,24 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '01.txt' input_file = "01.txt"
def __str__(self): def __str__(self):
return 'Day 1: Inverse Captcha' return "Day 1: Inverse Captcha"
def solve(self, puzzle_input, distance=1): def solve(self, puzzle_input, distance=1):
pi_length = len(puzzle_input) pi_length = len(puzzle_input)
return sum(int(puzzle_input[pos]) for pos in range(pi_length) if return sum(
puzzle_input[pos] == puzzle_input[(pos + distance) % pi_length]) int(puzzle_input[pos])
for pos in range(pi_length)
if puzzle_input[pos] == puzzle_input[(pos + distance) % pi_length]
)
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
distance = len(puzzle_input) // 2 distance = len(puzzle_input) // 2
return self.solve(puzzle_input, distance) return self.solve(puzzle_input, distance)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '02.txt' input_file = "02.txt"
def __str__(self): def __str__(self):
return 'Day 2: Corruption Checksum' return "Day 2: Corruption Checksum"
def _get_rows(self, puzzle_input): def _get_rows(self, puzzle_input):
return [list(map(int, rows.split())) for rows in puzzle_input.splitlines()] return [list(map(int, rows.split())) for rows in puzzle_input.splitlines()]
@ -29,6 +29,6 @@ class Solution(BaseSolution):
return sum(self.get_even_divisible(columns) for columns in rows) return sum(self.get_even_divisible(columns) for columns in rows)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '03.txt' input_file = "03.txt"
def __str__(self): def __str__(self):
return 'Day 3: Spiral Memory' return "Day 3: Spiral Memory"
def _get_rounds(self, value): def _get_rounds(self, value):
n = 0 n = 0
@ -32,6 +32,6 @@ class Solution(BaseSolution):
return 279138 return 279138
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,15 +2,15 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '04.txt' input_file = "04.txt"
def __str__(self): def __str__(self):
return 'Day 4: High-Entropy Passphrases' return "Day 4: High-Entropy Passphrases"
def validate(self, passphrase, extended=False): def validate(self, passphrase, extended=False):
words = passphrase.split() words = passphrase.split()
if extended: if extended:
words = [''.join(sorted(w)) for w in words] words = ["".join(sorted(w)) for w in words]
return sorted(list(set(words))) == sorted(words) return sorted(list(set(words))) == sorted(words)
def solve(self, puzzle_input): def solve(self, puzzle_input):
@ -20,6 +20,6 @@ class Solution(BaseSolution):
return sum(self.validate(p, True) for p in puzzle_input.splitlines()) return sum(self.validate(p, True) for p in puzzle_input.splitlines())
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '05.txt' input_file = "05.txt"
def __str__(self): def __str__(self):
return 'Day 5: A Maze of Twisty Trampolines, All Alike' return "Day 5: A Maze of Twisty Trampolines, All Alike"
def solve(self, puzzle_input, strange_jumps=False): def solve(self, puzzle_input, strange_jumps=False):
pos = 0 pos = 0
@ -23,6 +23,6 @@ class Solution(BaseSolution):
return self.solve(puzzle_input, True) return self.solve(puzzle_input, True)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '06.txt' input_file = "06.txt"
def __str__(self): def __str__(self):
return 'Day 6: Memory Reallocation' return "Day 6: Memory Reallocation"
def redistribute(self, banks): def redistribute(self, banks):
banks = list(banks) banks = list(banks)
@ -39,10 +39,10 @@ class Solution(BaseSolution):
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
seen = self._allocate(puzzle_input) seen = self._allocate(puzzle_input)
seen_last = ' '.join(str(n) for n in seen[-1]) seen_last = " ".join(str(n) for n in seen[-1])
return len(self._allocate(seen_last)) - 1 return len(self._allocate(seen_last)) - 1
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -18,8 +18,8 @@ class Program:
name, weight = data.split() name, weight = data.split()
except ValueError: except ValueError:
name, weight, _, *disc = data.split() name, weight, _, *disc = data.split()
weight = int(weight[1:len(weight) - 1]) weight = int(weight[1 : len(weight) - 1])
disc = tuple(p.replace(',', '') for p in disc) disc = tuple(p.replace(",", "") for p in disc)
return name, weight, disc return name, weight, disc
def has_disc(self): def has_disc(self):
@ -30,29 +30,31 @@ class Program:
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '07.txt' input_file = "07.txt"
def __str__(self): def __str__(self):
return 'Day 7: Recursive Circus' return "Day 7: Recursive Circus"
def _get_programs(self, puzzle_input): def _get_programs(self, puzzle_input):
return [Program(data) for data in puzzle_input.splitlines()] return [Program(data) for data in puzzle_input.splitlines()]
def _get_discs(self, disc, programs): def _get_discs(self, disc, programs):
subdisc = [{'own_weight': p.weight, 'obj': p} for p in programs if p.name in disc] subdisc = [
{"own_weight": p.weight, "obj": p} for p in programs if p.name in disc
]
for t in subdisc: for t in subdisc:
t['weight'] = t['own_weight'] t["weight"] = t["own_weight"]
if t['obj'].has_disc(): if t["obj"].has_disc():
t['disc'] = self._get_discs(t['obj'].disc, programs) t["disc"] = self._get_discs(t["obj"].disc, programs)
t['weight'] += sum([st['weight'] for st in t['disc']]) t["weight"] += sum([st["weight"] for st in t["disc"]])
del (t['obj']) del t["obj"]
return subdisc return subdisc
def _find_unbalanced_disc(self, disc): def _find_unbalanced_disc(self, disc):
disc = sorted(disc, key=lambda t: t['weight']) disc = sorted(disc, key=lambda t: t["weight"])
if not disc[0]['weight'] < disc[1]['weight']: if not disc[0]["weight"] < disc[1]["weight"]:
disc = sorted(disc, key=lambda t: t['weight'], reverse=True) disc = sorted(disc, key=lambda t: t["weight"], reverse=True)
return disc[0], disc[1]['weight'] - disc[0]['weight'] return disc[0], disc[1]["weight"] - disc[0]["weight"]
def solve(self, puzzle_input): def solve(self, puzzle_input):
programs = self._get_programs(puzzle_input) programs = self._get_programs(puzzle_input)
@ -67,28 +69,30 @@ class Solution(BaseSolution):
unseen = p.unseen_discs(seen) unseen = p.unseen_discs(seen)
if len(unseen) > 0: if len(unseen) > 0:
seen += unseen seen += unseen
bottom_program = list(filter(lambda p: p.name not in seen, programs_with_discs))[0] bottom_program = list(
filter(lambda p: p.name not in seen, programs_with_discs)
)[0]
return bottom_program return bottom_program
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
programs = self._get_programs(puzzle_input) programs = self._get_programs(puzzle_input)
bottom_program = self.solve(puzzle_input) bottom_program = self.solve(puzzle_input)
disc_tree = { disc_tree = {
'own_weight': bottom_program.weight, "own_weight": bottom_program.weight,
'disc': self._get_discs(bottom_program.disc, programs) "disc": self._get_discs(bottom_program.disc, programs),
} }
diff = -1 diff = -1
unbalanced = True unbalanced = True
while unbalanced: while unbalanced:
disc, new_diff = self._find_unbalanced_disc(disc_tree['disc']) disc, new_diff = self._find_unbalanced_disc(disc_tree["disc"])
if new_diff == 0: if new_diff == 0:
unbalanced = False unbalanced = False
else: else:
disc_tree = disc disc_tree = disc
diff = new_diff diff = new_diff
return disc_tree['own_weight'] + diff return disc_tree["own_weight"] + diff
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,22 +2,22 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '08.txt' input_file = "08.txt"
registry = {} registry = {}
def __str__(self): def __str__(self):
return 'Day 8: I Heard You Like Registers' return "Day 8: I Heard You Like Registers"
def _should_modify(self, x, comp, y): def _should_modify(self, x, comp, y):
if comp in ('==', '!=', '>=', '<=', '>', '<'): if comp in ("==", "!=", ">=", "<=", ">", "<"):
return eval('{:d} {} {:d}'.format(x, comp, y)) return eval("{:d} {} {:d}".format(x, comp, y))
return False return False
def _update_registry(self, registry, instruction): def _update_registry(self, registry, instruction):
r, action, n, _, k, comp, v = instruction.split() r, action, n, _, k, comp, v = instruction.split()
current = registry.get(r, 0) current = registry.get(r, 0)
if self._should_modify(registry.get(k, 0), comp, int(v)): if self._should_modify(registry.get(k, 0), comp, int(v)):
registry[r] = current + int(n) if action == 'inc' else current - int(n) registry[r] = current + int(n) if action == "inc" else current - int(n)
def solve(self, puzzle_input): def solve(self, puzzle_input):
registry = {} registry = {}
@ -35,6 +35,6 @@ class Solution(BaseSolution):
return max_value return max_value
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -4,30 +4,30 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '09.txt' input_file = "09.txt"
def __str__(self): def __str__(self):
return 'Day 9: Stream Processing' return "Day 9: Stream Processing"
def solve(self, puzzle_input): def solve(self, puzzle_input):
level = 0 level = 0
groups = [] groups = []
stream = re.sub(r'!.', '', puzzle_input) stream = re.sub(r"!.", "", puzzle_input)
stream = re.sub(r'<[^>]*>', '', stream) stream = re.sub(r"<[^>]*>", "", stream)
for c in stream: for c in stream:
if c == '{': if c == "{":
level += 1 level += 1
if c == '}': if c == "}":
groups.append(level) groups.append(level)
level -= 1 level -= 1
return sum(groups) return sum(groups)
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
stream = re.sub(r'!.', '', puzzle_input) stream = re.sub(r"!.", "", puzzle_input)
garbage = re.findall(r'<([^>]*)>', stream) garbage = re.findall(r"<([^>]*)>", stream)
return sum([len(g) for g in garbage]) return sum([len(g) for g in garbage])
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,14 +2,14 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '10.txt' input_file = "10.txt"
list = [] list = []
l = 0 l = 0
skip_size = 0 skip_size = 0
pos = 0 pos = 0
def __str__(self): def __str__(self):
return 'Day 10: Knot Hash' return "Day 10: Knot Hash"
def reset(self, l=256): def reset(self, l=256):
self.list = list(range(l)) self.list = list(range(l))
@ -28,7 +28,7 @@ class Solution(BaseSolution):
def solve(self, puzzle_input, r=256): def solve(self, puzzle_input, r=256):
self.reset(r) self.reset(r)
for sublist_length in map(int, puzzle_input.split(',')): for sublist_length in map(int, puzzle_input.split(",")):
self.reverse(sublist_length) self.reverse(sublist_length)
return self.list[0] * self.list[1] return self.list[0] * self.list[1]
@ -38,10 +38,13 @@ class Solution(BaseSolution):
for _ in range(64): for _ in range(64):
for sublist_length in puzzle_input: for sublist_length in puzzle_input:
self.reverse(sublist_length) self.reverse(sublist_length)
dense_hash = [eval('^'.join(list(map(str, self.list[seq:seq+16])))) for seq in range(0, r, 16)] dense_hash = [
return ''.join(['{:x}'.format(int(i)).zfill(2) for i in dense_hash]) eval("^".join(list(map(str, self.list[seq : seq + 16]))))
for seq in range(0, r, 16)
]
return "".join(["{:x}".format(int(i)).zfill(2) for i in dense_hash])
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,20 +2,20 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '11.txt' input_file = "11.txt"
furthest_away = 0 furthest_away = 0
# https://www.redblobgames.com/grids/hexagons/#coordinates # https://www.redblobgames.com/grids/hexagons/#coordinates
DIRECTIONS = { DIRECTIONS = {
'n': lambda x, y, z: (x, y + 1, z - 1), "n": lambda x, y, z: (x, y + 1, z - 1),
'ne': lambda x, y, z: (x + 1, y, z - 1), "ne": lambda x, y, z: (x + 1, y, z - 1),
'se': lambda x, y, z: (x + 1, y - 1, z), "se": lambda x, y, z: (x + 1, y - 1, z),
's': lambda x, y, z: (x, y - 1, z + 1), "s": lambda x, y, z: (x, y - 1, z + 1),
'sw': lambda x, y, z: (x - 1, y, z + 1), "sw": lambda x, y, z: (x - 1, y, z + 1),
'nw': lambda x, y, z: (x - 1, y + 1, z), "nw": lambda x, y, z: (x - 1, y + 1, z),
} }
def __str__(self): def __str__(self):
return 'Day 11: Hex Ed' return "Day 11: Hex Ed"
def _get_end(self, steps): def _get_end(self, steps):
x = 0 x = 0
@ -28,14 +28,14 @@ class Solution(BaseSolution):
return abs(x), abs(y), abs(z) return abs(x), abs(y), abs(z)
def solve(self, puzzle_input): def solve(self, puzzle_input):
x, y, z = self._get_end(puzzle_input.split(',')) x, y, z = self._get_end(puzzle_input.split(","))
return max(x, y, z) return max(x, y, z)
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
_, *__ = self._get_end(puzzle_input.split(',')) _, *__ = self._get_end(puzzle_input.split(","))
return self.furthest_away return self.furthest_away
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,17 +2,17 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '12.txt' input_file = "12.txt"
seen = [] seen = []
def __str__(self): def __str__(self):
return 'Day 12: Digital Plumber' return "Day 12: Digital Plumber"
def _walk(self, i, programs): def _walk(self, i, programs):
line = next(filter(lambda l: l.startswith('{} <->'.format(i)), programs)) line = next(filter(lambda l: l.startswith("{} <->".format(i)), programs))
piped = line.split()[2:] piped = line.split()[2:]
self.seen.add(i) self.seen.add(i)
for p in [int(p.replace(',', '')) for p in piped]: for p in [int(p.replace(",", "")) for p in piped]:
if p not in self.seen: if p not in self.seen:
self._walk(p, programs) self._walk(p, programs)
@ -34,6 +34,6 @@ class Solution(BaseSolution):
return groups return groups
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -4,12 +4,12 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '13.txt' input_file = "13.txt"
layers = [] layers = []
scanners = [] scanners = []
def __str__(self): def __str__(self):
return 'Day 13: Packet Scanners' return "Day 13: Packet Scanners"
def _move_scanners(self): def _move_scanners(self):
for p, l in enumerate(self.layers): for p, l in enumerate(self.layers):
@ -22,7 +22,10 @@ class Solution(BaseSolution):
self.scanners = [[0, 1] for l in self.layers] self.scanners = [[0, 1] for l in self.layers]
def _setup(self, puzzle_input): def _setup(self, puzzle_input):
pi = [tuple(map(int, line.strip().split(': '))) for line in puzzle_input.splitlines()] pi = [
tuple(map(int, line.strip().split(": ")))
for line in puzzle_input.splitlines()
]
self.layers = [0 for _ in range(pi[-1][0] + 1)] self.layers = [0 for _ in range(pi[-1][0] + 1)]
self._init_scanners() self._init_scanners()
for k, v in pi: for k, v in pi:
@ -55,13 +58,16 @@ class Solution(BaseSolution):
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
# todo: rewrite! # todo: rewrite!
lines = [line.split(': ') for line in puzzle_input.splitlines()] lines = [line.split(": ") for line in puzzle_input.splitlines()]
heights = {int(pos): int(height) for pos, height in lines} heights = {int(pos): int(height) for pos, height in lines}
wait = next( wait = next(
wait for wait in itertools.count() if not any(self._scan(heights[pos], wait + pos) == 0 for pos in heights)) wait
for wait in itertools.count()
if not any(self._scan(heights[pos], wait + pos) == 0 for pos in heights)
)
return wait return wait
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -3,18 +3,18 @@ from solutions.day_10 import Solution as KnotHash
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '14.txt' input_file = "14.txt"
def __str__(self): def __str__(self):
return 'Day 14: Disk Defragmentation' return "Day 14: Disk Defragmentation"
def _get_grid(self, pi): def _get_grid(self, pi):
grid = '' grid = ""
ks = KnotHash() ks = KnotHash()
for n in range(128): for n in range(128):
s = '-'.join([pi, str(n)]) s = "-".join([pi, str(n)])
knothash = ks.solve_again(s) knothash = ks.solve_again(s)
grid += '{:0128b}'.format(int(knothash, 16)) grid += "{:0128b}".format(int(knothash, 16))
return grid return grid
def _find_regions(self, squares): def _find_regions(self, squares):
@ -31,10 +31,10 @@ class Solution(BaseSolution):
get_adjacent_square(i - 128) get_adjacent_square(i - 128)
if i % 128 < 127: if i % 128 < 127:
get_adjacent_square(i + 1) get_adjacent_square(i + 1)
if i < 128 ** 2 - 128: if i < 128**2 - 128:
get_adjacent_square(i + 128) get_adjacent_square(i + 128)
for i in range(128 ** 2): for i in range(128**2):
if i in seen or i not in squares: if i in seen or i not in squares:
continue continue
regions += 1 regions += 1
@ -47,10 +47,10 @@ class Solution(BaseSolution):
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
grid = self._get_grid(puzzle_input) grid = self._get_grid(puzzle_input)
squares = [i for i, s in enumerate(list(grid)) if s == '1'] squares = [i for i, s in enumerate(list(grid)) if s == "1"]
return self._find_regions(squares) return self._find_regions(squares)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '15.txt' input_file = "15.txt"
def __str__(self): def __str__(self):
return 'Day 15: Dueling Generators' return "Day 15: Dueling Generators"
def _calc(self, x, f, m=1): def _calc(self, x, f, m=1):
x = (x * f) % 2147483647 x = (x * f) % 2147483647
@ -21,7 +21,7 @@ class Solution(BaseSolution):
for _ in range(40 * 10**6): for _ in range(40 * 10**6):
a = self._calc(a, af) a = self._calc(a, af)
b = self._calc(b, bf) b = self._calc(b, bf)
if '{:b}'.format(a)[-16:] == '{:b}'.format(b)[-16:]: if "{:b}".format(a)[-16:] == "{:b}".format(b)[-16:]:
j += 1 j += 1
return j return j
@ -29,14 +29,14 @@ class Solution(BaseSolution):
af, bf = (16807, 48271) af, bf = (16807, 48271)
a, b = [int(pi.split()[-1]) for pi in puzzle_input.splitlines()] a, b = [int(pi.split()[-1]) for pi in puzzle_input.splitlines()]
j = 0 j = 0
for _ in range(5 * 10 ** 6): for _ in range(5 * 10**6):
a = self._calc(a, af, 4) a = self._calc(a, af, 4)
b = self._calc(b, bf, 8) b = self._calc(b, bf, 8)
if '{:b}'.format(a)[-16:] == '{:b}'.format(b)[-16:]: if "{:b}".format(a)[-16:] == "{:b}".format(b)[-16:]:
j += 1 j += 1
return j return j
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,24 +2,24 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '16.txt' input_file = "16.txt"
def __str__(self): def __str__(self):
return 'Day 16: Permutation Promenade' return "Day 16: Permutation Promenade"
def _move(self, programs, m, i): def _move(self, programs, m, i):
l = len(programs) l = len(programs)
if m == 's': if m == "s":
r = int(i) r = int(i)
return programs[-r:] + programs[:l - r] return programs[-r:] + programs[: l - r]
if m == 'x': if m == "x":
x, y = [int(s) for s in i.split('/')] x, y = [int(s) for s in i.split("/")]
z = programs[x] z = programs[x]
programs[x] = programs[y] programs[x] = programs[y]
programs[y] = z programs[y] = z
return programs return programs
if m == 'p': if m == "p":
xp, yp = i.split('/') xp, yp = i.split("/")
x = programs.index(xp) x = programs.index(xp)
y = programs.index(yp) y = programs.index(yp)
z = programs[x] z = programs[x]
@ -34,22 +34,22 @@ class Solution(BaseSolution):
def solve(self, puzzle_input, n=16): def solve(self, puzzle_input, n=16):
programs = [chr(c) for c in range(97, 97 + n)] programs = [chr(c) for c in range(97, 97 + n)]
moves = puzzle_input.split(',') moves = puzzle_input.split(",")
return ''.join(self._dance(programs, moves)) return "".join(self._dance(programs, moves))
def solve_again(self, puzzle_input, n=16): def solve_again(self, puzzle_input, n=16):
moves = puzzle_input.split(',') moves = puzzle_input.split(",")
initial = [chr(c) for c in range(97, 97 + n)] initial = [chr(c) for c in range(97, 97 + n)]
programs = list(self.solve(puzzle_input)) programs = list(self.solve(puzzle_input))
dances = 1 dances = 1
while not programs == initial: while not programs == initial:
programs = self._dance(programs, moves) programs = self._dance(programs, moves)
dances += 1 dances += 1
for _ in range(10 ** 9 % dances): for _ in range(10**9 % dances):
programs = self._dance(programs, moves) programs = self._dance(programs, moves)
return ''.join(programs) return "".join(programs)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,10 +2,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '17.txt' input_file = "17.txt"
def __str__(self): def __str__(self):
return 'Day 17: Spinlock' return "Day 17: Spinlock"
def solve(self, puzzle_input): def solve(self, puzzle_input):
n = int(puzzle_input) n = int(puzzle_input)
@ -20,13 +20,13 @@ class Solution(BaseSolution):
pos = 0 pos = 0
n = int(puzzle_input) n = int(puzzle_input)
last_seen = 0 last_seen = 0
for i in range(1, 5 * 10 ** 7 + 1): for i in range(1, 5 * 10**7 + 1):
pos = (pos + n) % i + 1 pos = (pos + n) % i + 1
if pos == 1: if pos == 1:
last_seen = i last_seen = i
return last_seen return last_seen
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,16 +2,16 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '18.txt' input_file = "18.txt"
sound_freq = 0 sound_freq = 0
queue = [], [] queue = [], []
sent = [0, 0] sent = [0, 0]
def __str__(self): def __str__(self):
return 'Day 18: Duet' return "Day 18: Duet"
def _run(self, line, registry, swag_mode=True): def _run(self, line, registry, swag_mode=True):
actions = 'add jgz mod mul rcv set snd' actions = "add jgz mod mul rcv set snd"
a, *kv = line.split() a, *kv = line.split()
if len(kv) == 2: if len(kv) == 2:
k, v = kv k, v = kv
@ -19,9 +19,9 @@ class Solution(BaseSolution):
k = kv[0] k = kv[0]
v = None v = None
if a in actions: if a in actions:
if a == 'add' and k in registry: if a == "add" and k in registry:
registry[k] += registry[v] if v in registry else int(v) registry[k] += registry[v] if v in registry else int(v)
if a == 'jgz': # damn you, 'jgz 1 3' if a == "jgz": # damn you, 'jgz 1 3'
try: try:
k = int(k) k = int(k)
except ValueError: except ValueError:
@ -31,25 +31,25 @@ class Solution(BaseSolution):
except ValueError: except ValueError:
v = registry[v] if v in registry else 1 v = registry[v] if v in registry else 1
return v if k > 0 else 1 return v if k > 0 else 1
if a == 'mod' and k in registry: if a == "mod" and k in registry:
registry[k] %= registry[v] if v in registry else int(v) registry[k] %= registry[v] if v in registry else int(v)
if a == 'mul' and k in registry: if a == "mul" and k in registry:
registry[k] *= registry[v] if v in registry else int(v) registry[k] *= registry[v] if v in registry else int(v)
if a == 'set': if a == "set":
registry[k] = registry[v] if v in registry else int(v) registry[k] = registry[v] if v in registry else int(v)
if swag_mode: # Part 1: scientific wild-ass guess if swag_mode: # Part 1: scientific wild-ass guess
if a == 'rcv' and registry[k] != 0: if a == "rcv" and registry[k] != 0:
return self.STOP_SIGNAL return self.STOP_SIGNAL
if a == 'snd' and k in registry: if a == "snd" and k in registry:
self.sound_freq = registry[k] self.sound_freq = registry[k]
else: # part 2, actual instructions else: # part 2, actual instructions
if a == 'rcv': if a == "rcv":
if len(self.queue[registry['_id']]) == 0: if len(self.queue[registry["_id"]]) == 0:
return 0 return 0
registry[k] = self.queue[registry['_id']].pop(0) registry[k] = self.queue[registry["_id"]].pop(0)
if a == 'snd': if a == "snd":
self.sent[registry['_id']] += 1 self.sent[registry["_id"]] += 1
q = (registry['_id'] + 1) % 2 q = (registry["_id"] + 1) % 2
kk = registry[k] if k in registry else int(k) kk = registry[k] if k in registry else int(k)
self.queue[q].append(kk) self.queue[q].append(kk)
return 1 return 1
@ -65,7 +65,7 @@ class Solution(BaseSolution):
return self.sound_freq return self.sound_freq
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
registry = {'p': 0, '_id': 0}, {'p': 1, '_id': 1} registry = {"p": 0, "_id": 0}, {"p": 1, "_id": 1}
lines = puzzle_input.splitlines() lines = puzzle_input.splitlines()
i = 0 i = 0
j = 0 j = 0
@ -89,6 +89,6 @@ class Solution(BaseSolution):
return self.sent[1] return self.sent[1]
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -2,48 +2,48 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '19.txt' input_file = "19.txt"
trim_input = False trim_input = False
def __str__(self): def __str__(self):
return 'Day 19: A Series of Tubes' return "Day 19: A Series of Tubes"
def _walk_maze(self, puzzle_input): def _walk_maze(self, puzzle_input):
DIRECTIONS = { DIRECTIONS = {
'D': (1, 0), "D": (1, 0),
'U': (-1, 0), "U": (-1, 0),
'R': (0, 1), "R": (0, 1),
'L': (0, -1), "L": (0, -1),
} }
maze = puzzle_input.splitlines() maze = puzzle_input.splitlines()
pos = (0, list(maze[0]).index('|')) pos = (0, list(maze[0]).index("|"))
d = DIRECTIONS['D'] d = DIRECTIONS["D"]
paths = '-|' paths = "-|"
steps = 0 steps = 0
seen = '' seen = ""
def _nc(nu): def _nc(nu):
np = (pos[0] + nu[0], pos[1] + nu[1]) np = (pos[0] + nu[0], pos[1] + nu[1])
if np[0] < len(maze) and np[1] < len(maze[np[0]]): if np[0] < len(maze) and np[1] < len(maze[np[0]]):
return maze[np[0]][np[1]] return maze[np[0]][np[1]]
else: else:
return ' ' return " "
while True: while True:
pos = (pos[0] + d[0], pos[1] + d[1]) pos = (pos[0] + d[0], pos[1] + d[1])
c = _nc((0, 0)) c = _nc((0, 0))
steps += 1 steps += 1
if c == '+': if c == "+":
nc = _nc(d) nc = _nc(d)
if nc == ' ': if nc == " ":
for v in DIRECTIONS.values(): for v in DIRECTIONS.values():
if -v[0] == d[0] and -v[1] == d[1]: if -v[0] == d[0] and -v[1] == d[1]:
continue continue
nc = _nc(v) nc = _nc(v)
if nc != ' ': if nc != " ":
d = v d = v
break break
elif c == ' ': elif c == " ":
break break
elif c not in paths: elif c not in paths:
seen += c seen += c
@ -58,6 +58,6 @@ class Solution(BaseSolution):
return steps return steps
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -6,15 +6,18 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '20.txt' input_file = "20.txt"
def __str__(self): def __str__(self):
return 'Day 20: Particle Swarm' return "Day 20: Particle Swarm"
def _get_particle(self, line): def _get_particle(self, line):
return [list(map(int, coordinate.split(','))) for coordinate in re.findall(r'.=<([^>]+)>', line)] return [
list(map(int, coordinate.split(",")))
for coordinate in re.findall(r".=<([^>]+)>", line)
]
def solve(self, puzzle_input, ticks=10 ** 4): def solve(self, puzzle_input, ticks=10**4):
particles = [self._get_particle(line) for line in puzzle_input.splitlines()] particles = [self._get_particle(line) for line in puzzle_input.splitlines()]
distances = [[] for _ in range(len(particles))] distances = [[] for _ in range(len(particles))]
for _ in range(ticks): for _ in range(ticks):
@ -27,10 +30,13 @@ class Solution(BaseSolution):
p[1] += v[1] p[1] += v[1]
p[2] += v[2] p[2] += v[2]
distances[i].append(sum(map(abs, p))) distances[i].append(sum(map(abs, p)))
d = sorted(map(lambda d: (d[0], sum(d[1]) / len(d[1])), enumerate(distances)), key=lambda x: x[1]) d = sorted(
map(lambda d: (d[0], sum(d[1]) / len(d[1])), enumerate(distances)),
key=lambda x: x[1],
)
return d[0][0] return d[0][0]
def solve_again(self, puzzle_input, ticks=10 ** 3): def solve_again(self, puzzle_input, ticks=10**3):
particles = [self._get_particle(line) for line in puzzle_input.splitlines()] particles = [self._get_particle(line) for line in puzzle_input.splitlines()]
for _ in range(ticks): for _ in range(ticks):
positions = collections.defaultdict(list) positions = collections.defaultdict(list)
@ -42,7 +48,7 @@ class Solution(BaseSolution):
p[0] += v[0] p[0] += v[0]
p[1] += v[1] p[1] += v[1]
p[2] += v[2] p[2] += v[2]
k = '-'.join(map(str, p)) k = "-".join(map(str, p))
positions[k].append(particle) positions[k].append(particle)
for duplicates in positions.values(): for duplicates in positions.values():
if len(duplicates) > 1: if len(duplicates) > 1:
@ -51,6 +57,6 @@ class Solution(BaseSolution):
return len(particles) return len(particles)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -7,9 +7,9 @@ class Rule:
size = 0 size = 0
def __init__(self, line): def __init__(self, line):
pattern, output = line.split(' => ') pattern, output = line.split(" => ")
self.pattern = pattern.replace('/', '') self.pattern = pattern.replace("/", "")
self.output = output.replace('/', '') self.output = output.replace("/", "")
self.size = int(len(self.pattern) ** 0.5) self.size = int(len(self.pattern) ** 0.5)
self.patterns = [ self.patterns = [
@ -22,13 +22,18 @@ class Rule:
] ]
def __repr__(self): def __repr__(self):
return '[{}] {} -> {}'.format(self.size, self.pattern, self.output) return "[{}] {} -> {}".format(self.size, self.pattern, self.output)
def _r(self, b): def _r(self, b):
return ''.join(map(lambda g: ''.join(g), zip(*[b[s:s + self.size] for s in range(0, len(b), self.size)][::-1]))) return "".join(
map(
lambda g: "".join(g),
zip(*[b[s : s + self.size] for s in range(0, len(b), self.size)][::-1]),
)
)
def _f(self, b): def _f(self, b):
return b[-self.size:] + b[self.size:len(b) - self.size] + b[0:self.size] return b[-self.size :] + b[self.size : len(b) - self.size] + b[0 : self.size]
def matches(self, canvas): def matches(self, canvas):
return canvas in self.patterns return canvas in self.patterns
@ -38,13 +43,13 @@ class Rule:
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '21.txt' input_file = "21.txt"
def __str__(self): def __str__(self):
return 'Day 21: Fractal Art' return "Day 21: Fractal Art"
def _get_block(self, canvas, size, n=0): def _get_block(self, canvas, size, n=0):
s = '' s = ""
cl = int(len(canvas) ** 0.5) cl = int(len(canvas) ** 0.5)
x = n % (cl // size) x = n % (cl // size)
y = n // (cl // size) y = n // (cl // size)
@ -56,20 +61,22 @@ class Solution(BaseSolution):
def _join_blocks(self, blocks): def _join_blocks(self, blocks):
bl = len(blocks) bl = len(blocks)
c = int(bl ** 0.5) c = int(bl**0.5)
rl = int(len(blocks[0]) ** 0.5) rl = int(len(blocks[0]) ** 0.5)
canvas = '' canvas = ""
for i in range(0, bl, c): for i in range(0, bl, c):
for j in range(rl): for j in range(rl):
canvas += ''.join([block[j * rl:(j + 1) * rl] for block in blocks[i:i + c]]) canvas += "".join(
[block[j * rl : (j + 1) * rl] for block in blocks[i : i + c]]
)
return canvas return canvas
def solve(self, puzzle_input, iterations=5): def solve(self, puzzle_input, iterations=5):
canvas = '.#...####' canvas = ".#...####"
rules = [Rule(l.strip()) for l in puzzle_input.splitlines()] rules = [Rule(l.strip()) for l in puzzle_input.splitlines()]
for _ in range(iterations): for _ in range(iterations):
size = 2 if len(canvas) % 2 == 0 else 3 size = 2 if len(canvas) % 2 == 0 else 3
blocks = len(canvas) // (size ** 2) blocks = len(canvas) // (size**2)
cb = [] cb = []
for b in range(blocks): for b in range(blocks):
bc = self._get_block(canvas, size, b) bc = self._get_block(canvas, size, b)
@ -78,12 +85,12 @@ class Solution(BaseSolution):
r = rule[0] r = rule[0]
cb.append(r.enhance(bc)) cb.append(r.enhance(bc))
canvas = self._join_blocks(cb) canvas = self._join_blocks(cb)
return collections.Counter(canvas)['#'] return collections.Counter(canvas)["#"]
def solve_again(self, puzzle_input): def solve_again(self, puzzle_input):
return self.solve(puzzle_input, 18) return self.solve(puzzle_input, 18)
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -4,10 +4,10 @@ from solutions import BaseSolution
class Solution(BaseSolution): class Solution(BaseSolution):
input_file = '22.txt' input_file = "22.txt"
def __str__(self): def __str__(self):
return 'Day 22: Sporifica Virus' return "Day 22: Sporifica Virus"
infected = 0 infected = 0
@ -50,7 +50,7 @@ class Solution(BaseSolution):
dirs = dirs[1:] + [dirs[0]] dirs = dirs[1:] + [dirs[0]]
elif state == "#": elif state == "#":
dirs = [dirs[3]] + dirs[:3] dirs = [dirs[3]] + dirs[:3]
elif state == 'F': elif state == "F":
dirs = dirs[2:] + dirs[:2] dirs = dirs[2:] + dirs[:2]
return dirs return dirs
@ -61,16 +61,16 @@ class Solution(BaseSolution):
i, p = existing i, p = existing
return amap, p[2] return amap, p[2]
else: else:
amap.append([pos[0], pos[1], '.']) amap.append([pos[0], pos[1], "."])
return amap, '.' return amap, "."
def _update_state(self, amap, pos): def _update_state(self, amap, pos):
t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1] t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1]
existing = next(filter(t, enumerate(amap))) existing = next(filter(t, enumerate(amap)))
i, p = existing i, p = existing
if p[2] == '.': if p[2] == ".":
self.infected += 1 self.infected += 1
amap[i][2] = '.' if p[2] == '#' else '#' amap[i][2] = "." if p[2] == "#" else "#"
return amap return amap
def _move(self, pos, d): def _move(self, pos, d):
@ -80,12 +80,12 @@ class Solution(BaseSolution):
t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1] t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1]
existing = next(filter(t, enumerate(amap))) existing = next(filter(t, enumerate(amap)))
i, p = existing i, p = existing
if p[2] == '.': if p[2] == ".":
ns = 'W' ns = "W"
elif p[2] == 'W': elif p[2] == "W":
self.infected += 1 self.infected += 1
ns = "#" ns = "#"
elif p[2] == '#': elif p[2] == "#":
ns = "F" ns = "F"
else: else:
ns = "." ns = "."
@ -93,6 +93,6 @@ class Solution(BaseSolution):
return amap return amap
if __name__ == '__main__': if __name__ == "__main__":
solution = Solution() solution = Solution()
solution.show_results() solution.show_results()

View file

@ -8,18 +8,18 @@ class Day1TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_sums_equal_pairs(self): def test_sums_equal_pairs(self):
assert self.solution.solve('1122') == 3 assert self.solution.solve("1122") == 3
assert self.solution.solve('1111') == 4 assert self.solution.solve("1111") == 4
assert self.solution.solve('1234') == 0 assert self.solution.solve("1234") == 0
assert self.solution.solve('91212129') == 9 assert self.solution.solve("91212129") == 9
def test_sums_equal_pairs_halvway_around(self): def test_sums_equal_pairs_halvway_around(self):
assert self.solution.solve_again('1212') == 6 assert self.solution.solve_again("1212") == 6
assert self.solution.solve_again('1221') == 0 assert self.solution.solve_again("1221") == 0
assert self.solution.solve_again('123425') == 4 assert self.solution.solve_again("123425") == 4
assert self.solution.solve_again('123123') == 12 assert self.solution.solve_again("123123") == 12
assert self.solution.solve_again('12131415') == 4 assert self.solution.solve_again("12131415") == 4
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -13,19 +13,19 @@ class Day2TestCase(unittest.TestCase):
assert self.solution.get_diff([2, 4, 6, 8]) == 6 assert self.solution.get_diff([2, 4, 6, 8]) == 6
def test_calculates_checksum(self): def test_calculates_checksum(self):
puzzle_input = '\n'.join(['5 1 9 5', '7 5 3', '2 4 6 8']) puzzle_input = "\n".join(["5 1 9 5", "7 5 3", "2 4 6 8"])
assert self.solution.solve(puzzle_input) == 18 assert self.solution.solve(puzzle_input) == 18
def test_calculates_row_even_divisible(self): def test_calculates_row_even_divisible(self):
puzzle_input = '\n'.join(['5 9 2 8', '9 4 7 3', '3 8 6 5']) puzzle_input = "\n".join(["5 9 2 8", "9 4 7 3", "3 8 6 5"])
assert self.solution.get_even_divisible([5, 9, 2, 8]) == 4 assert self.solution.get_even_divisible([5, 9, 2, 8]) == 4
assert self.solution.get_even_divisible([9, 4, 7, 3]) == 3 assert self.solution.get_even_divisible([9, 4, 7, 3]) == 3
assert self.solution.get_even_divisible([3, 8, 6, 5]) == 2 assert self.solution.get_even_divisible([3, 8, 6, 5]) == 2
def test_calculates_row_result_sum(self): def test_calculates_row_result_sum(self):
puzzle_input = '\n'.join(['5 9 2 8', '9 4 7 3', '3 8 6 5']) puzzle_input = "\n".join(["5 9 2 8", "9 4 7 3", "3 8 6 5"])
assert self.solution.solve_again(puzzle_input) == 9 assert self.solution.solve_again(puzzle_input) == 9
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,11 +8,11 @@ class Day3TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_shortest_manhattan_distance(self): def test_shortest_manhattan_distance(self):
assert self.solution.solve('1') == 0 assert self.solution.solve("1") == 0
assert self.solution.solve('12') == 3 assert self.solution.solve("12") == 3
assert self.solution.solve('23') == 2 assert self.solution.solve("23") == 2
assert self.solution.solve('1024') == 31 assert self.solution.solve("1024") == 31
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -9,22 +9,22 @@ class Day4TestCase(unittest.TestCase):
def test_passphrase_has_only_unique_words(self): def test_passphrase_has_only_unique_words(self):
passphrases = [ passphrases = [
'aa bb cc dd ee', "aa bb cc dd ee",
'aa bb cc dd aa', "aa bb cc dd aa",
'aa bb cc dd aaa', "aa bb cc dd aaa",
] ]
assert self.solution.validate(passphrases[0]) == True assert self.solution.validate(passphrases[0]) == True
assert self.solution.validate(passphrases[1]) == False assert self.solution.validate(passphrases[1]) == False
assert self.solution.validate(passphrases[2]) == True assert self.solution.validate(passphrases[2]) == True
assert self.solution.solve('\n'.join(passphrases)) == 2 assert self.solution.solve("\n".join(passphrases)) == 2
def test_passphrase_has_no_anagrams(self): def test_passphrase_has_no_anagrams(self):
passphrases = [ passphrases = [
'abcde fghij', "abcde fghij",
'abcde xyz ecdab', "abcde xyz ecdab",
'a ab abc abd abf abj', "a ab abc abd abf abj",
'iiii oiii ooii oooi oooo', "iiii oiii ooii oooi oooo",
'oiii ioii iioi iiio', "oiii ioii iioi iiio",
] ]
assert self.solution.validate(passphrases[0], True) == True assert self.solution.validate(passphrases[0], True) == True
assert self.solution.validate(passphrases[1], True) == False assert self.solution.validate(passphrases[1], True) == False
@ -33,5 +33,5 @@ class Day4TestCase(unittest.TestCase):
assert self.solution.validate(passphrases[4], True) == False assert self.solution.validate(passphrases[4], True) == False
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,13 +8,29 @@ class Day5TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_calculate_exit_distance(self): def test_calculate_exit_distance(self):
puzzle_input = '\n'.join(['0', '3', '0', '1', '-3',]) puzzle_input = "\n".join(
[
"0",
"3",
"0",
"1",
"-3",
]
)
assert self.solution.solve(puzzle_input) == 5 assert self.solution.solve(puzzle_input) == 5
def test_calculate_stranger_exit_distance(self): def test_calculate_stranger_exit_distance(self):
puzzle_input = '\n'.join(['0', '3', '0', '1', '-3',]) puzzle_input = "\n".join(
[
"0",
"3",
"0",
"1",
"-3",
]
)
assert self.solution.solve_again(puzzle_input) == 10 assert self.solution.solve_again(puzzle_input) == 10
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,7 +8,7 @@ class Day6TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_count_redistribution_cycles(self): def test_count_redistribution_cycles(self):
puzzle_input = '0 2 7 0' puzzle_input = "0 2 7 0"
banks = list(map(int, puzzle_input.split())) banks = list(map(int, puzzle_input.split()))
assert self.solution.redistribute(banks) == (2, 4, 1, 2) assert self.solution.redistribute(banks) == (2, 4, 1, 2)
assert self.solution.redistribute((2, 4, 1, 2)) == (3, 1, 2, 3) assert self.solution.redistribute((2, 4, 1, 2)) == (3, 1, 2, 3)
@ -18,9 +18,9 @@ class Day6TestCase(unittest.TestCase):
assert self.solution.solve(puzzle_input) == 5 assert self.solution.solve(puzzle_input) == 5
def test_count_redistribution_cycles_again(self): def test_count_redistribution_cycles_again(self):
puzzle_input = '0 2 7 0' puzzle_input = "0 2 7 0"
assert self.solution.solve_again(puzzle_input) == 4 assert self.solution.solve_again(puzzle_input) == 4
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -5,7 +5,7 @@ from solutions.day_07 import Solution, Program
class Day7TestCase(unittest.TestCase): class Day7TestCase(unittest.TestCase):
def setUp(self): def setUp(self):
self.puzzle_input = ''' self.puzzle_input = """
pbga (66) pbga (66)
xhth (57) xhth (57)
ebii (61) ebii (61)
@ -19,24 +19,24 @@ class Day7TestCase(unittest.TestCase):
ugml (68) -> gyxo, ebii, jptl ugml (68) -> gyxo, ebii, jptl
gyxo (61) gyxo (61)
cntj (57) cntj (57)
'''.strip() """.strip()
self.solution = Solution() self.solution = Solution()
def test_find_bottom_tower(self): def test_find_bottom_tower(self):
p = Program('ugml (68) -> gyxo, ebii, jptl') p = Program("ugml (68) -> gyxo, ebii, jptl")
assert p.name == 'ugml' assert p.name == "ugml"
assert p.weight == 68 assert p.weight == 68
assert p.disc == ('gyxo', 'ebii', 'jptl') assert p.disc == ("gyxo", "ebii", "jptl")
p = Program('jptl (61)') p = Program("jptl (61)")
assert p.name == 'jptl' assert p.name == "jptl"
assert p.weight == 61 assert p.weight == 61
assert p.disc == () assert p.disc == ()
assert self.solution.solve(self.puzzle_input).name == 'tknk' assert self.solution.solve(self.puzzle_input).name == "tknk"
def test_find_weight_correction(self): def test_find_weight_correction(self):
corrected = self.solution.solve_again(self.puzzle_input) corrected = self.solution.solve_again(self.puzzle_input)
assert corrected == 60 assert corrected == 60
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,23 +8,23 @@ class Day8TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_largest_registry_value(self): def test_largest_registry_value(self):
puzzle_input = ''' puzzle_input = """
b inc 5 if a > 1 b inc 5 if a > 1
a inc 1 if b < 5 a inc 1 if b < 5
c dec -10 if a >= 1 c dec -10 if a >= 1
c inc -20 if c == 10 c inc -20 if c == 10
'''.strip() """.strip()
assert self.solution.solve(puzzle_input) == 1 assert self.solution.solve(puzzle_input) == 1
def test_largest_ath_registry_value(self): def test_largest_ath_registry_value(self):
puzzle_input = ''' puzzle_input = """
b inc 5 if a > 1 b inc 5 if a > 1
a inc 1 if b < 5 a inc 1 if b < 5
c dec -10 if a >= 1 c dec -10 if a >= 1
c inc -20 if c == 10 c inc -20 if c == 10
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input) == 10 assert self.solution.solve_again(puzzle_input) == 10
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,24 +8,24 @@ class Day9TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_calculates_score(self): def test_calculates_score(self):
assert self.solution.solve('{}') == 1 assert self.solution.solve("{}") == 1
assert self.solution.solve('{{{}}}') == 6 assert self.solution.solve("{{{}}}") == 6
assert self.solution.solve('{{},{}}') == 5 assert self.solution.solve("{{},{}}") == 5
assert self.solution.solve('{{{},{},{{}}}}') == 16 assert self.solution.solve("{{{},{},{{}}}}") == 16
assert self.solution.solve('{<a>,<a>,<a>,<a>}') == 1 assert self.solution.solve("{<a>,<a>,<a>,<a>}") == 1
assert self.solution.solve('{{<ab>},{<ab>},{<ab>},{<ab>}}') == 9 assert self.solution.solve("{{<ab>},{<ab>},{<ab>},{<ab>}}") == 9
assert self.solution.solve('{{<!!>},{<!!>},{<!!>},{<!!>}}') == 9 assert self.solution.solve("{{<!!>},{<!!>},{<!!>},{<!!>}}") == 9
assert self.solution.solve('{{<a!>},{<a!>},{<a!>},{<ab>}}') == 3 assert self.solution.solve("{{<a!>},{<a!>},{<a!>},{<ab>}}") == 3
def test_count_garbage(self): def test_count_garbage(self):
assert self.solution.solve_again('<>') == 0 assert self.solution.solve_again("<>") == 0
assert self.solution.solve_again('<random characters>') == 17 assert self.solution.solve_again("<random characters>") == 17
assert self.solution.solve_again('<<<<>') == 3 assert self.solution.solve_again("<<<<>") == 3
assert self.solution.solve_again('<{!>}>') == 2 assert self.solution.solve_again("<{!>}>") == 2
assert self.solution.solve_again('<!!>') == 0 assert self.solution.solve_again("<!!>") == 0
assert self.solution.solve_again('<!!!>>') == 0 assert self.solution.solve_again("<!!!>>") == 0
assert self.solution.solve_again('<{o"i!a,<{i<a>') == 10 assert self.solution.solve_again('<{o"i!a,<{i<a>') == 10
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -25,14 +25,16 @@ class Day10TestCase(unittest.TestCase):
assert self.solution.list == [3, 4, 2, 1, 0] assert self.solution.list == [3, 4, 2, 1, 0]
assert self.solution.skip_size == 4 assert self.solution.skip_size == 4
assert self.solution.pos == 4 assert self.solution.pos == 4
assert self.solution.solve('3,4,1,5', r=5) == 12 assert self.solution.solve("3,4,1,5", r=5) == 12
def test_dense_hash(self): def test_dense_hash(self):
assert self.solution.solve_again('') == 'a2582a3a0e66e6e86e3812dcb672a272' assert self.solution.solve_again("") == "a2582a3a0e66e6e86e3812dcb672a272"
assert self.solution.solve_again('AoC 2017') == '33efeb34ea91902bb2f59c9920caa6cd' assert (
assert self.solution.solve_again('1,2,3') == '3efbe78a8d82f29979031a4aa0b16a9d' self.solution.solve_again("AoC 2017") == "33efeb34ea91902bb2f59c9920caa6cd"
assert self.solution.solve_again('1,2,4') == '63960835bcdc130f0b66d7ff4f6a5a8e' )
assert self.solution.solve_again("1,2,3") == "3efbe78a8d82f29979031a4aa0b16a9d"
assert self.solution.solve_again("1,2,4") == "63960835bcdc130f0b66d7ff4f6a5a8e"
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,15 +8,15 @@ class Day11TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_distance(self): def test_distance(self):
assert self.solution.solve('ne,ne,ne') == 3 assert self.solution.solve("ne,ne,ne") == 3
assert self.solution.solve('ne,ne,sw,sw') == 0 assert self.solution.solve("ne,ne,sw,sw") == 0
assert self.solution.solve('ne,ne,s,s') == 2 assert self.solution.solve("ne,ne,s,s") == 2
assert self.solution.solve('se,sw,se,sw,sw') == 3 assert self.solution.solve("se,sw,se,sw,sw") == 3
def test_furthest_away(self): def test_furthest_away(self):
assert self.solution.solve_again('ne,ne,sw,sw') == 2 assert self.solution.solve_again("ne,ne,sw,sw") == 2
assert self.solution.solve_again('se,sw,se,sw,sw') == 3 assert self.solution.solve_again("se,sw,se,sw,sw") == 3
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,7 +8,7 @@ class Day12TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_connected_to_program0(self): def test_connected_to_program0(self):
puzzle_input = ''' puzzle_input = """
0 <-> 2 0 <-> 2
1 <-> 1 1 <-> 1
2 <-> 0, 3, 4 2 <-> 0, 3, 4
@ -16,11 +16,11 @@ class Day12TestCase(unittest.TestCase):
4 <-> 2, 3, 6 4 <-> 2, 3, 6
5 <-> 6 5 <-> 6
6 <-> 4, 5 6 <-> 4, 5
'''.strip() """.strip()
assert self.solution.solve(puzzle_input) == 6 assert self.solution.solve(puzzle_input) == 6
def test_group_coun(self): def test_group_coun(self):
puzzle_input = ''' puzzle_input = """
0 <-> 2 0 <-> 2
1 <-> 1 1 <-> 1
2 <-> 0, 3, 4 2 <-> 0, 3, 4
@ -28,9 +28,9 @@ class Day12TestCase(unittest.TestCase):
4 <-> 2, 3, 6 4 <-> 2, 3, 6
5 <-> 6 5 <-> 6
6 <-> 4, 5 6 <-> 4, 5
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input) == 2 assert self.solution.solve_again(puzzle_input) == 2
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,23 +8,23 @@ class Day13TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_get_through_firewall(self): def test_get_through_firewall(self):
puzzle_input = ''' puzzle_input = """
0: 3 0: 3
1: 2 1: 2
4: 4 4: 4
6: 4 6: 4
'''.strip() """.strip()
assert self.solution.solve(puzzle_input) == 24 assert self.solution.solve(puzzle_input) == 24
def test_wait(self): def test_wait(self):
puzzle_input = ''' puzzle_input = """
0: 3 0: 3
1: 2 1: 2
4: 4 4: 4
6: 4 6: 4
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input) == 10 assert self.solution.solve_again(puzzle_input) == 10
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,11 +8,11 @@ class Day14TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_used_squares(self): def test_used_squares(self):
assert self.solution.solve('flqrgnkx') == 8108 assert self.solution.solve("flqrgnkx") == 8108
def test_regions(self): def test_regions(self):
assert self.solution.solve_again('flqrgnkx') == 1242 assert self.solution.solve_again("flqrgnkx") == 1242
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,19 +8,19 @@ class Day15TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_40m_pairs(self): def test_40m_pairs(self):
puzzle_input = ''' puzzle_input = """
Generator A starts with 65 Generator A starts with 65
Generator B starts with 8921 Generator B starts with 8921
'''.strip() """.strip()
#assert self.solution.solve(puzzle_input) == 588 # assert self.solution.solve(puzzle_input) == 588
def test_5k_pairs(self): def test_5k_pairs(self):
puzzle_input = ''' puzzle_input = """
Generator A starts with 65 Generator A starts with 65
Generator B starts with 8921 Generator B starts with 8921
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input) == 309 assert self.solution.solve_again(puzzle_input) == 309
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,9 +8,9 @@ class Day16TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_something(self): def test_something(self):
puzzle_input = '''s1,x3/4,pe/b'''.strip() puzzle_input = """s1,x3/4,pe/b""".strip()
assert self.solution.solve(puzzle_input, 5) == 'baedc' assert self.solution.solve(puzzle_input, 5) == "baedc"
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,8 +8,8 @@ class Day17TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_something(self): def test_something(self):
assert self.solution.solve('3') == 638 assert self.solution.solve("3") == 638
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,7 +8,7 @@ class Day18TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_something(self): def test_something(self):
puzzle_input = ''' puzzle_input = """
set a 1 set a 1
add a 2 add a 2
mul a a mul a a
@ -19,11 +19,11 @@ class Day18TestCase(unittest.TestCase):
jgz a -1 jgz a -1
set a 1 set a 1
jgz a -2 jgz a -2
'''.strip() """.strip()
assert self.solution.solve(puzzle_input) == 4 assert self.solution.solve(puzzle_input) == 4
def test_something_else(self): def test_something_else(self):
puzzle_input = ''' puzzle_input = """
snd 1 snd 1
snd 2 snd 2
snd p snd p
@ -31,9 +31,9 @@ class Day18TestCase(unittest.TestCase):
rcv b rcv b
rcv c rcv c
rcv d rcv d
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input) == 3 assert self.solution.solve_again(puzzle_input) == 3
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,27 +8,27 @@ class Day19TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_seen(self): def test_seen(self):
puzzle_input = ''' | puzzle_input = """ |
| +--+ | +--+
A | C A | C
F---|----E|--+ F---|----E|--+
| | | D | | | D
+B-+ +--+ +B-+ +--+
''' """
assert self.solution.solve(puzzle_input) == 'ABCDEF' assert self.solution.solve(puzzle_input) == "ABCDEF"
def test_steps(self): def test_steps(self):
puzzle_input = ''' | puzzle_input = """ |
| +--+ | +--+
A | C A | C
F---|----E|--+ F---|----E|--+
| | | D | | | D
+B-+ +--+ +B-+ +--+
''' """
assert self.solution.solve_again(puzzle_input) == 38 assert self.solution.solve_again(puzzle_input) == 38
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,21 +8,21 @@ class Day20TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_shortest_distance_over_time(self): def test_shortest_distance_over_time(self):
puzzle_input = ''' puzzle_input = """
p=< 3,0,0>, v=< 2,0,0>, a=<-1,0,0> p=< 3,0,0>, v=< 2,0,0>, a=<-1,0,0>
p=< 4,0,0>, v=< 0,0,0>, a=<-2,0,0> p=< 4,0,0>, v=< 0,0,0>, a=<-2,0,0>
'''.strip() """.strip()
assert self.solution.solve(puzzle_input, 4) == 0 assert self.solution.solve(puzzle_input, 4) == 0
def test_something(self): def test_something(self):
puzzle_input = ''' puzzle_input = """
p=<-6,0,0>, v=< 3,0,0>, a=< 0,0,0> p=<-6,0,0>, v=< 3,0,0>, a=< 0,0,0>
p=<-4,0,0>, v=< 2,0,0>, a=< 0,0,0> p=<-4,0,0>, v=< 2,0,0>, a=< 0,0,0>
p=<-2,0,0>, v=< 1,0,0>, a=< 0,0,0> p=<-2,0,0>, v=< 1,0,0>, a=< 0,0,0>
p=< 3,0,0>, v=<-1,0,0>, a=< 0,0,0> p=< 3,0,0>, v=<-1,0,0>, a=< 0,0,0>
'''.strip() """.strip()
assert self.solution.solve_again(puzzle_input, 4) == 1 assert self.solution.solve_again(puzzle_input, 4) == 1
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -8,12 +8,12 @@ class Day21TestCase(unittest.TestCase):
self.solution = Solution() self.solution = Solution()
def test_something(self): def test_something(self):
puzzle_input = ''' puzzle_input = """
../.# => ##./#../... ../.# => ##./#../...
.#./..#/### => #..#/..../..../#..# .#./..#/### => #..#/..../..../#..#
'''.strip() """.strip()
assert self.solution.solve(puzzle_input, 2) == 12 assert self.solution.solve(puzzle_input, 2) == 12
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -26,5 +26,6 @@ class Day22TestCase(unittest.TestCase):
assert self.solution.solve_again(puzzle_input, 100) == 26 assert self.solution.solve_again(puzzle_input, 100) == 26
assert self.solution.solve_again(puzzle_input, 10000000) == 2511944 assert self.solution.solve_again(puzzle_input, 10000000) == 2511944
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main() unittest.main()