aoc-2020/d23/main.py

172 lines
4.1 KiB
Python
Executable File

#! /usr/bin/env python3
from typing import List
from typing import Tuple
def cups_str(cups: List[int], current: int) -> str:
return " ".join(
("(" if c == current else "") + str(c) + (")" if c == current else "")
for c in cups
)
def get_result(cups: List[int], part2: bool = False) -> str:
# Rotate 1 to the front
index_1 = cups.index(1)
if not part2:
result = cups[index_1:] + cups[:index_1]
# Remove 1 from the front
result = result[1:]
return "".join((str(c) for c in result))
else:
cup1 = cups[index_1+1 % len(cups)]
cup2 = cups[index_1+2 % len(cups)]
print(f"cup1: {cup1} cup2: {cup2}")
return str(cup1 * cup2)
def str_to_cups(opening: str, part2: bool = False) -> List[int]:
cups = [int(c) for c in opening]
if part2:
max_cup = max(cups)
cup_limit = 1000000
cups += [c for c in range(max_cup+1, cup_limit+1)]
return cups
def play_round(
cups: List[int],
current: int,
debug: bool = True,
) -> Tuple[List[int], int]:
if debug:
print(f"cups: {cups_str(cups, current)}")
cur_i = cups.index(current)
# Pick up cups
picked_up: List[int] = []
while len(picked_up) < 3:
if cur_i+1 < len(cups):
picked_up.append(cups.pop(cur_i+1))
else:
picked_up.append(cups.pop(0))
cur_i -= 1
if debug:
print(f"pick up: {', '.join((str(c) for c in picked_up))}")
# Find destination
dest = 0
max_cup = 0
for c in cups:
if c < current and c > dest:
dest = c
if dest == current-1:
break
if c > max_cup:
max_cup = c
if dest <= 0:
dest = max_cup
dest_i = cups.index(dest)
# Other guy
# dest = max((c for c in cups if c < current), default=max(cups))
# dest_i = cups.index(dest)
# My attempt 1
# dest = current - 1
# dest_i = None
# while dest_i is None:
# if dest <= 0:
# # Wrap around to the highest value instead
# dest = max(cups)
# try:
# dest_i = cups.index(dest)
# except ValueError:
# # Try the next cup down
# dest -= 1
if debug:
print(f"destination: {dest}")
# Add cups back
# cups[dest_i+1:dest_i+1] = picked_up
if dest_i+1 >= len(cups):
cups += picked_up
else:
for cup in reversed(picked_up):
cups.insert(dest_i+1, cup)
# If inserted before the current, move that index up
if dest_i < cur_i:
cur_i += 3
# Get the new current to the right of old
cur_i += 1
cur_i = cur_i % len(cups)
current = cups[cur_i]
return cups, current
def play_game(cups: List[int], rounds: int, debug: bool = True) -> List[int]:
current = cups[0]
if debug:
print(f"game: {cups_str(cups, current)} {rounds} rounds")
ten_percent = int(rounds / 10)
for move in range(rounds):
if move % ten_percent == 0:
print(f"{move/ten_percent*10}%")
if debug:
print(f"-- move {move+1} --")
cups, current = play_round(cups, current, debug=debug)
if debug:
print("")
if debug:
print("-- final --")
print(f"cups: {cups_str(cups, current)}")
print(f"result {get_result(cups)}")
return cups
def sample():
# cups = str_to_cups("389125467")
# cups = play_game(cups, 10, debug=False)
# print(f"result {get_result(cups)}")
#
cups = str_to_cups("389125467")
cups = play_game(cups, 100, debug=False)
print(f"result {get_result(cups)}")
# cups = str_to_cups("389125467", part2=True)
# cups = play_game(cups, 10000000, debug=False)
# print(f"result {get_result(cups, part2=True)}")
def part1():
cups = str_to_cups("853192647")
cups = play_game(cups, 100, debug=False)
print(f"result {get_result(cups)}")
def part2():
cups = str_to_cups("853192647", part2=True)
cups = play_game(cups, 10000000, debug=False)
print(f"result {get_result(cups, part2=True)}")
if __name__ == "__main__":
# sample()
# part1()
part2()