Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


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