Python
A much simpler problem compared to earlier ones
# generator to yield dial values in the required order
# yields (value: str, is_reverse: bool)
def yield_dial_vals(coll: list):
n = len(coll)
for i in range(0, n, 2):
yield coll[i], False
right_start = n - 2 if n % 2 == 1 else n - 1
for i in range(right_start, -1, -2):
yield coll[i], True
def part1(data: str):
nums = data.splitlines()
n = len(nums)
# total number of values on the dial
# + 1 for the '1' value
total_vals = n + 1
# effective rotation after full cycles
effective_rot = 2025 % total_vals
# if full cycles, return '1'
if effective_rot == 0:
return 1
# adjust for 0-indexing the remaining dial values
effective_rot -= 1
# skip numbers on the dial until we reach the final value
val_gen = yield_dial_vals(nums)
for _ in range(effective_rot):
next(val_gen)
# return the final value
return int(next(val_gen)[0])
assert (t := part1("""72
58
47
61
67""")) == 67, f"Expected: 67, Actual: {t}"
def part2(data: str, rotations = 20252025):
ranges = data.splitlines()
# count values on the dial other than '1'
n = 0
for val, _ in yield_dial_vals(ranges):
a, b = map(int, val.split("-"))
n += b - a + 1
# total number of values on the dial
# + 1 for the '1' value
total_vals = n + 1
# effective rotation after full cycles
effective_rot = rotations % total_vals
# if full cycles, return '1'
if effective_rot == 0:
return 1
# adjust for 0-indexing the remaining dial values
effective_rot -= 1
# iterate through ranges until we reach the one the dial lands on
for val, is_reverse in yield_dial_vals(ranges):
# get range bound and size
a, b = map(int, val.split("-"))
r = b - a + 1
# check if the dial lands within this range
if effective_rot < r:
# it does!
# return the appropriate value in the range based on direction
if is_reverse:
return b - effective_rot
else:
return a + effective_rot
# consume the rotations for skipping this range
effective_rot -= r
assert False, "Should have found the target range"
assert part2("""10-15
12-13
20-21
19-23
30-37""") == 30
# part 3 is just part 2 with a larger number of rotations
from functools import partial
part3 = partial(part2, rotations = 202520252025)