This repository has been archived on 2021-06-30. You can view files and clone it, but cannot push or open issues or pull requests.
aoc2020/day_4/main.cpp

225 lines
7.6 KiB
C++
Raw Normal View History

#include <iostream>
#include <fstream>
#include <vector>
#include <optional>
#include <variant>
class Passport {
std::optional<uint32_t> birthYear;
std::optional<uint32_t> issueYear;
std::optional<uint32_t> expireYear;
std::optional<float> height;
std::optional<std::string> hairColour;
std::optional<std::string> eyeColour;
std::optional<uint64_t> passportId;
std::optional<uint64_t> 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<std::string> getProperties(std::string &line) {
std::vector<std::string> 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<Passport> 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<std::string> 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;
}