advent2023

Advent of Code 2023 solutions
git clone git://bsandro.tech/advent2023
Log | Files | Refs | LICENSE

puzzle.c (4863B)


      1 #define _DEFAULT_SOURCE
      2 
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <errno.h>
      7 #include <string.h>
      8 #include <strings.h>
      9 #include <assert.h>
     10 #include <stdbool.h>
     11 #include <inttypes.h>
     12 
     13 #define STR_LEN 2048
     14 #define CARDS_LEN 5
     15 #define COUNTS_LEN 15
     16 
     17 typedef enum HandType {
     18 	Hand_Unknown      = 0,
     19 	Hand_HighCard     = 50000,
     20 	Hand_OnePair      = 41000,
     21 	Hand_TwoPair      = 32000,
     22 	Hand_ThreeOfAKind = 31100,
     23 	Hand_FullHouse    = 22100,
     24 	Hand_FourOfAKind  = 21110,
     25 	Hand_FiveOfAKind  = 11111
     26 } HandType;
     27 
     28 typedef struct Hand {
     29 	HandType type;
     30 	int bid;
     31 	char cards_orig[CARDS_LEN+1];
     32 	int cards[CARDS_LEN];
     33 	int counts[COUNTS_LEN];
     34 	int32_t csum;
     35 } Hand;
     36 
     37 static int get_card(char c) {
     38 	if (c>='2'&&c<='9') return c-'0';
     39 	if (c=='T') return 10;
     40 	if (c=='J') return 11;
     41 	if (c=='Q') return 12;
     42 	if (c=='K') return 13;
     43 	if (c=='A') return 14;
     44 	return -1;
     45 }
     46 
     47 static int get_card2(char c) {
     48 	if (c>='2'&&c<='9') return c-'0';
     49 	if (c=='T') return 10;
     50 	if (c=='J') return 1;
     51 	if (c=='Q') return 12;
     52 	if (c=='K') return 13;
     53 	if (c=='A') return 14;
     54 	return -1;
     55 }
     56 
     57 void make_type(Hand *h) {
     58 	int sum = 10000*h->counts[0] +
     59 	           1000*h->counts[1] +
     60 	            100*h->counts[2] +
     61 	             10*h->counts[3] +
     62 	                h->counts[4];
     63 	h->type = (HandType)sum;
     64 }
     65 
     66 void make_counts(Hand *h, bool use_joker) {
     67 	memset(h->counts, 0, sizeof(int)*COUNTS_LEN);
     68 	for (int i=0; i<CARDS_LEN; ++i) {
     69 		h->counts[h->cards[i]]++;
     70 	}
     71 
     72 	int jk = get_card2('J');
     73 	if (use_joker && h->counts[jk]>0) {
     74 		printf("(jk:%d)", h->counts[jk]);
     75 		int *curmax = &h->counts[COUNTS_LEN-1];
     76 		for (int i=COUNTS_LEN-1; i>=0; --i) {
     77 			if (i!=jk) {
     78 				if (h->counts[i] > *curmax) {
     79 					curmax = &h->counts[i];
     80 				}
     81 			}
     82 		}
     83 		//printf("(curmax:%d)", *curmax);
     84 		*curmax += h->counts[jk];
     85 		h->counts[jk] = 0;
     86 	}
     87 }
     88 
     89 void make_csum(Hand *h) {
     90 	h->csum = 100000000*get_card(h->cards_orig[0]) +
     91 	            1000000*get_card(h->cards_orig[1]) +
     92 	              10000*get_card(h->cards_orig[2]) +
     93 	                100*get_card(h->cards_orig[3]) +
     94 	                    get_card(h->cards_orig[4]);
     95 }
     96 
     97 void make_csum2(Hand *h) {
     98 	h->csum = 100000000*get_card2(h->cards_orig[0]) +
     99 	            1000000*get_card2(h->cards_orig[1]) +
    100 	              10000*get_card2(h->cards_orig[2]) +
    101 	                100*get_card2(h->cards_orig[3]) +
    102 	                    get_card2(h->cards_orig[4]);
    103 }
    104 
    105 static int cmp_cards(const void *c1, const void *c2) {
    106 	return *(int *)c1 - *(int *)c2;
    107 }
    108 
    109 static int cmp_counts(const void *c1, const void *c2) {
    110 	return *(int *)c2 - *(int *)c1;
    111 }
    112 
    113 static int cmp_hands(const void *v1, const void *v2) {
    114 	const Hand *h1 = (Hand *)v1;
    115 	const Hand *h2 = (Hand *)v2;
    116 	if (h1->type!=h2->type) {
    117 		return h1->type - h2->type;
    118 	}
    119 	return h1->csum - h2->csum;
    120 }
    121 
    122 void puzzle(const char *filename, long long *result1, long long *result2) {
    123 	FILE *infile = fopen(filename, "r");
    124 	if (infile == NULL) {
    125 		fprintf(stderr, "fopen() error: %s\n", strerror(errno));
    126 		return;
    127 	}
    128 
    129 	char buf[STR_LEN] = {0};
    130 	unsigned int line_num = 0;
    131 	*result1 = 0;
    132 	*result2 = 0;
    133 
    134 	Hand *hands = NULL;
    135 	int hands_len = 0;
    136 	while (fgets(buf, STR_LEN, infile) != NULL) {
    137 		hands_len++;
    138 		hands = realloc(hands, sizeof(Hand)*hands_len);
    139 		Hand *h = &hands[hands_len-1];
    140 		memset(h, 0, sizeof(Hand));
    141 		sscanf(buf, "%s %d", h->cards_orig, &h->bid);
    142 		for (int i=0; i<CARDS_LEN; ++i) {
    143 			h->cards[i] = get_card(h->cards_orig[i]);
    144 		}
    145 		qsort(h->cards, CARDS_LEN, sizeof(int), cmp_cards);
    146 		make_counts(h, false);
    147 		make_csum(h);
    148 		qsort(h->counts, COUNTS_LEN, sizeof(int), cmp_counts);
    149 		make_type(h);
    150 		//
    151 
    152 		++line_num;
    153 		bzero(buf, STR_LEN);
    154 	}
    155 
    156 	printf("--------- part 1 ----------\n");
    157 	qsort(hands, hands_len, sizeof(Hand), cmp_hands);
    158 	for (int i=0; i<hands_len; ++i) {
    159 		printf("hand %2d %s, type %d, bid %3d; ", i, hands[i].cards_orig, hands[i].type, hands[i].bid);
    160 		for (int j=0; j<CARDS_LEN; ++j) {
    161 			printf("%2d ", hands[i].cards[j]);
    162 		}
    163 		printf(" csum: %10d | ", hands[i].csum);
    164 		for (int j=0; j<COUNTS_LEN; ++j) {
    165 			if (hands[i].counts[j]>0) {
    166 				printf("%d ", hands[i].counts[j]);
    167 			}
    168 		}
    169 		printf("\n");
    170 		*result1 += (i+1)*hands[i].bid;
    171 	}
    172 
    173 	// 246452271 too high
    174 	printf("----------- part 2 ------------\n");
    175 	for (int i=0; i<hands_len; ++i) {
    176 		Hand *h = &hands[i];
    177 		printf("hand %s: was type %d, now ", h->cards_orig, h->type);
    178 		memset(h->cards, 0, sizeof(int)*CARDS_LEN);
    179 		for (int j=0; j<CARDS_LEN; ++j) {
    180 			h->cards[j] = get_card2(h->cards_orig[j]);
    181 		}
    182 		make_counts(h, true);
    183 		make_csum2(h);
    184 		qsort(h->counts, COUNTS_LEN, sizeof(int), cmp_counts);
    185 		make_type(h);
    186 		printf("%d\n", h->type);
    187 	}
    188 	qsort(hands, hands_len, sizeof(Hand), cmp_hands);
    189 	for (int i=0; i<hands_len; ++i) {
    190 		printf("hand %2d %s type %d\n", i, hands[i].cards_orig, hands[i].type);
    191 		*result2 += (i+1)*hands[i].bid;
    192 	}
    193 
    194 	// mutiny! ignoring feof/ferror.
    195 	fclose(infile);
    196 }