|
| 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