diff --git a/day-16/Cargo.lock b/day-16/Cargo.lock index 202b749..e48194d 100644 --- a/day-16/Cargo.lock +++ b/day-16/Cargo.lock @@ -1,10 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "day-16" version = "0.1.0" dependencies = [ "indoc", + "lazy_static", + "regex", ] [[package]] @@ -30,6 +41,18 @@ dependencies = [ "unindent", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -54,6 +77,24 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" + [[package]] name = "syn" version = "1.0.54" @@ -65,6 +106,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + [[package]] name = "unicode-xid" version = "0.2.1" diff --git a/day-16/Cargo.toml b/day-16/Cargo.toml index beeff78..9599ebe 100644 --- a/day-16/Cargo.toml +++ b/day-16/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" [dependencies] indoc = "0.3" +lazy_static = "1.4" +regex = "1.4" diff --git a/day-16/src/main.rs b/day-16/src/main.rs index bc8bdb9..9d9fd7a 100644 --- a/day-16/src/main.rs +++ b/day-16/src/main.rs @@ -1,23 +1,87 @@ +use std::collections::HashMap; use std::fs; +use std::ops::RangeInclusive; + +use lazy_static::lazy_static; +use regex::Regex; + +type Rules = HashMap, RangeInclusive)>; +type Ticket = Vec; fn main() -> Result<(), Box> { let input = fs::read_to_string("input")?; - let (_, tickets) = parse_tickets(&input)?; + let (rules, _, tickets) = parse_tickets(&input)?; // Part 1 - let invalid = get_invalid_values(&tickets); + let invalid = get_invalid_values(&rules, &tickets); println!("{}", invalid.iter().sum::()); Ok(()) } -fn parse_tickets(input: &str) -> Result<(Vec, Vec>), &str> { - unimplemented!() +fn parse_tickets(input: &str) -> Result<(Rules, Ticket, Vec), String> { + let blocks: Vec<&str> = input.split("\n\n").collect(); + let parse_u32 = |val: &str| { + val.parse::() + .map_err(|e| format!("Invalid number: {}", e)) + }; + + if blocks.len() < 3 { + Err("Input incomplete")?; + } + + let rules = blocks[0] + .lines() + .map(|line| { + lazy_static! { + static ref RULE_RE: Regex = + Regex::new(r"([[:alpha:]]+?): (\d+)-(\d+) or (\d+)-(\d+)") + .expect("Regex should compile"); + } + + let caps = RULE_RE + .captures(line) + .ok_or(format!("Invalid rule line: {}", line))?; + + let name = caps[1].to_string(); + let range1 = parse_u32(&caps[2])?..=parse_u32(&caps[3])?; + let range2 = parse_u32(&caps[4])?..=parse_u32(&caps[5])?; + + Ok((name, (range1, range2))) + }) + .collect::>()?; + + let own_ticket = blocks[1] + .lines() + .skip(1) + .next() + .ok_or("Input incomplete")? + .split(',') + .map(|c| parse_u32(c)) + .collect::>()?; + + let other_tickets = blocks[2] + .lines() + .skip(1) + .map(|line| line.split(',').map(|c| parse_u32(c)).collect()) + .collect::, String>>()?; + + Ok((rules, own_ticket, other_tickets)) } -fn get_invalid_values(tickets: &Vec>) -> Vec { - unimplemented!() +fn get_invalid_values(rules: &Rules, tickets: &Vec) -> Vec { + tickets + .iter() + .flat_map(|ticket| { + ticket.iter().filter(|value| { + !rules + .values() + .any(|(rule1, rule2)| rule1.contains(value) || rule2.contains(value)) + }) + }) + .copied() + .collect() } #[cfg(test)] @@ -44,8 +108,8 @@ mod tests { " ); - let (_, tickets) = parse_tickets(input)?; - let invalid = get_invalid_values(&tickets); + let (rules, _, tickets) = parse_tickets(input)?; + let invalid = get_invalid_values(&rules, &tickets); assert_eq!(invalid.iter().sum::(), 71);