2020 day 22/2 (C) - clean code

This commit is contained in:
2022-11-29 20:53:07 +01:00
parent ea9c144127
commit ca8de49d5e
3 changed files with 57 additions and 104 deletions

View File

@@ -499,6 +499,10 @@ ex2.bash: res=32760
time: 1:21.92 real, 81.89 user, 0.01 sys time: 1:21.92 real, 81.89 user, 0.01 sys
context-switch: 462+1, page-faults: 0+5135 context-switch: 462+1, page-faults: 0+5135
aoc-c : res=32760
time: 0:01.11 real, 1.09 user, 0.01 sys
context-switch: 70+1, page-faults: 0+1933
========================================= =========================================
================= day23 ================= ================= day23 =================
========================================= =========================================

View File

@@ -65,58 +65,26 @@ static __always_inline u32 hash(u32 h)
return hash_32(h, HBITS); return hash_32(h, HBITS);
} }
static void print_cards(player_t *players)
{
struct card *card;
for (int player = 0; player < 2; ++player) {
int c = 0;
log(2, "Player %d's deck: ", player + 1);
list_for_each_entry(card, &players[player].head, list) {
if (c++)
log(2, ",");
log(2, " %d", card->card);
}
log(2, "\n");
}
}
static int equal_decks(hash_t *hasht, player_t *new) static int equal_decks(hash_t *hasht, player_t *new)
{ {
//int i = 0;
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
card_t *c1 = list_first_entry_or_null(&hasht->players[i], card_t, list); card_t *c1 = list_first_entry_or_null(&hasht->players[i], card_t, list);
card_t *c2 = list_first_entry_or_null(&new[i].head, card_t, list); card_t *c2 = list_first_entry_or_null(&new[i].head, card_t, list);
log_f(3, "p=%d c1=%p c2=%p", i + 1, c1, c2);
if (!c1 || !c2) { if (!c1 || !c2) /* one list (only) is empty */
/* one list is empty and one is not */
//if ((!c1 && c2) || (c1 && !c2)) {
log(3, "NULL\n");
return 0; return 0;
}
log_f(3, "\nplayer=%d ", i + 1);
while (!list_entry_is_head(c1, &hasht->players[i], list) && while (!list_entry_is_head(c1, &hasht->players[i], list) &&
!list_entry_is_head(c2, &new[i].head, list) && !list_entry_is_head(c2, &new[i].head, list) &&
c1->card == c2->card) { c1->card == c2->card) {
log(3, "c1=%d c2=%d ", c1->card, c2->card); if (c1->card != c2->card)
if (c1->card != c2->card) {
log(3, "\n");
return 0; return 0;
}
c1 = list_next_entry(c1, list); c1 = list_next_entry(c1, list);
c2 = list_next_entry(c2, list); c2 = list_next_entry(c2, list);
} }
log(3, "\nd1=%p c1=%p/%d\nd2=%p c2=%p/%d ",
&hasht[i], c1, list_entry_is_head(c1, &hasht->players[i], list),
&new[i], c2, list_entry_is_head(c2, &new[i].head, list));
//log(3, "\nZOBI\n");
if (!list_entry_is_head(c1, &hasht->players[i], list) || if (!list_entry_is_head(c1, &hasht->players[i], list) ||
!list_entry_is_head(c2, &new[i].head, list)) !list_entry_is_head(c2, &new[i].head, list))
return 0; return 0;
log(3, "\n");
//log(3, "\nZOBI\n");
} }
return 1; return 1;
} }
@@ -129,24 +97,12 @@ static hash_t *create_hash(player_t *players, u32 h)
hash->zobrist = h; hash->zobrist = h;
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
log_f(4, "player %d: ", i + 1);
INIT_LIST_HEAD(&hash->players[i]); INIT_LIST_HEAD(&hash->players[i]);
list_for_each_entry(card, &players[i].head, list) { list_for_each_entry(card, &players[i].head, list) {
struct card *new = pool_get(pool_cards); struct card *new = pool_get(pool_cards);
new->card = card->card; new->card = card->card;
list_add_tail(&new->list, &hash->players[i]); list_add_tail(&new->list, &hash->players[i]);
log(4, "%d ", card->card);
} }
log(4, "\n");
}
log_f(3, "hash=%p p1-next=%p p2-next=%p\n", hash,
hash->players[0].next, hash->players[1].next);
for (int i = 0; i < 2; ++i) {
log_f(4, "duped player %d: ", i + 1);
list_for_each_entry(card, &hash->players[i], list) {
log(4, "%d ", card->card);
}
log(4, "\n");
} }
return hash; return hash;
} }
@@ -167,7 +123,6 @@ static player_t *create_subgame(player_t *from, player_t *to)
struct card *new = pool_get(pool_cards); struct card *new = pool_get(pool_cards);
new->card = card->card; new->card = card->card;
list_add_tail(&new->list, &to[i].head); list_add_tail(&new->list, &to[i].head);
log(4, "%d ", card->card);
if (!--ncards) if (!--ncards)
break; break;
} }
@@ -185,16 +140,10 @@ static hash_t *find_deck(struct hlist_head *hasht, player_t *players)
hash_t *cur; hash_t *cur;
u32 z = zobrist(players); u32 z = zobrist(players);
u32 h = hash(z); u32 h = hash(z);
log_f(3, "zobrist = %u/%u ", z, h);
hlist_for_each_entry(cur, hasht + h, hlist) { hlist_for_each_entry(cur, hasht + h, hlist) {
log(3, "[%u]\n", cur->zobrist); if (cur->zobrist == z && equal_decks(cur, players))
if (cur->zobrist == z && equal_decks(cur, players)) {
// && equal_decks(&cur->players[1], &players[1].head)) {
log_f(3, "found\n");
return cur; return cur;
}
} }
log_f(3, "not found\n");
cur = create_hash(players, z); cur = create_hash(players, z);
hlist_add_head(&cur->hlist, &hasht[h]); hlist_add_head(&cur->hlist, &hasht[h]);
return NULL; return NULL;
@@ -247,78 +196,91 @@ static void winmove(player_t *winner, player_t *loser)
winner->ncards++; winner->ncards++;
} }
static long calc_result(player_t *players)
{
/* we don't need to check for winner, as one list is empty */
card_t *card;
long res = 0, mult = 1;
list_for_each_entry_reverse(card, &players[0].head, list)
res += card->card * mult++;
list_for_each_entry_reverse(card, &players[1].head, list)
res += card->card * mult++;
return res;
}
static long part1(player_t *players) static long part1(player_t *players)
{ {
int round = 0, winner = 0; int round = 0, winner = 0;
while (players[0].ncards > 0 && players[1].ncards > 0) { while (players[0].ncards > 0 && players[1].ncards > 0) {
winner = 0; int val[2];
/* we can use list_first_entry() macro, as both lists are not empty */ /* we can use list_first_entry() macro, as both lists are not empty */
int val1 = list_first_entry(&players[0].head, struct card, list)->card; val[0] = list_first_entry(&players[0].head, struct card, list)->card;
int val2 = list_first_entry(&players[1].head, struct card, list)->card; val[1] = list_first_entry(&players[1].head, struct card, list)->card;
if (val2 > val1) winner = val[1] > val[0];
winner = 1;
winmove(players + winner, players + 1 - winner); winmove(players + winner, players + 1 - winner);
round++; round++;
} }
return calc_result(players);
return winner;
} }
static long part2(player_t *players) static long part2(player_t *players)
{ {
int round = 1, winner = 0, game; int round = 1, winner = 0, game;
long res = 0;
static int maxgame = 0; static int maxgame = 0;
DEFINE_HASHTABLE(hasht_deck, HBITS); /* htable for dup decks */ DEFINE_HASHTABLE(hasht_deck, HBITS); /* htable for dup decks */
game = ++maxgame;
log(2, "=== Game %d ===\n", game = ++maxgame);
while (players[0].ncards > 0 && players[1].ncards > 0) { while (players[0].ncards > 0 && players[1].ncards > 0) {
int val1, val2; int val[2];
winner = 0; winner = 0;
log(2, "\n-- Round %d (Game %d) --\n", round, game); if (find_deck(hasht_deck, players)) /* duplicate */
print_cards(players); goto end;
if (find_deck(hasht_deck, players)) {
log(3, "dup found\n");
goto end; // return winner;
} else {
log(3, "dup not found\n");
}
/* we can use list_first_entry() macro, as both lists are not empty */ /* we can use list_first_entry() macro, as both lists are not empty */
val1 = list_first_entry(&players[0].head, struct card, list)->card; val[0] = list_first_entry(&players[0].head, struct card, list)->card;
val2 = list_first_entry(&players[1].head, struct card, list)->card; val[1] = list_first_entry(&players[1].head, struct card, list)->card;
log(2, "Player 1 plays: %d\n", val1);
log(2, "Player 2 plays: %d\n", val2);
if (players[0].ncards > val1 && players[1].ncards > val2) { if (players[0].ncards > val[0] && players[1].ncards > val[1]) {
player_t sub[2]; player_t sub[2];
log(2, "Playing a sub-game to determine the winner...\n\n");
winner = part2(create_subgame(players, sub)); winner = part2(create_subgame(players, sub));
log(2, "\n...anyway, back to game %d\n", game);
} else { } else {
if (val2 > val1) winner = val[1] > val[0];
winner = 1;
} }
winmove(players + winner, players + 1 - winner); winmove(players + winner, players + 1 - winner);
log(2, "Player %d wins round %d of game %d!\n", winner + 1, round, game);
round++; round++;
} }
end: end:
log(2, "The winner of game %d is player %d!\n", game, winner + 1); if (game == 1)
res = calc_result(players);
/* cleanup decks */ /* cleanup decks */
card_t *card, *tmp; card_t *card, *tmp1;
if (game != 1) { for (int i = 0; i < 2; ++i) {
list_for_each_entry_safe(card, tmp1, &players[i].head, list) {
list_del(&card->list);
pool_add(pool_cards, card);
}
}
/* cleanup hashtable */
ulong bkt;
struct hlist_node *tmp2;
hash_t *obj;
hash_for_each_safe(hasht_deck, bkt, tmp2, obj, hlist) {
/* cleanup hash decks */
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
list_for_each_entry_safe(card, tmp, &players[i].head, list) { list_for_each_entry_safe(card, tmp1, &obj->players[i], list) {
list_del(&card->list); list_del(&card->list);
pool_add(pool_cards, card); pool_add(pool_cards, card);
} }
} }
hlist_del(&obj->hlist);
pool_add(pool_hash, obj);
} }
return winner; return game == 1? res: winner;
} }
int main(int ac, char **av) int main(int ac, char **av)
@@ -338,26 +300,13 @@ int main(int ac, char **av)
} }
} }
pool_cards = pool_create("cards", 128, sizeof(struct card)); pool_cards = pool_create("cards", 4096, sizeof(struct card));
pool_hash = pool_create("hash", 128, sizeof(struct hash)); pool_hash = pool_create("hash", 128, sizeof(struct hash));
zobrist_init(); zobrist_init();
player_t players[2]; player_t players[2];
parse(players); parse(players);
if (part == 1) long res = part == 1 ? part1(players): part2(players);
part1(players);
else
part2(players);
/* we don't need to check for winner, as one list is empty */
log(2, "\n== Post-game results ==\n");
print_cards(players);
card_t *card;
long res = 0, mult = 1;
list_for_each_entry_reverse(card, &players[0].head, list)
res += card->card * mult++;
list_for_each_entry_reverse(card, &players[1].head, list)
res += card->card * mult++;
printf("%s : res=%ld\n", *av, res); printf("%s : res=%ld\n", *av, res);
exit(0); exit(0);

View File

@@ -8,7 +8,7 @@
- `C`: Days 1-9 - `C`: Days 1-9
#### Advent of Code 2020 #### Advent of Code 2020
- `C`: Days 1-19, 23-25 - `C`: Days 1-19, 22-25
- `Bash`: All (days 1-25) - `Bash`: All (days 1-25)
- `Cobol`: Day 1 (!!) - `Cobol`: Day 1 (!!)