Advent of Code 2022 day 23

Relatively straightforward, to the extent that I was able to program everything within one file, without having to split off for part 2. Used currying to rotate through the conditionals.

with open("23.txt") as f:
# with open("23_test.txt") as f:
# with open("23_test_test.txt") as f:
    lines = f.read().splitlines()

def clean_card(card):
    min_col = min([
        col
        for col in range(len(card[0]))
        for row in range(len(card))
        if card[row][col] == "#"
    ])
    max_col = max([
        col
        for col in range(len(card[0]))
        for row in range(len(card))
        if card[row][col] == "#"
    ])
    min_row = min([
        row
        for col in range(len(card[0]))
        for row in range(len(card))
        if card[row][col] == "#"
    ])
    max_row = max([
        row
        for col in range(len(card[0]))
        for row in range(len(card))
        if card[row][col] == "#"
    ])
    return [
        [
            card[row][col] for col in range(min_col, max_col+1)
        ] for row in range(min_row, max_row+1)
    ]

def print_card(card):
    card = clean_card(card)
    print(
        "\n".join([
            "".join([
                card[row][col] for col in range(len(card[0]))
            ])
            for row in range(len(card))
        ])
    )

def get_number_of_elves(lines):
    return sum([line.count("#") for line in lines])

def create_initial_card(lines):
    adj = 200
    col = max(len(line) for line in lines)
    row = len(lines)
    return (
        [
            list("."*(adj + col + adj))
            for _ in range(adj)
        ] +
        [
            list("."*adj) + list(line) + list("."*adj)
            for line in lines
        ] +
        [
            list("."*(adj + col + adj))
            for _ in range(adj)
        ]
    )


def can_move_north(card, row, col):
    return all(card[row-1][col+i] == "." for i in range(-1, 2))

def can_move_south(card, row, col):
    return all(card[row+1][col+i] == "." for i in range(-1, 2))

def can_move_west(card, row, col):
    return all(card[row+i][col-1] == "." for i in range(-1, 2))

def can_move_east(card, row, col):
    return all(card[row+i][col+1] == "." for i in range(-1, 2))

def stay_stationary(card, row, col):
    return all(
        cond(card, row, col)
        for cond in (
            can_move_north,
            can_move_south,
            can_move_west,
            can_move_east,
        )
    )

def move_north(move_to, card, row, col):
    if (row-1, col) in move_to:
        move_to[(row-1, col)].add((row-1, col))
        return move_to
    move_to[(row-1, col)] = {(row, col)}
    return move_to

def move_south(move_to, card, row, col):
    if (row+1, col) in move_to:
        move_to[(row+1, col)].add((row, col))
        return move_to
    move_to[(row+1, col)] = {(row, col)}
    return move_to

def move_west(move_to, card, row, col):
    if (row, col-1) in move_to:
        move_to[(row, col-1)].add((row, col))
        return move_to
    move_to[(row, col-1)] = {(row, col)}
    return move_to

def move_east(move_to, card, row, col):
    if (row, col+1) in move_to:
        move_to[(row, col+1)].add((row, col))
        return move_to
    move_to[(row, col+1)] = {(row, col)}
    return move_to

conditionals = [
    (can_move_north, move_north),
    (can_move_south, move_south),
    (can_move_west, move_west),
    (can_move_east, move_east),
]

def update_move_to(move_to, card, row, col, conditionals):
    if stay_stationary(card, row, col):
        return move_to
    for cond in conditionals:
        if cond[0](card, row, col):
            return cond[1](move_to, card, row, col)
    return move_to

initial_card = create_initial_card(lines)

card = initial_card.copy()
# print_card(card)
# print(get_number_of_elves(card))
for round in range(10):
    move_to = dict()
    for row in range(len(card)):
        for col in range(len(card[row])):
            if card[row][col] == "#":
                move_to = update_move_to(move_to, card, row, col, conditionals)
    for key, values in move_to.items():
        if len(values) == 1:
            from_row, from_col = values.pop()
            card[from_row][from_col] = "."
            to_row, to_col = key
            card[to_row][to_col] = "#"
    conditionals = conditionals[1:] + [conditionals[0]]
    # print(round + 1)
    # print_card(card)

card = clean_card(card)
print(len(card) * len(card[0]) - get_number_of_elves(card))

# part 2
card = create_initial_card(lines)
conditionals = [
    (can_move_north, move_north),
    (can_move_south, move_south),
    (can_move_west, move_west),
    (can_move_east, move_east),
]
rounds = 0
while True:
    rounds += 1
    move_to = dict()
    for row in range(len(card)):
        for col in range(len(card[row])):
            if card[row][col] == "#":
                move_to = update_move_to(move_to, card, row, col, conditionals)
    # print(move_to)
    # print_card(card)
    if len(move_to) == 0:
        print(rounds)
        exit()
    for key, values in move_to.items():
        if len(values) == 1:
            from_row, from_col = values.pop()
            card[from_row][from_col] = "."
            to_row, to_col = key
            card[to_row][to_col] = "#"
    conditionals = conditionals[1:] + [conditionals[0]]