advent-of-code/2024/21/two.py
2024-12-25 12:59:49 +01:00

282 lines
6.5 KiB
Python

#!/usr/bin/env python3
import sys
import typing
import functools
input_file = sys.argv[1]
with open(input_file) as fd:
lines = [line.rstrip() for line in fd.readlines()]
numeric_keypad = ["789", "456", "123", " 0A"]
directional_keypad = [" ^A", "<v>"]
vec = tuple[int, int]
directions = {
"^": (-1, 0), # ^ North
">": (0, 1), # > East
"v": (1, 0), # v South
"<": (0, -1), # < West
}
directional_keypad_buttons = tuple(directions.keys()) + ("A",)
complexity = int(sys.argv[2])
keypads = [numeric_keypad] + ([directional_keypad] * complexity)
def but_pos(but: str, keypad: list[str]) -> vec:
for i, line in enumerate(keypad):
if but in line:
return i, line.index(but)
raise IndexError(f"No such button: {but} in {keypad}")
def in_bounds(i: int, j: int, keypad: list[str]) -> bool:
if j not in range(3) or i not in range(len(keypad)):
return False
return keypad[i][j] != " "
# FIFTH TRY
# Using 2 as a base
@functools.cache
def press(buts: str, depth: int) -> int:
if depth == len(keypads):
return len(buts)
keypad = keypads[depth]
i, j = but_pos("A", keypad)
nums = 0
for but in buts:
nnbuts = ""
ni, nj = but_pos(but, keypad)
bounded = True
while nj < j:
nnbuts += "<"
j -= 1
bounded &= in_bounds(i, j, keypad)
while ni > i:
nnbuts += "v"
i += 1
bounded &= in_bounds(i, j, keypad)
while ni < i:
nnbuts += "^"
i -= 1
bounded &= in_bounds(i, j, keypad)
while nj > j:
nnbuts += ">"
j += 1
bounded &= in_bounds(i, j, keypad)
if not bounded:
nnbuts = nnbuts[::-1]
nnbuts += "A"
nums += press(nnbuts, depth + 1)
return nums
score = 0
for code in lines:
print("Code", code)
topresses = press(code, 0)
numpart = int("0" + code.replace("A", ""))
print(f"{topresses=} * {numpart=}")
score += topresses * numpart
print(score)
# FOURTH TRY
# def press4(buts: str) -> int:
# poss = [list(but_pos("A")) for keypad in keypads]
# indexes = [0 for _ in keypads]
# combis = ["" for _ in keypads]
# combis[0] = buts
# while indexes[0] != len(buts):
# for k in len(keypads):
# pass
# return 0
#
#
# score = 0
# for code in lines:
# print("Code", code)
#
# topresses = press4(code)
#
# numpart = int("0" + code.replace("A", ""))
# print(f"{topresses=} * {numpart=}")
# score += topresses * numpart
#
# print(score)
sys.exit(0)
# THIRD TRY
def press3(buts: str, depth: int) -> typing.Generator[str, None, None]:
if depth >= len(keypads):
yield from buts
return
keypad = keypads[::-1][depth]
but_poss: dict[str, vec] = dict()
for i, line in enumerate(keypad):
for j, but in enumerate(line):
but_poss[but] = i, j
i, j = but_poss["A"]
ai, ij = but_poss[" "]
for but in press3(buts, depth + 1):
nnbuts = ""
ni, nj = but_poss[but]
bounded = True
if nj < j:
nnbuts += "<" * (j - nj)
j = nj
bounded &= (ai, ij) != (i, j)
if ni > i:
nnbuts += "v" * (ni - i)
i = ni
bounded &= (ai, ij) != (i, j)
if ni < i:
nnbuts += "^" * (i - ni)
i = ni
bounded &= (ai, ij) != (i, j)
if nj > j:
nnbuts += ">" * (nj - j)
j = nj
if not bounded:
nnbuts = nnbuts[::-1]
nnbuts += "A"
yield from nnbuts
score = 0
for code in lines:
print("Code", code)
topresses = 0
for _ in press3(code, 0):
topresses += 1
numpart = int("0" + code.replace("A", ""))
print(f"{topresses=} * {numpart=}")
score += topresses * numpart
print(score)
# SECOND TRY
# # Shouldn't move over the bounds, repeat movements when possible, also use movements
# # that start further to A then closer to A, because we're going to press A after anyways
# moves = {
# "AA": "",
# "A^": "<",
# "A>": "v",
# "Av": "<v", # sort
# "A<": "v<<", # hole avoid
# "^A": ">",
# "^^": "",
# "^>": "v>", # sort
# "^v": "v",
# "^<": "v<", # hole avoid
# ">A": "^",
# ">^": "<^", # sort
# ">>": "",
# ">v": "<",
# "><": "<<",
# "vA": "^>", # symetric. but lower layer sort!
# "v^": "^",
# "v>": ">",
# "vv": "",
# "v<": "<",
# "<A": ">>^", # hole avoid
# "<^": ">^", # hole avoid
# "<>": ">>",
# "<v": ">",
# "<<": "",
# }
#
#
# def press(buts: str, depth: int) -> str:
# if depth == len(keypads):
# return buts
# keypad = keypads[depth]
# numerical = keypad == numeric_keypad
# prev_but = "A"
# i, j = but_pos(prev_but, keypad)
# nbuts = ""
# for but in buts:
# if numerical:
# nnbuts = ""
# ni, nj = but_pos(but, keypad)
# # right before down
# # up before left
# bounded = True
# while nj < j:
# nnbuts += "<"
# j -= 1
# bounded &= in_bounds(i, j, keypad)
# while ni > i:
# nnbuts += "v"
# i += 1
# bounded &= in_bounds(i, j, keypad)
# while ni < i:
# nnbuts += "^"
# i -= 1
# bounded &= in_bounds(i, j, keypad)
# while nj > j:
# nnbuts += ">"
# j += 1
# bounded &= in_bounds(i, j, keypad)
# if not bounded:
# nnbuts = nnbuts[::-1]
# nbuts += nnbuts
# else:
# move = prev_but + but
# nbuts += moves[move]
# nbuts += "A"
# prev_but = but
# return press(nbuts, depth + 1)
#
#
# score = 0
# for code in lines:
# print("Code", code)
# presses = press(code, 0)
# print(f"{presses=}")
# topresses = len(presses)
#
# numpart = int("0" + code.replace("A", ""))
# print(f"{topresses=} * {numpart=}")
# score += topresses * numpart
#
# print(score)
# FIRST TRY
# keys = {
# "A": "A",
# "^": "<A" + ">",
# ">": "VA" + "^",
# "V": "V<A" + ">^",
# "<": "V<<A" + ">>^",
# }
#
# def press(but: str, depth: int) -> str:
# if depth <= 0:
# return but
# depth -= 1
# return "".join(press(b, depth) for b in keys[but])
#
#
# res = press("^", complexity)
# # res += press("A", complexity)
# print(len(res), res)