advent2021

Advent of Code 2021 Solutions
git clone git://bsandro.tech/advent2021
Log | Files | Refs

commit 362de4cf2cc8d77ca48705ec134e9c724a1ce81b
parent cdaa9ee3e67d079c3806497cfbb6fe68739a794b
Author: bsandro <[email protected]>
Date:   Wed, 22 Dec 2021 21:39:46 +0200

Day 22, puzzle 2

Diffstat:
Mday21/Makefile | 6++++--
Mday21/puzzle.c | 138++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 124 insertions(+), 20 deletions(-)

diff --git a/day21/Makefile b/day21/Makefile @@ -2,8 +2,10 @@ NAME=$(shell basename ${PWD}) SRC=$(wildcard *.c ../common/*.c) DEPS:=$(wildcard *.h ../common/*.h) OBJ:=$(SRC:.c=.o) -CFLAGS=-O0 -g -fsanitize=address -fno-omit-frame-pointer -std=c99 -Werror -Wall -Wextra -I. -I../common -LDFLAGS=-g -lc -lm -fsanitize=address +#CFLAGS=-O0 -g -fsanitize=address -fno-omit-frame-pointer -std=c99 -Werror -Wall -Wextra -I. -I../common +#LDFLAGS=-g -lc -lm -fsanitize=address +CFLAGS=-O2 -std=c99 -Werror -Wall -Wextra -I. -I../common +LDFLAGS=-lc -lm all: $(NAME) diff --git a/day21/puzzle.c b/day21/puzzle.c @@ -14,6 +14,24 @@ #define STR_LEN 1024 +struct cache_t { + long p1, p2, p1s, p2s; + long long p1w; + long long p2w; + bool p1t; +}; + +struct result_t { + long long p1w; + long long p2w; +}; + +long long calc_result1(long p1, long p2); +long long calc_result2(long p1, long p2); +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); +struct cache_t * get_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s); +void set_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s, long long p1w, long long p2w); + void puzzle(const char *filename, long long *result1, long long *result2) { FILE *infile = fopen(filename, "r"); if (infile == NULL) { @@ -41,14 +59,20 @@ void puzzle(const char *filename, long long *result1, long long *result2) { assert(p1 != 0 && p2 != 0); - *result2 = 0; + *result1 = calc_result1(p1, p2); + *result2 = calc_result2(p1, p2); + + // mutiny! ignoring feof/ferror. + fclose(infile); +} + +long long calc_result1(long p1, long p2) { long p1s = 0; // player 1 score long p2s = 0; // player 2 score long d = 1; // dice value long rc = 0; // real rolls count while (1) { - //printf("rc=%3ld, d=%3ld, ", rc, d); if (d == 1) { p1 += 6; d += 3; @@ -58,10 +82,10 @@ void puzzle(const char *filename, long long *result1, long long *result2) { d = 1; } else if (d == 99) { p1 += 200; - d = 2; //(d + 3) % 100; + d = 2; } else if (d == 100) { p1 += 103; - d = 3; //(d + 3) % 100; + d = 3; } else { d = (d + 3) % 100; p1 += d * 3 + 3; @@ -70,17 +94,13 @@ void puzzle(const char *filename, long long *result1, long long *result2) { p1 += d * 3 + 3; d += 3; } - //printf("p1=%3ld, ", p1); p1 = p1 > 10 ? (p1 % 10) : p1; p1 = p1 == 0 ? 10 : p1; - //printf("p1(pos)=%3ld, ", p1); p1s += p1; - //printf("p1s=%3ld\n", p1s); rc += 3; if (p1s >= 1000) break; - //printf("rc=%3ld, d=%3ld, ", rc, d); if (d == 1) { p2 += 6; d += 3; @@ -90,10 +110,10 @@ void puzzle(const char *filename, long long *result1, long long *result2) { d = 1; } else if (d == 99) { p2 += 200; - d = 2; //(d + 3) % 100; + d = 2; } else if (d == 100) { p2 += 103; - d = 3; //(d + 3) % 100; + d = 3; } else { d = (d + 3) % 100; p2 += d * 3 + 3; @@ -102,23 +122,105 @@ void puzzle(const char *filename, long long *result1, long long *result2) { p2 += d * 3 + 3; d += 3; } - //printf("p2=%3ld, ", p2); p2 = p2 > 10 ? (p2 % 10) : p2; p2 = p2 == 0 ? 10 : p2; - //printf("p2(pos)=%3ld, ", p2); p2s += p2; - //printf("p2s=%3ld\n\n", p2s); rc += 3; if (p2s >= 1000) break; } - //printf("\n\n\np1=%3ld, p1s=%3ld, p2=%3ld, p2s=%3ld, rc=%3ld\n", p1, p1s, p2, p2s, rc); + return fmin(p1s, p2s) * rc; +} - long min_score = fmin(p1s, p2s); +long long calc_result2(long p1, long p2) { + struct array_t cache = { .data = NULL }; + array_init(&cache, sizeof(struct cache_t), 1000); + struct result_t result = roll_turn(&cache, true, p1, p2, 0, 0, 0, 0); + return fmaxl(result.p1w, result.p2w); +} - *result1 = min_score * rc; +struct cache_t * get_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s) { + struct cache_t *cache_data = cache->data; + for (size_t i = 0; i < cache->count; ++i) { + struct cache_t *c = &cache_data[i]; + if (c->p1t == p1t && c->p1 == p1 && c->p2 == p2 && c->p1s == p1s && c->p2s == p2s) { + return c; + } + } + return NULL; +} - // mutiny! ignoring feof/ferror. - fclose(infile); +void set_cache(struct array_t *cache, bool p1t, long p1, long p2, long p1s, long p2s, long long p1w, long long p2w) { + if (cache->count >= cache->cap) array_expand(cache); + struct cache_t *cache_data = cache->data; + + struct cache_t *c = get_cache(cache, p1t, p1, p2, p1s, p2s); + assert(c == NULL); + c = &cache_data[cache->count++]; + c->p1t = p1t; + c->p1 = p1; + c->p2 = p2; + c->p1s = p1s; + c->p2s = p2s; + c->p1w = p1w; + c->p2w = p2w; +} + + +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) { + + struct result_t result = {0}; + if (pp1s >= 21) { + result.p1w = 1; + return result; + } + if (pp2s >= 21) { + result.p2w = 1; + return result; + } + + struct cache_t *c = get_cache(cache, pp1t, pp1, pp2, pp1s, pp2s); + if (c != NULL) { + result.p1w = c->p1w; + result.p2w = c->p2w; + return result; + } + + for (int d1 = 1; d1 <= 3; ++d1) { + for (int d2 = 1; d2 <= 3; ++d2) { + for (int d3 = 1; d3 <= 3; ++d3) { + + long dice = d1+d2+d3; + long p1 = pp1; + long p2 = pp2; + long p1s = pp1s; + long p2s = pp2s; + bool p1t = pp1t; + + if (p1t) { + // player 1 turn + p1t = false; + p1 += dice; + p1 = p1 > 10 ? (p1 % 10) : p1; + p1 = (p1 == 0) ? 10 : p1; + p1s += p1; + + } else { + // player 2 turn + p1t = true; + p2 += dice; + p2 = p2 > 10 ? (p2 % 10) : p2; + p2 = p2 == 0 ? 10 : p2; + p2s += p2; + + } + struct result_t res = roll_turn(cache, p1t, p1, p2, p1s, p2s, p1w, p2w); + result.p1w += res.p1w; + result.p2w += res.p2w; + } + } + } + set_cache(cache, pp1t, pp1, pp2, pp1s, pp2s, result.p1w, result.p2w); + return result; }