Day 4 solution

[?]
Dec 16, 2020, 11:57 PM
RSO3CMWGWGW73HBTR5LZJR5N4KFWDE7WVHN4RAFDQNOYMHSS2KTAC

Dependencies

Change contents

  • file addition: day4.rs (----------)
    [2.17]
    use std::collections::HashMap;
    use std::env;
    fn extract_keys<S: AsRef<str>>(ln: S) -> HashMap<String,String> {
    let mut collected = HashMap::new();
    for field in ln.as_ref().split_whitespace() {
    let parts: Vec<_> = field.split(':').collect();
    collected.insert(String::from(parts[0]), String::from(parts[1]));
    };
    collected
    }
    const REQUIRED: &[(&str, fn(String) -> bool)] =
    &[
    ("byr", check_byr),
    ("iyr", check_iyr),
    ("eyr", check_eyr),
    ("hgt", check_hgt),
    ("hcl", check_hcl),
    ("ecl", check_ecl),
    ("pid", check_pid)
    ];
    fn check_byr(ln: String) -> bool {
    ln.len() == 4 && match ln.parse::<usize>() {
    Ok(year) => year >= 1920 && year <= 2002,
    Err(_) => false,
    }
    }
    fn check_iyr(ln: String) -> bool {
    ln.len() == 4 && match ln.parse::<usize>() {
    Ok(year) => year >= 2010 && year <= 2020,
    Err(_) => false,
    }
    }
    fn check_eyr(ln: String) -> bool {
    ln.len() == 4 && match ln.parse::<usize>() {
    Ok(year) => year >= 2020 && year <= 2030,
    Err(_) => false,
    }
    }
    fn check_hgt(ln: String) -> bool {
    match ln.find(|c: char| !c.is_digit(10)) {
    Some(sep) => {
    let (num, unit) = ln.split_at(sep);
    match num.parse::<isize>() {
    Ok(num) => {
    if unit == "in" {
    num >= 59 && num <= 76
    } else if unit == "cm" {
    num >= 150 && num <= 193
    } else {
    false
    }
    },
    Err(_) => false,
    }
    },
    None => false,
    }
    }
    fn check_hcl(ln: String) -> bool {
    if ln.len() != 7 {
    return false;
    }
    let mut ci = ln.chars();
    if ci.next() != Some('#') {
    return false;
    }
    for c in ci {
    if !c.is_digit(16) {
    return false;
    }
    }
    true
    }
    fn check_ecl(ln: String) -> bool {
    for ex in ["amb","blu","brn","gry","grn","hzl","oth"].iter() {
    if ln == *ex {
    return true;
    }
    }
    false
    }
    fn check_pid(ln: String) -> bool {
    ln.len() == 9 && ln.chars().all(|c| c.is_digit(10))
    }
    #[derive(Clone,Copy,Debug)]
    enum Document {
    Passport,
    NorthPole,
    Invalid
    }
    struct DelimByEmpty<I> {
    inner: I,
    }
    impl<I> DelimByEmpty<I> {
    fn new(inner: I) -> Self {
    DelimByEmpty { inner: inner }
    }
    }
    impl<I: Iterator<Item=HashMap<Q,R>>, Q: Clone + std::cmp::Eq + std::hash::Hash, R: Clone> Iterator for DelimByEmpty<I> {
    type Item = HashMap<Q,R>;
    fn next(&mut self) -> Option<Self::Item> {
    let mut result = HashMap::new();
    loop {
    match self.inner.next() {
    None => {
    if result.is_empty() {
    return None;
    } else {
    return Some(result);
    }
    },
    Some(line) => {
    if line.is_empty() {
    return Some(result);
    } else {
    for (key,val) in line.iter() {
    result.insert(key.clone(), val.clone());
    }
    }
    },
    }
    }
    }
    }
    fn validate_line(found: HashMap<String,String>, version: usize) -> Document {
    for (key,validator) in REQUIRED.iter() {
    match found.get(&String::from(*key)) {
    None => { return Document::Invalid; },
    Some(value) => {
    if version == 2 && !validator(value.clone()) {
    return Document::Invalid;
    }
    },
    }
    };
    if found.contains_key(&String::from("cid")) {
    Document::Passport
    } else {
    Document::NorthPole
    }
    }
    fn main() {
    use std::io::BufRead;
    let args: Vec<_> = env::args().collect();
    let version: usize = args[2].parse().unwrap();
    let result: i32 = DelimByEmpty::new(
    std::io::BufReader::new(std::fs::File::open(&args[1]).unwrap())
    .lines()
    .map(Result::unwrap)
    .map(extract_keys)
    ).map(|d| validate_line(d, version))
    .map(|t| match t {
    Document::Invalid => 0,
    _ => 1,
    })
    .sum();
    println!("{:}",result);
    }