Files
adventofcode2023/day7/c/day7.c
dobiadi 14d18f6814 Day7 C
2023-12-09 01:54:59 +01:00

249 lines
6.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_MAX_LENGTH 64
#define MAX_HANDS 2048
#define CARDS_PER_HAND 5
enum hand_type {
UNKNOWN,
FIVE_OF_A_KIND,
FOUR_OF_A_KIND,
FULL_HOUSE,
THREE_OF_A_KIND,
TWO_PAIR,
ONE_PAIR,
HIGH_CARD
};
const char card_values[] = {'A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2'};
const char card_values2[] = {'A', 'K', 'Q', 'T', '9', '8', '7', '6', '5', '4', '3', '2', 'J'};
#define card_values_len (sizeof(card_values) / sizeof(card_values[0]))
typedef struct hand {
char cards[CARDS_PER_HAND];
unsigned long bid;
enum hand_type type;
} hand_t;
enum hand_type get_hand_type(hand_t *hand, int allow_joker);
int cmp(const void *a, const void *b);
int cmp2(const void *a, const void *b);
int main() {
char *p, *buf, c;
buf = (char *)malloc(LINE_MAX_LENGTH);
memset(buf, 0, LINE_MAX_LENGTH);
p = buf;
hand_t hands[MAX_HANDS];
memset(hands, 0, MAX_HANDS * sizeof(hand_t));
int hands_num = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c == '\n') {
p = buf;
sscanf(p, "%c%c%c%c%c %lu", &hands[hands_num].cards[0], &hands[hands_num].cards[1], &hands[hands_num].cards[2], &hands[hands_num].cards[3], &hands[hands_num].cards[4], &hands[hands_num].bid);
hands_num++;
memset(buf, 0, LINE_MAX_LENGTH);
p = buf;
}
}
// Part1
for (int i = 0; i < hands_num; i++) {
hands[i].type = get_hand_type(&hands[i], 0);
}
qsort(hands, hands_num, sizeof(hand_t), cmp);
unsigned long part1 = 0;
for (int i = 0; i < hands_num; i++) {
part1 += (i+1) * hands[i].bid;
}
printf("%lu\n", part1);
// Part2
for (int i = 0; i < hands_num; i++) {
hands[i].type = get_hand_type(&hands[i], 1);
}
qsort(hands, hands_num, sizeof(hand_t), cmp2);
unsigned long part2 = 0;
for (int i = 0; i < hands_num; i++) {
part2 += (i+1) * hands[i].bid;
}
printf("%lu\n", part2);
free(buf);
}
enum hand_type get_hand_type(hand_t *hand, int allow_joker) {
// Five of a kind
int good = 0;
for (int i = 0; i < CARDS_PER_HAND; i++) {
good = 0;
for (int j = 0; j < CARDS_PER_HAND; j++) {
if (hand->cards[i] == hand->cards[j] || (allow_joker && hand->cards[j] == 'J')) {
good++;
}
}
if (good == 5) {
return FIVE_OF_A_KIND;
}
}
// Four of a kind
for (int i = 0; i < CARDS_PER_HAND; i++) {
good = 0;
for (int j = 0; j < CARDS_PER_HAND; j++) {
if (hand->cards[i] == hand->cards[j] || (allow_joker && hand->cards[j] == 'J')) {
good++;
}
}
if (good == 4) {
return FOUR_OF_A_KIND;
}
}
// Full house
int good2 = 0;
for (int i = 0; i < CARDS_PER_HAND; i++) {
for (int j = 0; j < CARDS_PER_HAND; j++) {
good = 0;
good2 = 0;
int used_jokers[5] = {0, 0, 0, 0, 0};
for (int k = 0; k < CARDS_PER_HAND; k++) {
if (hand->cards[i] == hand->cards[k] || (allow_joker && !used_jokers[k] && hand->cards[k] == 'J')) {
good++;
if (allow_joker && hand->cards[k] == 'J') {
used_jokers[k] = 1;
}
}
}
for (int k = 0; k < CARDS_PER_HAND; k++) {
if (hand->cards[j] == hand->cards[k] || (allow_joker && !used_jokers[k] && hand->cards[k] == 'J')) {
good2++;
}
}
if ((good == 3 && good2 == 2 || good == 2 && good2 == 3) && hand->cards[i] != 'J' && hand->cards[j] != 'J' && hand->cards[i] != hand->cards[j]) {
return FULL_HOUSE;
}
}
}
// Three of a kind
for (int i = 0; i < CARDS_PER_HAND; i++) {
good = 0;
for (int j = 0; j < CARDS_PER_HAND; j++) {
if (hand->cards[i] == hand->cards[j] || (allow_joker && hand->cards[j] == 'J')) {
good++;
}
}
if (good == 3) {
return THREE_OF_A_KIND;
}
}
// Two pair
for (int i = 0; i < CARDS_PER_HAND; i++) {
for (int j = 0; j < CARDS_PER_HAND; j++) {
good = 0;
good2 = 0;
int used_joker = 0;
for (int k = 0; k < CARDS_PER_HAND; k++) {
if (hand->cards[i] == hand->cards[k] || (allow_joker && hand->cards[k] == 'J')) {
good++;
if (allow_joker && hand->cards[k] == 'J') {
used_joker = 1;
}
}
}
for (int k = 0; k < CARDS_PER_HAND; k++) {
if (hand->cards[j] == hand->cards[k] || (allow_joker && !used_joker && hand->cards[k] == 'J')) {
good2++;
}
}
if (good == 2 && good2 == 2 && hand->cards[i] != hand->cards[j]) {
return TWO_PAIR;
}
}
}
// One pair
for (int i = 0; i < CARDS_PER_HAND; i++) {
good = 0;
for (int j = 0; j < CARDS_PER_HAND; j++) {
if (hand->cards[i] == hand->cards[j] || (allow_joker && hand->cards[j] == 'J')) {
good++;
}
}
if (good == 2) {
return ONE_PAIR;
}
}
return HIGH_CARD;
}
int cmp(const void *a, const void *b) {
hand_t *hand1 = (hand_t*) a, *hand2 = (hand_t*) b;
if (hand1->type == hand2->type) {
for (int i = 0; i < CARDS_PER_HAND; i++) {
int j, k;
for (j = 0; j < card_values_len; j++) {
if (hand1->cards[i] == card_values[j]) {
break;
}
}
for (k = 0; k < card_values_len; k++) {
if (hand2->cards[i] == card_values[k]) {
break;
}
}
if (j != k) {
return k - j;
}
}
}
return hand2->type - hand1->type;
}
int cmp2(const void *a, const void *b) {
hand_t *hand1 = (hand_t*) a, *hand2 = (hand_t*) b;
if (hand1->type == hand2->type) {
for (int i = 0; i < CARDS_PER_HAND; i++) {
int j, k;
for (j = 0; j < card_values_len; j++) {
if (hand1->cards[i] == card_values2[j]) {
break;
}
}
for (k = 0; k < card_values_len; k++) {
if (hand2->cards[i] == card_values2[k]) {
break;
}
}
if (j != k) {
return k - j;
}
}
}
return hand2->type - hand1->type;
}