aoc2016/day21.py
2025-01-12 09:47:12 +01:00

102 lines
3.0 KiB
Python

from enum import Enum
from tools.aoc import AOCDay
from tools.types import String
from typing import Any
class OP(int, Enum):
SWAP = 0
ROTATE = 1
REVERSE = 2
MOVE = 3
def scramble(password: String, ops: list[tuple[OP, Any, ...]], reverse: bool = False) -> str:
if reverse:
ops = list(reversed(ops))
def get_rotate_num(c: str) -> int:
return 1 + password.index(c) + (password.index(c) >= 4)
for op in ops:
if op[0] == OP.SWAP:
x, y = op[1], op[2]
if not isinstance(x, int) or not isinstance(y, int):
x, y = password.index(x), password.index(y)
password = password.swap(x, y)
elif op[0] == OP.ROTATE:
rot = op[1]
if isinstance(rot, int):
if reverse:
rot *= -1
password = password.rotate(rot)
else:
if not reverse:
rot = get_rotate_num(rot)
password = password.rotate(rot)
else:
rot_count = 0
while rot_count != get_rotate_num(rot):
rot_count += 1
password = password.rotate(-1)
elif op[0] == OP.REVERSE:
x, y = op[1], op[2]
password = password.reverse(x, y)
elif op[0] == OP.MOVE:
x, y = op[1], op[2]
if reverse:
x, y = y, x
to_move = password[x]
password = String(password[:x] + password[x + 1 :])
password = String(password[:y] + to_move + password[y:])
return password
class Day(AOCDay):
inputs = [
[
("decab", "input21_test"),
("gfdhebac", "input21"),
],
[
("dhaegfbc", "input21"),
],
]
def parse_input(self) -> list[tuple[OP, Any, ...]]:
instr = []
for line in self.getInput():
parts = line.split()
if parts[0] == "swap":
if parts[1] == "position":
instr.append((OP.SWAP, int(parts[2]), int(parts[5])))
else:
instr.append((OP.SWAP, parts[2], parts[5]))
elif parts[0] == "rotate":
if parts[1] == "based":
instr.append((OP.ROTATE, parts[6]))
else:
instr.append((OP.ROTATE, int(parts[2]) * (-1 if parts[1] == "left" else 1)))
elif parts[0] == "reverse":
instr.append((OP.REVERSE, int(parts[2]), int(parts[4])))
else:
instr.append((OP.MOVE, int(parts[2]), int(parts[5])))
return instr
def part1(self) -> Any:
to_scramble = String("abcde") if self.is_test() else String("abcdefgh")
return scramble(to_scramble, self.parse_input())
def part2(self) -> Any:
to_unscramble = String("fbgdceah")
return scramble(to_unscramble, self.parse_input(), reverse=True)
if __name__ == "__main__":
day = Day(2016, 21)
day.run(verbose=True)