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