puzzle.c (3200B)
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 12 #define STR_LEN 2048 13 14 bool is_digit(char b) { 15 return b>='0' && b<='9'; 16 } 17 18 typedef enum LinePart { 19 LINE_PART_NONE, 20 LINE_PART_CARD, 21 LINE_PART_WINS, 22 LINE_PART_NUMS 23 } LinePart; 24 25 typedef struct Card { 26 int id; 27 int count; 28 int wins; 29 struct Card *next; 30 } Card; 31 32 Card * make_card() { 33 Card *c = malloc(sizeof(Card)); 34 memset(c, 0, sizeof(Card)); 35 return c; 36 } 37 38 void print_cards(Card *first) { 39 Card *c = first; 40 while (c!=NULL) { 41 printf("%d: %d\n", c->id, c->wins); 42 c = c->next; 43 } 44 } 45 46 typedef struct Number { 47 int value; 48 struct Number *next; 49 } Number; 50 51 Number * make_number(int val) { 52 Number *num = malloc(sizeof(Number)); 53 memset(num, 0, sizeof(Number)); 54 num->value = val; 55 return num; 56 } 57 58 void print_numbers(Number *first) { 59 Number *n = first; 60 while (n!=NULL) { 61 printf("%d -> ", n->value); 62 n = n->next; 63 } 64 printf("\n"); 65 } 66 67 void puzzle(const char *filename, long long *result1, long long *result2) { 68 FILE *infile = fopen(filename, "r"); 69 if (infile == NULL) { 70 fprintf(stderr, "fopen() error: %s\n", strerror(errno)); 71 return; 72 } 73 74 char buf[STR_LEN] = {0}; 75 unsigned int line_num = 0; 76 77 *result1 = 0; 78 *result2 = 0; 79 80 Card *cards = NULL; 81 Card *card_last = NULL; 82 83 while (fgets(buf, STR_LEN, infile) != NULL) { 84 Number *wins = NULL; 85 Number *wins_last = NULL; 86 Number *nums = NULL; 87 Number *nums_last = NULL; 88 Card *card = make_card(); 89 int len = strlen(buf); 90 int i = 0; 91 LinePart part = LINE_PART_CARD; 92 int num = 0; 93 while (i<len) { 94 if (part==LINE_PART_CARD && buf[i]==':') { 95 part = LINE_PART_WINS; 96 card->id = num; 97 card->count = 1; 98 if (cards==NULL) cards = card; 99 if (card_last!=NULL) card_last->next = card; 100 card_last = card; 101 num = 0; 102 } else if (part==LINE_PART_WINS && buf[i]=='|') { 103 part = LINE_PART_NUMS; 104 } else if (is_digit(buf[i])) { 105 num = num*10 + buf[i] - '0'; 106 } else if (part!=LINE_PART_CARD && (buf[i]==' '||buf[i]==10) && num!=0) { 107 if (part==LINE_PART_WINS) { 108 Number *n = make_number(num); 109 if (wins==NULL) wins=n; 110 if (wins_last!=NULL) wins_last->next = n; 111 wins_last = n; 112 } else if (part==LINE_PART_NUMS) { 113 Number *n = make_number(num); 114 if (nums==NULL) nums=n; 115 if (nums_last!=NULL) nums_last->next = n; 116 nums_last = n; 117 } 118 num=0; 119 } 120 ++i; 121 } 122 123 int score = 0; 124 for (Number *n = nums; n!=NULL; n=n->next) { 125 for (Number *w = wins; w!=NULL; w=w->next) { 126 if (n->value==w->value) { 127 card->wins++; 128 if (score==0) score=1; 129 else score*=2; 130 } 131 } 132 } 133 *result1 += score; 134 135 ++line_num; 136 bzero(buf, STR_LEN); 137 } 138 139 int cnt = card_last->id; 140 int copies[cnt]; 141 memset(&copies, 0, sizeof(int)*cnt); 142 for (int i=0; i<cnt; ++i) { 143 copies[i] = 1; 144 } 145 146 Card *card = cards; 147 while (card!=NULL) { 148 int cid = card->id-1; 149 for (int j=0; j<copies[cid]; ++j) { 150 for (int i=1; i<=card->wins; ++i) { 151 copies[cid+i]++; 152 } 153 } 154 card = card->next; 155 } 156 for (int i=0; i<cnt; ++i) { 157 *result2 += copies[i]; 158 } 159 160 // mutiny! ignoring feof/ferror. 161 fclose(infile); 162 }