From 1271eb0e98d3032fd65785830d99b4a6977c0a73 Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Wed, 16 Dec 2020 13:40:21 +0100 Subject: [PATCH] rust(day16): Implement day 16 --- rust/src/main.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/rust/src/main.rs b/rust/src/main.rs index d67e7c0..1b1c936 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -518,6 +518,153 @@ mod day15 { } } +mod day16 { + use std::collections::BTreeSet; + use std::fmt; + use std::time::{Duration, Instant}; + + type Ticket = Vec; + + #[derive(PartialEq, Eq, Hash)] + struct Range { + from: usize, + to: usize, + } + + impl fmt::Debug for Range { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{} - {}", self.from, self.to)) + } + } + impl Range { + fn from(s: &str) -> Self { + let mut range = s.split("-"); + Self { + from: range.next().unwrap().parse().unwrap(), + to: range.next().unwrap().parse().unwrap(), + } + } + } + + #[derive(Debug, PartialEq, Eq, Hash)] + struct Rule { + name: String, + ranges: (Range, Range), + } + + pub fn run(print: bool) -> Duration { + let input = std::fs::read_to_string("../inputs/16").unwrap(); + let instant = Instant::now(); + + let mut lines = input.lines(); + let mut rules = Vec::new(); + while let Some(line) = lines.next() { + let mut colon_split = line.split(": "); + let name = colon_split.next().unwrap().to_string(); + if name.is_empty() { + break; + } + + let mut ranges = colon_split.next().unwrap().split(" or "); + + rules.push(Rule { + name, + ranges: ( + Range::from(ranges.next().unwrap()), + Range::from(ranges.next().unwrap()), + ), + }); + } + + lines.next(); // "your ticket:" + + let your_ticket: Ticket = lines + .next() + .unwrap() + .split(",") + .flat_map(str::parse) + .collect(); + + lines.next(); // "" + lines.next(); // "nearby tickets:" + + let mut nearby_tickets: Vec = Vec::new(); + while let Some(line) = lines.next() { + nearby_tickets.push(line.split(",").flat_map(str::parse).collect()); + } + + let mut part1 = 0; + let mut valid_tickets = Vec::new(); + for ticket in &nearby_tickets { + let mut valid = true; + for field in ticket { + let rule = rules.iter().find(|rule| { + (field >= &rule.ranges.0.from && field <= &rule.ranges.0.to) + || (field >= &rule.ranges.1.from && field <= &rule.ranges.1.to) + }); + if rule.is_none() { + valid = false; + part1 += field; + } + } + if valid { + valid_tickets.push(ticket); + } + } + + if print { + dbg!(part1); + } + + let mut field_possibilities: Vec<_> = (0..your_ticket.len()) + .map(|_| (0..rules.len()).collect::>()) + .collect(); + + for ticket in valid_tickets { + for (field, possibilities) in ticket.iter().zip(field_possibilities.iter_mut()) { + for rule_i in possibilities.clone().iter() { + let rule = &rules[*rule_i]; + if !((field >= &rule.ranges.0.from && field <= &rule.ranges.0.to) + || (field >= &rule.ranges.1.from && field <= &rule.ranges.1.to)) + { + possibilities.remove(&rule_i); + } + } + } + } + + let mut part2 = 1; + loop { + let field_possibility = field_possibilities + .iter() + .enumerate() + .find(|(_, fp)| fp.len() == 1); + + let (i, possibility) = match field_possibility { + Some((i, v)) => (i, *v.iter().next().take().unwrap()), + None => break, + }; + + for fp in field_possibilities.iter_mut() { + fp.remove(&possibility); + } + + let rule = &rules[possibility].name; + //println!("{} is {}", rule, your_ticket[i]); + + if rule.starts_with("departure") { + part2 *= your_ticket[i]; + } + } + + if print { + dbg!(part2); + } + + instant.elapsed() + } +} + fn main() { let days = [ day01::run, @@ -535,6 +682,7 @@ fn main() { day13::run, day14::run, day15::run, + day16::run, ]; if let Some(day) = std::env::args().nth(1) {