puzzle.c (4804B)
1 #define _DEFAULT_SOURCE 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <errno.h> 6 #include <string.h> 7 #include <strings.h> 8 #include <assert.h> 9 #include <ctype.h> 10 #include <stdbool.h> 11 #include <math.h> 12 13 #include "util.h" 14 15 #define STR_LEN 1024 16 17 struct cache_t { 18 long p1, p2, p1s, p2s; 19 long long p1w; 20 long long p2w; 21 bool p1t; 22 }; 23 24 struct result_t { 25 long long p1w; 26 long long p2w; 27 }; 28 29 long long calc_result1(long p1, long p2); 30 long long calc_result2(long p1, long p2); 31 struct result_t roll_turn(struct array_t *cache, bool pp1t, long pp1, long pp2, long pp1s, long pp2s, long long p1w, long long p2w); 32 struct cache_t * get_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s); 33 void set_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s, long long p1w, long long p2w); 34 35 void puzzle(const char *filename, long long *result1, long long *result2) { 36 FILE *infile = fopen(filename, "r"); 37 if (infile == NULL) { 38 fprintf(stderr, "fopen() error: %s\n", strerror(errno)); 39 return; 40 } 41 42 char buf[STR_LEN] = {0}; 43 unsigned int line_num = 0; 44 45 long p1 = 0; 46 long p2 = 0; 47 48 while (fgets(buf, STR_LEN, infile) != NULL) { 49 int len = strlen(buf); 50 assert(len > 2); 51 if (line_num == 0) { // player 1 52 p1 = buf[len-2] - '0'; 53 } else if (line_num == 1) { // player 2 54 p2 = buf[len-2] - '0'; 55 } 56 ++line_num; 57 bzero(buf, STR_LEN); 58 } 59 60 assert(p1 != 0 && p2 != 0); 61 62 *result1 = calc_result1(p1, p2); 63 *result2 = calc_result2(p1, p2); 64 65 // mutiny! ignoring feof/ferror. 66 fclose(infile); 67 } 68 69 long long calc_result1(long p1, long p2) { 70 long p1s = 0; // player 1 score 71 long p2s = 0; // player 2 score 72 long d = 1; // dice value 73 long rc = 0; // real rolls count 74 75 while (1) { 76 if (d == 1) { 77 p1 += 6; 78 d += 3; 79 } else if (d >= 98) { 80 if (d == 98) { 81 p1 += 297; 82 d = 1; 83 } else if (d == 99) { 84 p1 += 200; 85 d = 2; 86 } else if (d == 100) { 87 p1 += 103; 88 d = 3; 89 } else { 90 d = (d + 3) % 100; 91 p1 += d * 3 + 3; 92 } 93 } else { 94 p1 += d * 3 + 3; 95 d += 3; 96 } 97 p1 = p1 > 10 ? (p1 % 10) : p1; 98 p1 = p1 == 0 ? 10 : p1; 99 p1s += p1; 100 rc += 3; 101 102 if (p1s >= 1000) break; 103 104 if (d == 1) { 105 p2 += 6; 106 d += 3; 107 } else if (d >= 98) { 108 if (d == 98) { 109 p2 += 297; 110 d = 1; 111 } else if (d == 99) { 112 p2 += 200; 113 d = 2; 114 } else if (d == 100) { 115 p2 += 103; 116 d = 3; 117 } else { 118 d = (d + 3) % 100; 119 p2 += d * 3 + 3; 120 } 121 } else { 122 p2 += d * 3 + 3; 123 d += 3; 124 } 125 p2 = p2 > 10 ? (p2 % 10) : p2; 126 p2 = p2 == 0 ? 10 : p2; 127 p2s += p2; 128 rc += 3; 129 130 if (p2s >= 1000) break; 131 } 132 133 return fmin(p1s, p2s) * rc; 134 } 135 136 long long calc_result2(long p1, long p2) { 137 struct array_t cache = { .data = NULL }; 138 array_init(&cache, sizeof(struct cache_t), 1000); 139 struct result_t result = roll_turn(&cache, true, p1, p2, 0, 0, 0, 0); 140 return fmaxl(result.p1w, result.p2w); 141 } 142 143 struct cache_t * get_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s) { 144 struct cache_t *cache_data = cache->data; 145 for (size_t i = 0; i < cache->count; ++i) { 146 struct cache_t *c = &cache_data[i]; 147 if (c->p1t == p1t && c->p1 == p1 && c->p2 == p2 && c->p1s == p1s && c->p2s == p2s) { 148 return c; 149 } 150 } 151 return NULL; 152 } 153 154 void set_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s, long long p1w, long long p2w) { 155 if (cache->count >= cache->cap) array_expand(cache); 156 struct cache_t *cache_data = cache->data; 157 158 struct cache_t *c = get_cache(cache, p1t, p1, p2, p1s, p2s); 159 assert(c == NULL); 160 c = &cache_data[cache->count++]; 161 c->p1t = p1t; 162 c->p1 = p1; 163 c->p2 = p2; 164 c->p1s = p1s; 165 c->p2s = p2s; 166 c->p1w = p1w; 167 c->p2w = p2w; 168 } 169 170 171 struct result_t roll_turn(struct array_t *cache, bool pp1t, long pp1, long pp2, long pp1s, long pp2s, long long p1w, long long p2w) { 172 173 struct result_t result = {0}; 174 if (pp1s >= 21) { 175 result.p1w = 1; 176 return result; 177 } 178 if (pp2s >= 21) { 179 result.p2w = 1; 180 return result; 181 } 182 183 struct cache_t *c = get_cache(cache, pp1t, pp1, pp2, pp1s, pp2s); 184 if (c != NULL) { 185 result.p1w = c->p1w; 186 result.p2w = c->p2w; 187 return result; 188 } 189 190 for (int d1 = 1; d1 <= 3; ++d1) { 191 for (int d2 = 1; d2 <= 3; ++d2) { 192 for (int d3 = 1; d3 <= 3; ++d3) { 193 194 long dice = d1+d2+d3; 195 long p1 = pp1; 196 long p2 = pp2; 197 long p1s = pp1s; 198 long p2s = pp2s; 199 bool p1t = pp1t; 200 201 if (p1t) { 202 // player 1 turn 203 p1t = false; 204 p1 += dice; 205 p1 = p1 > 10 ? (p1 % 10) : p1; 206 p1 = (p1 == 0) ? 10 : p1; 207 p1s += p1; 208 209 } else { 210 // player 2 turn 211 p1t = true; 212 p2 += dice; 213 p2 = p2 > 10 ? (p2 % 10) : p2; 214 p2 = p2 == 0 ? 10 : p2; 215 p2s += p2; 216 217 } 218 struct result_t res = roll_turn(cache, p1t, p1, p2, p1s, p2s, p1w, p2w); 219 result.p1w += res.p1w; 220 result.p2w += res.p2w; 221 } 222 } 223 } 224 set_cache(cache, pp1t, pp1, pp2, pp1s, pp2s, result.p1w, result.p2w); 225 return result; 226 }