use regex::Regex;
use std::collections::HashMap;
use std::io::{self, Read};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn main() -> Result<()> {
let mut input = String::new();
io::stdin().read_to_string(&mut input)?;
let parsed: Vec<HashMap<String, String>> = parse(input);
part1(&parsed);
part2(&parsed);
Ok(())
}
fn part1(input: &Vec<HashMap<String, String>>) {
let mut valid = 0;
let all_key = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"];
for passport in input {
if all_key.iter().all(|&key| passport.contains_key(key)) {
valid += 1;
}
}
println!("{}", valid);
}
fn part2(input: &Vec<HashMap<String, String>>) {
let mut valid = 0;
let all_key = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"];
for passport in input {
let mut local = 0;
for key in &all_key {
if !passport.contains_key(*key) {
break;
}
if validate(key, passport.get(*key).unwrap()) {
local += 1;
}
}
if local == 7 {
valid += 1;
}
}
println!("{}", valid);
}
fn validate(key: &str, value: &String) -> bool {
match key {
"byr" => {
let year = value.parse::<u32>().unwrap();
if year >= 1920 && year <= 2002 {
true
} else {
false
}
}
"iyr" => {
let year = value.parse::<u32>().unwrap();
if year >= 2010 && year <= 2020 {
true
} else {
false
}
}
"eyr" => {
let year = value.parse::<u32>().unwrap();
if year >= 2020 && year <= 2030 {
true
} else {
false
}
}
"hgt" => {
let is_cm = value.contains("cm");
if is_cm {
let value = value.replace("cm", "").parse::<u32>().unwrap();
if value >= 150 && value <= 193 {
true
} else {
false
}
} else {
let value = value.replace("in", "").parse::<u32>().unwrap();
if value >= 59 && value <= 76 {
true
} else {
false
}
}
}
"hcl" => {
let re = Regex::new(r"#[a-f0-9]{6}").unwrap();
if re.is_match(value) {
true
} else {
false
}
}
"ecl" => {
let valid = ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"];
if valid.iter().any(|key| key == value) {
true
} else {
false
}
}
"pid" => {
let re = Regex::new(r"^[0-9]{9}$").unwrap();
if re.is_match(value) {
true
} else {
false
}
}
_ => false,
}
}
fn parse(input: String) -> Vec<HashMap<String, String>> {
let mut vec: Vec<HashMap<String, String>> = Vec::new();
let parsed = input.trim().split("\n\n");
for para in parsed {
let mut map: HashMap<String, String> = HashMap::new();
let para_intermidiate = para.replace("\n", " ");
let para_parsed = para_intermidiate.split(" ");
for part in para_parsed {
let mut split = part.split(":");
let key = split.next().unwrap();
let value = split.next().unwrap();
map.insert(key.into(), value.into());
}
vec.push(map);
}
vec
}