158 lines
3.6 KiB
Python
Executable File
158 lines
3.6 KiB
Python
Executable File
#! /usr/bin/env python3
|
|
from typing import List
|
|
from typing import Iterable
|
|
from typing import Dict
|
|
from typing import Tuple
|
|
|
|
|
|
def listify(cups: Dict[int, int]) -> Iterable[int]:
|
|
yield 1
|
|
next_cup = cups[1]
|
|
while next_cup != 1:
|
|
yield next_cup
|
|
next_cup = cups[next_cup]
|
|
|
|
|
|
def cups_str(cups: Dict[int, int], current: int) -> str:
|
|
return " ".join(
|
|
("(" if c == current else "") + str(c) + (")" if c == current else "")
|
|
for c in listify(cups)
|
|
)
|
|
|
|
|
|
def get_result(cups: Dict[int, int]) -> str:
|
|
# Rotate 1 to the front
|
|
cup1 = cups[1]
|
|
cup2 = cups[cup1]
|
|
print(f"cup1: {cup1} cup2: {cup2}")
|
|
return str(cup1 * cup2)
|
|
|
|
|
|
def str_to_cups(opening: str, max_cups: int = 0) -> Dict[int, int]:
|
|
cups_list = [int(c) for c in opening]
|
|
max_cup = max(cups_list)
|
|
|
|
if max_cups:
|
|
cup_limit = max_cups
|
|
cups_list += [c for c in range(max_cup+1, cup_limit+1)]
|
|
|
|
cups = dict(zip(cups_list, cups_list[1:]+cups_list[0:1]))
|
|
|
|
return cups
|
|
|
|
|
|
def play_round(
|
|
cups: Dict[int, int],
|
|
current: int,
|
|
max_cup: int,
|
|
debug: bool = False,
|
|
) -> Tuple[Dict[int, int], int]:
|
|
if debug:
|
|
print(f"cups: {cups_str(cups, current)}")
|
|
|
|
# Pick up cups
|
|
first_cup = cups[current]
|
|
second_cup = cups[first_cup]
|
|
third_cup = cups[second_cup]
|
|
following_cup = cups[third_cup]
|
|
|
|
# Seal
|
|
cups[current] = following_cup
|
|
|
|
if debug:
|
|
print(f"pick up: {first_cup}, {second_cup}, {third_cup}")
|
|
|
|
# Find destination
|
|
dest = current - 1
|
|
if dest < 1:
|
|
dest = max_cup
|
|
|
|
while dest in (first_cup, second_cup, third_cup):
|
|
dest -= 1
|
|
if dest < 1:
|
|
dest = max_cup
|
|
|
|
if debug:
|
|
print(f"destination: {dest}")
|
|
|
|
# Add cups back
|
|
following_cup = cups[dest]
|
|
cups[dest] = first_cup
|
|
cups[third_cup] = following_cup
|
|
|
|
# Get the new current to the right of old
|
|
current = cups[current]
|
|
|
|
return cups, current
|
|
|
|
|
|
def play_game(
|
|
cups: Dict[int, int],
|
|
start: int,
|
|
max_cup: int,
|
|
rounds: int,
|
|
debug: bool = False,
|
|
) -> Dict[int, int]:
|
|
current = start
|
|
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, max_cup, 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")
|
|
# start = 3
|
|
# max_cups = 9
|
|
# cups = play_game(cups, start, max_cups, 100, debug=True)
|
|
# print(f"result {get_result(cups)}")
|
|
|
|
start = 3
|
|
rounds = 10000000
|
|
max_cups = 1000000
|
|
cups = str_to_cups("389125467", max_cups=max_cups)
|
|
cups = play_game(cups, start, max_cups, rounds, debug=False)
|
|
print(f"result {get_result(cups)}")
|
|
|
|
|
|
def part1():
|
|
cups = str_to_cups("853192647")
|
|
cups = play_game(cups, 100, debug=False)
|
|
print(f"result {get_result(cups)}")
|
|
|
|
|
|
def part2():
|
|
start = 8
|
|
rounds = 10000000
|
|
max_cups = 1000000
|
|
cups = str_to_cups("853192647", max_cups=max_cups)
|
|
cups = play_game(cups, start, max_cups, rounds, debug=False)
|
|
print(f"result {get_result(cups)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# sample()
|
|
# part1()
|
|
part2()
|