#include #include #include #include #include class Passport { std::optional birthYear; std::optional issueYear; std::optional expireYear; std::optional height; std::optional hairColour; std::optional eyeColour; std::optional passportId; std::optional countryId; public: Passport() = default; [[nodiscard]] bool isValid() const { return birthYear.has_value() && issueYear.has_value() && expireYear.has_value() && height.has_value() && hairColour.has_value() && eyeColour.has_value() && passportId.has_value(); // && countryId.has_value(); } Passport &withBirthYear(uint32_t year) { this->birthYear = year; return *this; } Passport &withIssueYear(uint32_t year) { this->issueYear = year; return *this; } Passport &withExpirationYear(uint32_t year) { this->expireYear = year; return *this; } Passport &withHeightInCentimeters(uint32_t cm) { this->height = (float) cm; return *this; } Passport &withHeightInInches(uint32_t inches) { this->height = inches * 2.54f; return *this; } Passport &withHairColour(std::string colour) { this->hairColour = colour; return *this; } Passport &withEyeColour(std::string colour) { this->eyeColour = colour; return *this; } Passport &withPassportId(uint64_t id) { this->passportId = id; return *this; } Passport &withCountryId(uint64_t id) { this->countryId = id; return *this; } }; std::vector getProperties(std::string &line) { std::vector properties; std::string tmp = line; size_t end = tmp.find(' '); while (end != std::variant_npos) { std::string property = tmp.substr(0, end); properties.push_back(property); tmp = tmp.substr(end + 1); end = tmp.find(' '); } properties.push_back(tmp); return properties; } bool isValidHairColour(std::string &str) { if (str[0] != '#') return false; return std::variant_npos == str.find_first_not_of("0123456789abcdefABCDEF", 1); } bool isValidEyeColour(std::string &str) { if (str == "amb") return true; if (str == "blu") return true; if (str == "brn") return true; if (str == "gry") return true; if (str == "grn") return true; if (str == "hzl") return true; if (str == "oth") return true; return false; } int main() { std::ifstream input{"../input.txt"}; std::vector passports; uint32_t p1ValidCount = 0; uint32_t p2ValidCount = 0; std::string line; Passport p1Passport = {}; Passport p2Passport = {}; while (std::getline(input, line)) { if (line.empty()) { if (p1Passport.isValid()) p1ValidCount++; if (p2Passport.isValid()) p2ValidCount++; p1Passport = {}; p2Passport = {}; continue; } std::vector properties = getProperties(line); for (std::string &property : properties) { std::string type = property.substr(0, 3); std::string value = property.substr(4); if (type == "byr") { try { uint32_t year = std::stoi(value); p1Passport.withBirthYear(year); if (year >= 1920 && year <= 2002) p2Passport.withBirthYear(year); } catch (const std::exception &) { std::cout << value << " is not an integer. [BYR]" << std::endl; } } else if (type == "iyr") { try { uint32_t year = std::stoi(value); p1Passport.withIssueYear(year); if (year >= 2010 && year <= 2020) p2Passport.withIssueYear(year); } catch (const std::exception &) { std::cout << value << " is not an integer. [IYR]" << std::endl; } } else if (type == "eyr") { try { uint32_t year = std::stoi(value); p1Passport.withExpirationYear(year); if (year >= 2020 && year <= 2030) p2Passport.withExpirationYear(year); } catch (const std::exception &) { std::cout << value << " is not an integer. [EYR]" << std::endl; } } else if (type == "hgt") { // Account for whether its inches or centimeters std::string unit = value.substr(value.length() - 2); if (unit == "in") { try { uint32_t number = std::stoi(value.substr(0, value.length() - 2)); p1Passport.withHeightInInches(number); if (number >= 59 && number <= 76) p2Passport.withHeightInInches(number); } catch (const std::exception &) { std::cout << value << " is not an integer. [HGT:cm]" << std::endl; } } else if (unit == "cm") { try { uint32_t number = std::stoi(value.substr(0, value.length() - 2)); p1Passport.withHeightInCentimeters(number); if (number >= 150 && number <= 193) p2Passport.withHeightInCentimeters(number); } catch (const std::exception &) { std::cout << value << " is not an integer. [HGT:in]" << std::endl; } } else { // Assume centimeters. NOTE: This case is invalid in Part 2 try { uint32_t number = std::stoi(value); p1Passport.withHeightInCentimeters(number); } catch (const std::exception &) { std::cout << value << " is not an integer. [HGT]" << std::endl; } } } else if (type == "hcl") { p1Passport.withHairColour(value); if (isValidHairColour(value)) p2Passport.withHairColour(value); } else if (type == "ecl") { p1Passport.withEyeColour(value); if (isValidEyeColour(value)) p2Passport.withEyeColour(value); } else if (type == "pid") { try { uint64_t id = std::stoll(value); p1Passport.withPassportId(id); if (value.length() == 9) p2Passport.withPassportId(id); } catch (const std::exception &) { std::cout << value << " is not a 64-bit integer. [PID]" << std::endl; p1Passport.withPassportId(0); // NOTE: This is needed to pass part 1. } } else if (type == "cid") { try { uint64_t id = std::stoll(value); p1Passport.withCountryId(id); } catch (const std::exception &) { std::cout << value << " is not an 64-bit integer. [CID]" << std::endl; } } } } // Check for last p1Passport and P2Passport if (p1Passport.isValid()) p1ValidCount++; if (p2Passport.isValid()) p2ValidCount++; std::cout << "(P1) Valid Passports: " << p1ValidCount << std::endl; std::cout << "(P2) Valid Passports: " << p2ValidCount << std::endl; return 0; }