""" Animation of solving an AdventOfCode Challenge """ # requires: python-fluepdot, python-dotenv import os from time import perf_counter, sleep from typing import Callable from dotenv import load_dotenv from fluepdot import Fluepdot, Mode load_dotenv() fd = Fluepdot(os.getenv('DOTS_HOST')) fd.set_mode(Mode.DIFFERENTIAL) DELAY = .001 def clear(): x, y = fd.get_size() arr = [[False for _ in range(x)] for _ in range(y)] fd.post_frame(arr) def profiler(method): def profiler_method(*arg, **kw): t = perf_counter() ret = method(*arg, **kw) print(f'{method.__name__} method took : {perf_counter()-t:.4f} sec') return ret return profiler_method def transpose(m): return [''.join([m[j][i] for j in range(len(m))]) for i in range(len(m[0]))] def get_reflection(mirror: list[str]) -> int | Exception: fdx, fdy = fd.get_size() for x in range(1, len(mirror)): sol = True draw_arr = [[False for _ in range(fdx)] for _ in range(fdy)] offset = 0 for ind, (c1, c2) in enumerate(zip(mirror[x:], mirror[x-1::-1])): for i, c in enumerate(c1): if c == '#': draw_arr[ind+offset][i] = True for i, c in enumerate(c2): if c == '#': draw_arr[ind+offset][i+len(c1)+5] = True if c1 == c2: draw_arr[ind+offset][len(c1)+5+len(c2)+5] = True else: sol = False if ind+offset == fdy: fd.post_frame(draw_arr) sleep(DELAY) offset -= fdy else: fd.post_frame(draw_arr) sleep(DELAY) if sol: fd.post_text(f'Mirror at {x}') return x return Exception('No reflection found') def get_reflection2(mirror: list[str]) -> int | Exception: for x in range(len(mirror)): errors = 0 errors += sum(s1!=s2 for c1, c2 in zip(mirror[x:], mirror[x-1::-1]) for s1, s2 in zip(c1, c2)) if errors == 1: return x return Exception('No reflection found') def get_reflection_line(func: Callable[[list[str]], int], mirror: list[str]) -> int: # check for vertical reflection across a horizontal line ind = func(mirror) if isinstance(ind, int): return 100*ind # check for horizontal reflection across a vertical line ind = func(transpose(mirror)) if isinstance(ind, int): return ind raise ind # Part 1: def part1(mirrors: list[list[str]]) -> int: return sum([get_reflection_line(get_reflection, mirror) for mirror in mirrors]) # Part 2: def part2(mirrors: list[list[str]]) -> int: return sum([get_reflection_line(get_reflection2, mirror) for mirror in mirrors]) def get_input(): with open(os.path.dirname(os.path.realpath(__file__))+'/assets/input', 'r', encoding='utf-8') as f: content = [s.strip().split('\n') for s in f.read().rstrip().split('\n\n')] return content @profiler def solve(): mirrors = get_input() fd.post_text(f'Part 1: {part1(mirrors)}') sleep(10) fd.post_text(f'Part 2: {part2(mirrors)}') if __name__ == "__main__": solve()