#! /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()