2021-12-20 - Trench Map
(original .ipynb)
Day 20 puzzle input is the input parameter for an image enhancement algorithm and a small 5x5 image to be enhanced (mine is here). Part 1 involves implementing the defined enhancement algorithm, applying it two times and finding the number of #
pixels. Part 2 involves doing the same but applying the algorithm 50 times.
test_input_str = """..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..## #..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.### .######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#. .#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#..... .#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.. ...####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#..... ..##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# #..#. #.... ##..# ..#.. ..###""" puzzle_input_str = open("puzzle_input/day20.txt").read() from advent import grid_animated_render_frame, grid_animated_combine def parse_image(image_str): image = [] for line in image_str.split("\n"): image.append([c for c in line]) return image def parse_input(input_str): algo_str, image_str = input_str.split("\n\n") return algo_str.replace("\n", ""), parse_image(image_str) def dump_image(image): for line in image: print("".join(line)) def grow_image(image, pad): if "#" in image[0]: # image.insert(0, ["."]*len(image[0])) image.insert(0, [pad]*len(image[0])) if "#" in image[-1]: # image.append(["."]*len(image[-1])) image.append([pad]*len(image[-1])) leftmost_chars = [row[0] for row in image] if "#" in leftmost_chars: for r in range(len(image)): image[r].insert(0, pad) rightmost_chars = [row[-1] for row in image] if "#" in rightmost_chars: for r in range(len(image)): image[r].append(pad) def get_pixel(image, r, c, pad): if r < 0 or r >= len(image): return pad if c < 0 or c >= len(image[r]): return pad # print(len(image), "rows") # print(len(image[0]), "cols") # print("accessing row", r, "col", c) # dump_image(image) return image[r][c] def get_enhancement_index(image, r, c, pad): blob = [] for dr in [-1, 0, 1]: for dc in [-1, 0, 1]: px = get_pixel(image, r+dr, c+dc, pad) #print(r+dr, c+dc, px) blob.append("1" if px == "#" else "0") return int("".join(blob), 2) def enhance(image, algo_str, pad): grow_image(image, pad) new_image = [] for r in range(len(image)): row = [] for c in range(len(image[r])): idx = get_enhancement_index(image, r, c, pad) row.append(algo_str[idx]) new_image.append(row) return new_image def count_lit(image): count = 0 # this is baby stuff, need to write it better for row in image: for col in row: if col == "#": count += 1 return count # def grid_animated_render_frame(grid, palette, cell_size=10, bg_color="white"): # def grid_animated_combine(images, filename, duration=100, loop=0, show=False): palette = { ".": "white", "#": "black" } def create_frame(image): img_size = 300 # image centered in it ... sorta r_pad = (img_size - len(image)) // 2 c_pad = (img_size - len(image[0])) // 2 new_image = [] for r in range(img_size): new_image.append(["."] * img_size) for r, row in enumerate(image): for c, col in enumerate(row): new_image[r_pad+r][c_pad+c] = col return grid_animated_render_frame(new_image, palette, cell_size=1) def part_one(input_str, iterations=2, filename=None): algo_str, image = parse_input(input_str) step = 0 frames = [] while step < iterations: pad = "." if step % 2 == 0 else algo_str[0] image = enhance(image, algo_str, pad) if filename: frames.append(create_frame(image)) step += 1 if filename: grid_animated_combine(frames, filename, duration=250, show=True) return count_lit(image) assert 35 == part_one(test_input_str) print("part one:", part_one(puzzle_input_str, filename="day21-p1.gif"))
part one: 5498
def part_two(input_str, filename=None): # lol return part_one(input_str, 50, filename) assert 3351 == part_two(test_input_str) print("part two:", part_two(puzzle_input_str, filename="day21-p2.gif"))
part two: 16014