Day 23 - Advent of Code 2022

Working solutions for the day 23 puzzles.

Part One

""" day_23_01.py """

# usage: python3 day_23_01.py < input


import sys


def parse(raw_location_data):
    """ create object """
    output = set()
    x, y = 0, 0
    for item in raw_location_data:
        if item == '\n':
            x, y = 0, y + 1
            continue
        if item == '#':
            output.add((x, y))
        x += 1
    return output


deltas = {'n': (0, -1), 'ne': (1, -1), 'e': (1, 0), 'se': (1, 1),
          's': (0, 1), 'sw': (-1, 1), 'w': (-1, 0), 'nw': (-1, -1)}


def adjacent(dirs, point, elf_data):
    """ count adjacent to point in dirs """
    tally = 0
    for d in dirs:
        dx, dy = deltas[d]
        if (point[0] + dx, point[1] + dy) in elf_data:
            tally += 1
    return tally


elves = parse(sys.stdin.read())
options = {'all': ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'],
           0: ['n', 'ne', 'nw'], 1: ['s', 'se', 'sw'],
           2: ['w', 'nw', 'sw'], 3: ['e', 'ne', 'se']}

option = 0
rounds = 10
while rounds > 0:
    rounds -= 1
    proposed = {}
    for elf in elves:
        count = adjacent(options['all'], elf, elves)
        if count == 0:
            continue
        for i in range(option, option + 4):
            count = adjacent(options[i % 4], elf, elves)
            if count == 0:
                proposed[elf] = deltas[options[i % 4][0]]
                break
    option = (option + 1) % 4
    if not proposed:
        break
    moves = [(x + dx, y + dy) for (x, y), (dx, dy) in proposed.items()]
    for elf in elves.copy():
        if elf in proposed:
            move = elf[0] + proposed[elf][0], elf[1] + proposed[elf][1]
            if moves.count(move) == 1:
                elves.remove(elf)
                elves.add(move)

x_range, y_range = [x for x, _ in elves], [y for _, y in elves]

count = 0
for x_coord in range(min(x_range), max(x_range) + 1):
    for y_coord in range(min(y_range), max(y_range) + 1):
        if (x_coord, y_coord) not in elves:
            count += 1
print(count)

Part Two

""" day_23_02.py """

# usage: python3 day_23_02.py < input


import sys


def parse(raw_location_data):
    """ create object """
    output = set()
    x, y = 0, 0
    for item in raw_location_data:
        if item == '\n':
            x, y = 0, y + 1
            continue
        if item == '#':
            output.add((x, y))
        x += 1
    return output


deltas = {'n': (0, -1), 'ne': (1, -1), 'e': (1, 0), 'se': (1, 1),
          's': (0, 1), 'sw': (-1, 1), 'w': (-1, 0), 'nw': (-1, -1)}


def adjacent(dirs, point, elf_data):
    """ count adjacent to point in dirs """
    tally = 0
    for d in dirs:
        dx, dy = deltas[d]
        if (point[0] + dx, point[1] + dy) in elf_data:
            tally += 1
    return tally


elves = parse(sys.stdin.read())
options = {'all': ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'],
           0: ['n', 'ne', 'nw'], 1: ['s', 'se', 'sw'],
           2: ['w', 'nw', 'sw'], 3: ['e', 'ne', 'se']}

option = 0
rounds = 0
while True:
    rounds += 1
    proposed = {}
    for elf in elves:
        count = adjacent(options['all'], elf, elves)
        if count == 0:
            continue
        for i in range(option, option + 4):
            count = adjacent(options[i % 4], elf, elves)
            if count == 0:
                proposed[elf] = deltas[options[i % 4][0]]
                break
    option = (option + 1) % 4
    if not proposed:
        break
    moves = [(x + dx, y + dy) for (x, y), (dx, dy) in proposed.items()]
    for elf in elves.copy():
        if elf in proposed:
            move = elf[0] + proposed[elf][0], elf[1] + proposed[elf][1]
            if moves.count(move) == 1:
                elves.remove(elf)
                elves.add(move)
print(rounds)