226 lines
5.8 KiB
C
226 lines
5.8 KiB
C
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#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());
|
|
}
|