diff options
Diffstat (limited to 'src/2020/day4/aoc.h')
-rw-r--r-- | src/2020/day4/aoc.h | 109 |
1 files changed, 102 insertions, 7 deletions
diff --git a/src/2020/day4/aoc.h b/src/2020/day4/aoc.h index a0b42b5..663fa1b 100644 --- a/src/2020/day4/aoc.h +++ b/src/2020/day4/aoc.h @@ -4,7 +4,7 @@ namespace aoc2020 { -struct passwort { +struct passport { line_view byr; line_view iyr; line_view eyr; @@ -14,19 +14,114 @@ struct passwort { line_view pid; line_view cid; - friend std::ostream& operator<<(std::ostream& o, const passwort& p) { + friend std::ostream& operator<<(std::ostream& o, const passport& p) { o << p.byr << " " << p.iyr << " " << p.eyr << " "; o << p.hgt << " " << p.hcl << " " << p.ecl << " "; o << p.pid << " " << p.cid << " "; return o; } - bool is_valid() const noexcept { - return byr.length > 0 && iyr.length > 0 && eyr.length > 0 && hgt.length > 0 && hcl.length > 0 && ecl.length > 0 && - pid.length > 0; + void get_number(const char** pp, int* d) { + const char* p = *pp; + while (*p >= '0' && *p <= '9') { + *d = *d * 10 + *p - '0'; + p++; + } + *pp = p; + } + + typedef bool (passport::*cf)(line_view); + + template <int A, int B, int C> + bool chk1(line_view lv) { + int y{0}; + const char* p = lv.line; + get_number(&p, &y); + return lv.length == A && y >= B && y <= C; + } + + bool chk2(line_view lv) { + int d{0}; + const char* p = lv.line; + get_number(&p, &d); + bool b1 = (*p == 'c' && *(p + 1) == 'm') && d >= 150 && d <= 193; + bool b2 = (*p == 'i' && *(p + 1) == 'n') && d >= 59 && d <= 76; + return b1 || b2; + } + + bool chk3(line_view lv) { + static const char* cs[] = {"amb", "blu", "brn", "gry", "grn", "hzl", "oth"}; + for (auto c : cs) { + if (lv == c) { + return true; + } + } + return false; + } + + template <int A, char B, char C> + bool chk4(line_view lv) { + const char* p = lv.line; + for (int i = 0; i < A; i++) { + if (*(p + i) < B || *(p + i) > C) { + return false; + } + } + return lv.length == A; + } + + bool chk5(line_view lv) { + const char* p = lv.line + 1; + auto is_az = [](char c) { return c >= 'a' && c <= 'z'; }; + auto is_09 = [](char c) { return c >= '0' && c <= '9'; }; + while (p < lv.line + lv.length) { + if (!is_az(*p) && !is_09(*p)) { + return false; + } + p++; + } + return *lv.line == '#' && lv.length == 7; + } + + // byr (Birth Year) - four digits; at least 1920 and at most 2002. + // iyr (Issue Year) - four digits; at least 2010 and at most 2020. + // eyr (Expiration Year) - four digits; at least 2020 and at most 2030. + // 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. + // hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. + // ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. + // pid (Passport ID) - a nine-digit number, including leading zeroes. + // cid (Country ID) - ignored, missing or not. + + void is_valid(bool* b1, bool* b2) { + *b1 = byr.length > 0 && iyr.length > 0 && eyr.length > 0 && hgt.length > 0 && hcl.length > 0 && ecl.length > 0 && + pid.length > 0; + + *b2 = false; + if (*b1) { + struct { + cf f; + line_view* field; + } checkers[] = { + {&passport::chk1<4, 1920, 2002>, &byr}, + {&passport::chk1<4, 2010, 2020>, &iyr}, + {&passport::chk1<4, 2020, 2030>, &eyr}, + {&passport::chk2, &hgt}, + {&passport::chk5, &hcl}, + {&passport::chk3, &ecl}, + {&passport::chk4<9, '0', '9'>, &pid}, + }; + for (auto c : checkers) { + if (!((this->*(c.f))(*c.field))) { + return; + } + } + *b2 = true; + } } - passwort(const char* p1, const char* p2) { + passport(const char* p1, const char* p2) { struct { line_view* field; const char* label; @@ -64,5 +159,5 @@ struct passwort { } }; -int day4(line_view); +std::pair<int, int> day4(line_view); } // namespace aoc2020 |