Skip to content

Commit ad18d62

Browse files
authored
Day 21 (#26)
1 parent 2f5507b commit ad18d62

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

Day21.c

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "Helpers.c"
2+
3+
typedef struct {
4+
uint64_t p1;
5+
uint64_t p2;
6+
} Wins;
7+
8+
static void parse(const char *input, int *startP1, int *startP2) {
9+
assert(sscanf(input, "Player 1 starting position: %d\nPlayer 2 starting position: %d", startP1, startP2) == 2);
10+
}
11+
12+
static int partOne(int start1, int start2) {
13+
int pos1 = start1 - 1; // Translate from 1...10 to 0..9.
14+
int pos2 = start2 - 1;
15+
int score1 = 0;
16+
int score2 = 0;
17+
int dice = 0;
18+
int rolls = 0;
19+
20+
for (;;) {
21+
dice = dice == 100 ? 1 : dice + 1;
22+
pos1 = (pos1 + dice) % 10;
23+
24+
dice = dice == 100 ? 1 : dice + 1;
25+
pos1 = (pos1 + dice) % 10;
26+
27+
dice = dice == 100 ? 1 : dice + 1;
28+
pos1 = (pos1 + dice) % 10;
29+
30+
rolls += 3;
31+
score1 += pos1 + 1;
32+
33+
if (score1 >= 1000) {
34+
break;
35+
}
36+
37+
dice = dice == 100 ? 1 : dice + 1;
38+
pos2 = (pos2 + dice) % 10;
39+
40+
dice = dice == 100 ? 1 : dice + 1;
41+
pos2 = (pos2 + dice) % 10;
42+
43+
dice = dice == 100 ? 1 : dice + 1;
44+
pos2 = (pos2 + dice) % 10;
45+
46+
rolls += 3;
47+
score2 += pos2 + 1;
48+
49+
if (score2 >= 1000) {
50+
break;
51+
}
52+
}
53+
54+
return (score1 > score2 ? score2 : score1) * rolls;
55+
}
56+
57+
static Wins playWithDirac(const int diceSumFreq[10], uint8_t score1, uint8_t score2, bool isP1Turn, uint8_t pos1, uint8_t pos2, Wins cachedWins[31][31][2][10][10]) {
58+
Wins cached = cachedWins[score1][score2][isP1Turn][pos1][pos2];
59+
60+
if (cached.p1 > 0 || cached.p2 > 0) {
61+
return cached;
62+
} else if (score1 >= 21) {
63+
return (Wins){.p1 = 1, .p2 = 0};
64+
} else if (score2 >= 21) {
65+
return (Wins){.p1 = 00, .p2 = 1};
66+
} else {
67+
Wins totalWins = {0};
68+
69+
for (int diceSum = 3; diceSum < 10; ++diceSum) {
70+
Wins universeWins;
71+
72+
if (isP1Turn) {
73+
int newPos1 = (pos1 + diceSum) % 10;
74+
int newScore1 = score1 + newPos1 + 1;
75+
76+
universeWins = playWithDirac(diceSumFreq, newScore1, score2, false, newPos1, pos2, cachedWins);
77+
} else {
78+
int newPos2 = (pos2 + diceSum) % 10;
79+
int newScore2 = score2 + newPos2 + 1;
80+
81+
universeWins = playWithDirac(diceSumFreq, score1, newScore2, true, pos1, newPos2, cachedWins);
82+
}
83+
84+
totalWins.p1 += universeWins.p1 * diceSumFreq[diceSum];
85+
totalWins.p2 += universeWins.p2 * diceSumFreq[diceSum];
86+
}
87+
88+
// Remember this outcome so we can reuse it other universes.
89+
cachedWins[score1][score2][isP1Turn][pos1][pos2] = totalWins;
90+
91+
return totalWins;
92+
}
93+
}
94+
95+
static uint64_t partTwo(int startPos1, int startPos2) {
96+
int diracDiceSumFreq[10] = {0};
97+
98+
for (int d1 = 1; d1 <= 3; ++d1) {
99+
for (int d2 = 1; d2 <= 3; ++d2) {
100+
for (int d3 = 1; d3 <= 3; ++d3) {
101+
++diracDiceSumFreq[d1 + d2 + d3];
102+
}
103+
}
104+
}
105+
106+
Wins cachedWins[31][31][2][10][10] = {0};
107+
108+
// startPos is assumed 1..10, translate to 0..9.
109+
Wins totalWins = playWithDirac(diracDiceSumFreq, 0, 0, true, startPos1 - 1, startPos2 - 1, cachedWins);
110+
111+
return totalWins.p1 > totalWins.p2
112+
? totalWins.p1
113+
: totalWins.p2;
114+
}
115+
116+
int main() {
117+
const char *input = Helpers_readInputFile(__FILE__);
118+
119+
int start1;
120+
int start2;
121+
parse(input, &start1, &start2);
122+
123+
Helpers_assert(PART1, Helpers_clock(),
124+
partOne(start1, start2),
125+
739785, 1004670);
126+
127+
Helpers_assert(PART2, Helpers_clock(),
128+
partTwo(start1, start2),
129+
444356092776315, 492043106122795);
130+
131+
return 0;
132+
}

Day21.example.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Player 1 starting position: 4
2+
Player 2 starting position: 8

Day21.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Player 1 starting position: 9
2+
Player 2 starting position: 6

0 commit comments

Comments
 (0)