Skip to content

Commit 0c4248e

Browse files
committed
Solve EverybodyCodes Story 1 Quest 1
1 parent abbab17 commit 0c4248e

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
"""Everyone Codes Day N."""
2+
3+
import re
4+
5+
6+
def eni(n: int, exp: int, mod: int, part: int) -> int:
7+
"""Return an ENI result."""
8+
if part != 3:
9+
remainders = []
10+
if part == 1:
11+
# Part 1: brute force each remainder.
12+
score = 1
13+
steps = exp
14+
else:
15+
# Part 2: higher values; skip to the end using pow() and compute 5 remainders.
16+
score = pow(n, exp - 5, mod)
17+
steps = 5
18+
19+
for step in range(steps):
20+
score = score * n % mod
21+
remainders.append(score)
22+
return int("".join(str(i) for i in reversed(remainders)))
23+
24+
# Part 3: solve for each remainder with cycle finding.
25+
seen = set()
26+
scores = []
27+
score = 1
28+
for step in range(exp):
29+
score = score * n % mod
30+
31+
# Stop on cycle detection.
32+
if score in seen:
33+
break
34+
35+
scores.append(score)
36+
seen.add(score)
37+
38+
# Find how many steps since the score was last seen, ie cycle length.
39+
prior_step = scores.index(score)
40+
stride = step - prior_step
41+
# How many times does the cycle repeat and how many steps after the last cycle?
42+
div, rmod = divmod(exp - step, stride)
43+
modsum = lambda x: sum(i % mod for i in x)
44+
# Score: (steps prior to cycling) + (cycle scores repeated div times) + (steps after the last cycle).
45+
return modsum(scores) + div * modsum(scores[prior_step:]) + modsum(scores[prior_step:prior_step + rmod])
46+
47+
48+
def verify_eni(a: int, b: int, c: int, x: int, y: int, z: int, m: int, part: int) -> int:
49+
"""Return the sum of three ENIs."""
50+
return eni(a, x, m, part) + eni(b, y, m, part) + eni(c, z, m, part)
51+
52+
53+
def solve(part: int, data: str) -> int:
54+
"""Solve the line which yields the highest ENI sum."""
55+
return max(
56+
verify_eni(*[int(i) for i in re.findall(r"[0-9]+", line)], part=part)
57+
for line in data.splitlines()
58+
)
59+
60+
61+
TEST_DATA = [
62+
"""\
63+
A=4 B=4 C=6 X=3 Y=4 Z=5 M=11
64+
A=8 B=4 C=7 X=8 Y=4 Z=6 M=12
65+
A=2 B=8 C=6 X=2 Y=4 Z=5 M=13
66+
A=5 B=9 C=6 X=8 Y=6 Z=8 M=14
67+
A=5 B=9 C=7 X=6 Y=6 Z=8 M=15
68+
A=8 B=8 C=8 X=6 Y=9 Z=6 M=16""",
69+
"""\
70+
A=4 B=4 C=6 X=3 Y=14 Z=15 M=11
71+
A=8 B=4 C=7 X=8 Y=14 Z=16 M=12
72+
A=2 B=8 C=6 X=2 Y=14 Z=15 M=13
73+
A=5 B=9 C=6 X=8 Y=16 Z=18 M=14
74+
A=5 B=9 C=7 X=6 Y=16 Z=18 M=15
75+
A=8 B=8 C=8 X=6 Y=19 Z=16 M=16""",
76+
"""\
77+
A=3657 B=3583 C=9716 X=903056852 Y=9283895500 Z=85920867478 M=188
78+
A=6061 B=4425 C=5082 X=731145782 Y=1550090416 Z=87586428967 M=107
79+
A=7818 B=5395 C=9975 X=122388873 Y=4093041057 Z=58606045432 M=102
80+
A=7681 B=9603 C=5681 X=716116871 Y=6421884967 Z=66298999264 M=196
81+
A=7334 B=9016 C=8524 X=297284338 Y=1565962337 Z=86750102612 M=145""",
82+
"""\
83+
A=4 B=4 C=6 X=3000 Y=14000 Z=15000 M=110
84+
A=8 B=4 C=7 X=8000 Y=14000 Z=16000 M=120
85+
A=2 B=8 C=6 X=2000 Y=14000 Z=15000 M=130
86+
A=5 B=9 C=6 X=8000 Y=16000 Z=18000 M=140
87+
A=5 B=9 C=7 X=6000 Y=16000 Z=18000 M=150
88+
A=8 B=8 C=8 X=6000 Y=19000 Z=16000 M=160""",
89+
"""\
90+
A=3657 B=3583 C=9716 X=903056852 Y=9283895500 Z=85920867478 M=188
91+
A=6061 B=4425 C=5082 X=731145782 Y=1550090416 Z=87586428967 M=107
92+
A=7818 B=5395 C=9975 X=122388873 Y=4093041057 Z=58606045432 M=102
93+
A=7681 B=9603 C=5681 X=716116871 Y=6421884967 Z=66298999264 M=196
94+
A=7334 B=9016 C=8524 X=297284338 Y=1565962337 Z=86750102612 M=145""",
95+
]
96+
TESTS = [
97+
(1, TEST_DATA[0], 11611972920),
98+
(2, TEST_DATA[1], 11051340),
99+
(2, TEST_DATA[2], 1507702060886),
100+
(3, TEST_DATA[3], 3279640),
101+
(3, TEST_DATA[4], 7276515438396),
102+
]

0 commit comments

Comments
 (0)