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 }