#include #include #include #include "../lib/util.h" typedef char Year[5]; typedef char Height[6]; typedef char HexColor[8]; typedef char Color[4]; typedef char PID[10]; typedef char CID[4]; typedef struct Passport { Year byr; Year iyr; Year eyr; Height hgt; HexColor hcl; Color ecl; PID pid; CID cid; } Passport; bool is_valid_passport_part_1(Passport *passport) { if (passport->byr[0] == '\0') return false; if (passport->iyr[0] == '\0') return false; if (passport->eyr[0] == '\0') return false; if (passport->hgt[0] == '\0') return false; if (passport->hcl[0] == '\0') return false; if (passport->ecl[0] == '\0') return false; if (passport->pid[0] == '\0') return false; return true; } bool is_valid_passport_part_2(Passport *passport) { // byr (Birth Year) - four digits; at least 1920 and at most 2002. if (passport->byr[0] == '\0') return false; int byr = atoi(passport->byr); if (byr < 1920 || byr > 2002) return false; // iyr (Issue Year) - four digits; at least 2010 and at most 2020. if (passport->iyr[0] == '\0') return false; int iyr = atoi(passport->iyr); if (iyr < 2010 || iyr > 2020) return false; // eyr (Expiration Year) - four digits; at least 2020 and at most 2030. if (passport->eyr[0] == '\0') return false; int eyr = atoi(passport->eyr); if (eyr < 2020 || eyr > 2030) return false; // hgt (Height) - a number followed by either cm or in: // If cm, the number must be at least 150 and at most 193. // If in, the number must be at least 59 and at most 76. if (passport->hgt[0] == '\0') return false; int hgt = atoi(passport->hgt); if (hgt >= 59 && hgt <= 76) { if (passport->hgt[2] != 'i' && passport->hgt[3] != 'n') return false; } else if (hgt >= 150 && hgt <= 193) { if (passport->hgt[3] != 'c' && passport->hgt[4] != 'm') return false; } else return false; // hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. if (passport->hcl[0] != '#') return false; for (int i = 1; i < 7; i++) { char c = passport->hcl[i]; if (c < 48 || (c > 57 && c < 97) || c > 122) return false; } // ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. if (passport->ecl[0] == '\0') return false; char *ecl = passport->ecl; if ( strcmp(ecl, "amb") != 0 && strcmp(ecl, "blu") != 0 && strcmp(ecl, "brn") != 0 && strcmp(ecl, "gry") != 0 && strcmp(ecl, "grn") != 0 && strcmp(ecl, "hzl") != 0 && strcmp(ecl, "oth") != 0 && strcmp(ecl, "amb") != 0 ) return false; // pid (Passport ID) - a nine-digit number, including leading zeroes. if (passport->pid[0] == '\0') return false; if (strlen(passport->pid) != 9) return false; // cid (Country ID) - ignored, missing or not. return true; } void clear_passport(Passport *passport) { *(passport->byr) = 0; *(passport->iyr) = 0; *(passport->eyr) = 0; *(passport->hgt) = 0; *(passport->hcl) = 0; *(passport->ecl) = 0; *(passport->pid) = 0; *(passport->cid) = 0; } void print_passport(Passport *passport) { printf( "Birth Year: %s\n" "Issue Year: %s\n" "Expiration Year: %s\n" "Height: %s\n" "Hair Color: %s\n" "Eye Color: %s\n" "Passport ID: %s\n" "Country ID: %s\n", passport->byr, passport->iyr, passport->eyr, passport->hgt, passport->hcl, passport->ecl, passport->pid, passport->cid ); } void parse_passport_field(char *field, Passport *passport) { switch(*field) { case 'b': strcpy(passport->byr, field + 4); break; case 'i': strcpy(passport->iyr, field + 4); break; case 'e': switch(*(field + 1)) { case 'y': strcpy(passport->eyr, field + 4); break; case 'c': strcpy(passport->ecl, field + 4); break; } break; case 'h': switch(*(field + 1)) { case 'c': strcpy(passport->hcl, field + 4); break; case 'g': strcpy(passport->hgt, field + 4); break; } break; case 'p': strcpy(passport->pid, field + 4); break; case 'c': strcpy(passport->cid, field + 4); break; } } void parse_passport(char *text, Passport *passport) { char *pp_text = strtok(text, " "); do { parse_passport_field(pp_text, passport); } while(pp_text = strtok(NULL, " ")); } int check_valid_passports(bool (*passport_validator) (Passport *passport)) { InputWithSize *input_with_size = load_input_with_size(); char *input_normalized = malloc(input_with_size -> size); char *data_pointer = input_with_size -> data_buffer; char *normalized_pointer = input_normalized; int passport_count = 0; for (int i = 0; i < input_with_size -> size; i++) { if (data_pointer[i] == '\n') { if (data_pointer[i + 1] == '\n') { *normalized_pointer = '\0'; i++; passport_count++; } else { *normalized_pointer = ' '; } } else { *normalized_pointer = data_pointer[i]; } normalized_pointer++; } *normalized_pointer = 0; int normalized_size = normalized_pointer - input_normalized; free_input_with_size(input_with_size); normalized_pointer = input_normalized; Passport *passport = malloc(sizeof(Passport)); int passport_text_len = strlen(normalized_pointer); int valid_passports = 0; while(*normalized_pointer != '\0') { clear_passport(passport); parse_passport(normalized_pointer, passport); if (passport_validator(passport)) valid_passports++; // print_passport(passport); // puts(""); normalized_pointer += passport_text_len + 1; passport_text_len = strlen(normalized_pointer); } free(passport); free(input_normalized); return valid_passports; } int part_1() { return check_valid_passports(is_valid_passport_part_1); } int part_2() { return check_valid_passports(is_valid_passport_part_2); } int main() { printf("Part 1: %d\n", part_1()); printf("Part 2: %d\n", part_2()); }