|
|
@ -0,0 +1,88 @@ |
|
|
|
|
|
#include <iterator>
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
#include <cctype>
|
|
|
|
|
|
|
|
|
|
|
|
#include "solutions.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace std; |
|
|
|
|
|
|
|
|
|
|
|
bool is_digit(char c) { |
|
|
|
|
|
return isdigit((int) c); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool is_hex_digit(char c) { |
|
|
|
|
|
return isdigit((int) c) || (c >= 'a' && c <= 'f'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pair<string, string> solve4(istream& input) { |
|
|
|
|
|
cerr << boolalpha; |
|
|
|
|
|
stringstream current_passport{string()}; |
|
|
|
|
|
uint64_t part1 = 0, part2 = 0; |
|
|
|
|
|
unordered_map<string, function<bool(string&)>> valid_funcs; |
|
|
|
|
|
valid_funcs["byr"] = [](string &value) { |
|
|
|
|
|
int int_value = stoi(value); |
|
|
|
|
|
return value.length() == 4 && all_of(value.begin(), value.end(), is_digit) && int_value >= 1920 && int_value <= 2002; |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["iyr"] = [](string &value) { |
|
|
|
|
|
int int_value = stoi(value); |
|
|
|
|
|
return value.length() == 4 && all_of(value.begin(), value.end(), is_digit) && int_value >= 2010 && int_value <= 2020; |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["eyr"] = [](string &value) { |
|
|
|
|
|
int int_value = stoi(value); |
|
|
|
|
|
return value.length() == 4 && all_of(value.begin(), value.end(), is_digit) && int_value >= 2020 && int_value <= 2030; |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["hgt"] = [](string &value) { |
|
|
|
|
|
int int_value = stoi(value); |
|
|
|
|
|
return (value.length() == to_string(int_value).length() + 2) && ( |
|
|
|
|
|
(value.ends_with("in") && int_value >= 59 && int_value <= 76) || |
|
|
|
|
|
(value.ends_with("cm") && int_value >= 150 && int_value <= 193) |
|
|
|
|
|
); |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["hcl"] = [](string &value) { |
|
|
|
|
|
auto it = value.begin(); |
|
|
|
|
|
return value.length() == 7 && *it == '#' && all_of(next(it), value.end(), is_hex_digit); |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["ecl"] = [](string &value) { |
|
|
|
|
|
unordered_set<string> valid_eye_colors = { { |
|
|
|
|
|
"amb"s, "blu"s, "brn"s, "gry"s, "grn"s, "hzl"s, "oth"s |
|
|
|
|
|
} }; |
|
|
|
|
|
return valid_eye_colors.contains(value); |
|
|
|
|
|
}; |
|
|
|
|
|
valid_funcs["pid"] = [](string &value) { |
|
|
|
|
|
return value.length() == 9 && all_of(value.begin(), value.end(), is_digit); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
for (string line; getline(input, line); ) { |
|
|
|
|
|
if (!line.empty()) { // append to existing passport
|
|
|
|
|
|
if (!current_passport.eof()) { |
|
|
|
|
|
current_passport << ' '; |
|
|
|
|
|
} |
|
|
|
|
|
current_passport << line; |
|
|
|
|
|
} |
|
|
|
|
|
if (line.empty() || input.peek() == EOF) { // no input; parse current passport
|
|
|
|
|
|
unordered_set<string> mandatory_fields = { |
|
|
|
|
|
{ "byr"s, "iyr"s, "eyr"s, "hgt"s, "hcl"s, "ecl"s, "pid"s} |
|
|
|
|
|
}; |
|
|
|
|
|
bool all_fields_valid = true; |
|
|
|
|
|
for (string entry; getline(current_passport, entry, ' '); ) { |
|
|
|
|
|
auto field_delim_pos = entry.find(':'); |
|
|
|
|
|
if (field_delim_pos != string::npos) { |
|
|
|
|
|
string field_name = entry.substr(0, field_delim_pos); |
|
|
|
|
|
string field_value = entry.substr(field_delim_pos+1); |
|
|
|
|
|
mandatory_fields.erase(field_name); |
|
|
|
|
|
if (valid_funcs.contains(field_name)) { |
|
|
|
|
|
all_fields_valid = all_fields_valid && valid_funcs[field_name](field_value); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
current_passport.clear(); |
|
|
|
|
|
part1 += (uint64_t) mandatory_fields.empty(); |
|
|
|
|
|
part2 += (uint64_t) (mandatory_fields.empty() && all_fields_valid); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return pair(to_string(part1), to_string(part2)); |
|
|
|
|
|
} |