day 21 part2, 1st version. Need improvement in queue management (!)

This commit is contained in:
2022-01-24 15:49:02 +01:00
parent 76bd022049
commit 58027905b8
2 changed files with 151 additions and 9 deletions

View File

@@ -36,3 +36,22 @@ This is how the game would go:
Since player 1 has at least 1000 points, player 1 wins and the game ends. At this point, the losing player had 745 points and the die had been rolled a total of 993 times; 745 * 993 = 739785. Since player 1 has at least 1000 points, player 1 wins and the game ends. At this point, the losing player had 745 points and the die had been rolled a total of 993 times; 745 * 993 = 739785.
Play a practice game using the deterministic 100-sided die. The moment either player wins, what do you get if you multiply the score of the losing player by the number of times the die was rolled during the game? Play a practice game using the deterministic 100-sided die. The moment either player wins, what do you get if you multiply the score of the losing player by the number of times the die was rolled during the game?
Your puzzle answer was 989352.
--- Part Two ---
Now that you're warmed up, it's time to play the real game.
A second compartment opens, this time labeled Dirac dice. Out of it falls a single three-sided die.
As you experiment with the die, you feel a little strange. An informational brochure in the compartment explains that this is a quantum die: when you roll it, the universe splits into multiple copies, one copy for each possible outcome of the die. In this case, rolling the die always splits the universe into three copies: one where the outcome of the roll was 1, one where it was 2, and one where it was 3.
The game is played the same as before, although to prevent things from getting too far out of hand, the game now ends when either player's score reaches at least 21.
Using the same starting positions as in the example above, player 1 wins in 444356092776315 universes, while player 2 merely wins in 341960390180808 universes.
Using your given starting positions, determine every possible outcome. Find the player that wins in more universes; in how many universes does that player win?
Your puzzle answer was 430229563871565.
Both parts of this puzzle are complete! They provide two gold stars: **

View File

@@ -20,13 +20,53 @@
#include "bits.h" #include "bits.h"
#include "list.h" #include "list.h"
/* Possible rolls in part 2:
* 1,1,1=3 2,1,1=4 3,1,1=5
* 1,1,2=4 2,1,2=5 3,1,2=6
* 1,1,3=5 2,1,3=6 3,1,3=7
*
* 1,2,1=4 2,2,1=5 3,2,1=6
* 1,2,2=5 2,2,2=6 3,2,2=7
* 1,2,3=6 2,2,3=7 3,2,3=8
*
* 1,3,1=5 2,3,1=6 3,3,1=7
* 1,3,2=6 2,3,2=7 3,3,2=8
* 1,3,3=7 2,3,3=8 3,3,3=9
*/
typedef struct {
u16 roll;
u16 count;
} multi_t;
multi_t multi[] = {
{ 3, 1 },
{ 4, 3 },
{ 5, 6 },
{ 6, 7 },
{ 7, 6 },
{ 8, 3 },
{ 9, 1 },
};
#define NUNIVERSE (sizeof multi / sizeof(*multi))
static pool_t *pool_queue;
typedef struct { typedef struct {
int score; int score;
int pos; int pos;
} player_t; } player_t;
static player_t players[2]; static ulong count1, count2;
typedef struct {
player_t players[2];
u64 count;
struct list_head list_queue;
} queue_t;
static LIST_HEAD(list_queue);
static player_t players[2];
static int nrolls = 0; static int nrolls = 0;
static inline int do_roll() static inline int do_roll()
@@ -59,7 +99,34 @@ static int player_turn(int player)
return players[player].score; return players[player].score;
} }
static int part1() static void enqueue(queue_t *new)
{
log_f(2, "count=%lu score1=%d pos1=%d score2=%d pos2=%d\n",
new->count,
new->players[0].score, new->players[0].pos,
new->players[1].score, new->players[1].pos);
list_add_tail(&new->list_queue, &list_queue);
}
static queue_t *dequeue()
{
queue_t *ret = NULL;
if (!list_empty(&list_queue)) {
struct list_head *ptr;
ptr = list_queue.next;
list_del(ptr);
ret = list_entry(ptr, queue_t, list_queue);
log_f(2, "count=%lu score1=%d pos1=%d score2=%d pos2=%d\n",
ret->count,
ret->players[0].score, ret->players[0].pos,
ret->players[1].score, ret->players[1].pos);
}
return ret;
}
static u64 part1()
{ {
while (1) { while (1) {
if (player_turn(0) >= 1000) if (player_turn(0) >= 1000)
@@ -67,13 +134,71 @@ static int part1()
if (player_turn(1) >= 1000) if (player_turn(1) >= 1000)
return players[0].score * nrolls; return players[0].score * nrolls;
} }
return 1; /* not reached */
return 1;
} }
static int part2() static u64 part2()
{ {
return 1; queue_t *queue, *new;
pool_queue = pool_create("queue", 1024, sizeof(queue_t));
/* first queue seed */
queue = pool_get(pool_queue);
queue->players[0].score = 0;
queue->players[0].pos = players[0].pos;
queue->players[1].score = 0;
queue->players[1].pos = players[1].pos;
queue->count = 1;
enqueue(queue);
while ((queue = dequeue())) {
//log_i(1, "C1=%lu\n", queue->count);
for (uint i = 0; i < NUNIVERSE; ++i) {
log_i(2, "%d/%lu: roll1=%d count1=%d\n", i, NUNIVERSE,
multi[i].roll, multi[i].count);
/* calculate new position */
int pos1 = (queue->players[0].pos + multi[i].roll) % 10;
if (!pos1)
pos1 = 10;
int score1 = queue->players[0].score + pos1;
log_i(2, "pos1=%d score1=%d\n", pos1, score1);
if (score1 >= 21) {
count1 += queue->count * multi[i].count;
log_i(2, "count1=%lu\n", count1);
} else {
for (uint j = 0; j < NUNIVERSE; ++j) {
log_i(3, "%d/%lu: roll2=%d count2=%d\n", j, NUNIVERSE,
multi[j].roll, multi[j].count);
int pos2 = (queue->players[1].pos + multi[j].roll) % 10;
if (!pos2)
pos2 = 10;
int score2 = queue->players[1].score + pos2;
log_i(3, "pos2=%d score2=%d\n", pos2, score2);
if (score2 >= 21) {
count2 += queue->count * multi[i].count *
multi[j].count;
log_i(3, "count2=%lu\n", count2);
} else { /* game continues */
new = pool_get(pool_queue);
//log_i(1, "C111=%lu\n", queue->count);
*new = *queue;
new->players[0].pos = pos1;
new->players[0].score = score1;
new->players[1].pos = pos2;
new->players[1].score = score2;
new->count = queue->count * multi[i].count *
multi[j].count;
log_i(3, "C1=%lu C2=%lu\n", queue->count, new->count);
enqueue(new);
}
}
}
}
}
return count1 > count2? count1: count2;
} }
static int usage(char *prg) static int usage(char *prg)
@@ -110,9 +235,7 @@ int main(int ac, char **av)
return usage(*av); return usage(*av);
read_input(); read_input();
printf("player1: %d\n", players[0].pos); printf("%s : res=%ld\n", *av, part == 1? part1(): part2());
printf("player1: %d\n", players[1].pos);
printf("%s : res=%d\n", *av, part == 1? part1(): part2());
exit(0); exit(0);
} }