aoc_omni/c/2020/4/main.c
2025-11-30 21:22:21 -05:00

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());
}