#include #include #include #include #include void normalize(char *data) { for (char *p = data; *p; p++) { if (*p == '\n' && *(p + 1) == '\n') { *p = ' '; p++; } else if (*p == '\n') { *p = ' '; } } } char *valid[] = { "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid" }; char *valid_colors[] = { "amb", "blu", "brn", "gry", "grn", "hzl", "oth" }; int part_one(char *data) { int res = 0; int correct = 0; for (char *p = data; *p; p++) { if (*p == '\n') { if (correct == 7) res++; correct = 0; continue; } char key[4] = { 0 }; char value[16] = { 0 }; sscanf(p, "%3[^:]:%s ", key, value); for (int i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) { if (!strcmp(key, valid[i])) { correct++; break; } } p += 3 + strlen(value) + 1; if (*(p + 1) == '\0') { if (correct == 7) res++; } } return res; } #define EQ(a, b) (!strcmp((a), (b))) // String equality #define BR(x) ((x) >= 1920 && (x) <= 2002) // Birth rule #define IR(x) ((x) >= 2010 && (x) <= 2020) // Issue rule #define ER(x) ((x) >= 2020 && (x) <= 2030) // Expiration rule #define HR(x) ((x) >= 150 && (x) <= 193) // Height rule #define CR(x) \ (EQ(x, "amb") || EQ(x, "blu") || EQ(x, "brn") || EQ(x, "gry") || EQ(x, "grn") || \ EQ(x, "hzl") || EQ(x, "oth")) // Eye color rule // BTW: I hate gotos int part_two(char *data) { int res = 0; int correct = 0; for (char *p = data; *p; p++) { if (*p == '\n') { if (correct == 7) res++; correct = 0; continue; } char key[4] = { 0 }; char value[16] = { 0 }; sscanf(p, "%3[^:]:%s ", key, value); // General value verification/parsing int y = 0; if (EQ(key, "byr") || EQ(key, "iyr") || EQ(key, "eyr")) { if (!sscanf(value, "%4d", &y)) goto invalid; } else if (EQ(key, "hgt")) { char last = value[strlen(value) - 1]; if (last == 'm') { sscanf(value, "%dcm", &y); } else if (last == 'n') { sscanf(value, "%din", &y); y = (int)roundf(((float)y * 2.54)); // lol } else { goto invalid; } } else if (EQ(key, "hcl") && (strlen(value) != 7 || !sscanf(value, "#%6x", &y))) { goto invalid; } else if (EQ(key, "ecl")) { char c[4]; if (!sscanf(value, "%3s", c) || !CR(c)) goto invalid; } else if (EQ(key, "pid")) { if (!sscanf(value, "%9d", &y)) goto invalid; } // Number range verification if (EQ(key, "byr") && !BR(y)) goto invalid; else if (EQ(key, "iyr") && !IR(y)) goto invalid; else if (EQ(key, "eyr") && !ER(y)) goto invalid; else if (EQ(key, "hgt") && !HR(y)) { goto invalid; } for (int i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) { if (!strcmp(key, valid[i])) { correct++; break; } } goto next; invalid: /* printf("Invalid: %s:%s (y=%d)\n", key, value, y); */ correct = -42; // Awesome fix! next: p += 3 + strlen(value) + 1; if (*(p + 1) == '\0') { if (correct == 7) res++; } } return res; } #define SIZE 20000 int main(int argc, char *argv[]) { FILE *fp = fopen("input", "r"); if (!fp) exit(EXIT_FAILURE); char buf[SIZE] = { 0 }; fread(buf, SIZE, 1, fp); clock_t tic = clock(); normalize(buf); printf("%d\n", part_one(buf)); printf("%d\n", part_two(buf)); clock_t toc = clock(); printf("TIME: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC); fclose(fp); return 0; }