From 272761b05c06e53b204489502ef4e6aac0bb3d05 Mon Sep 17 00:00:00 2001 From: Andrew Glaze Date: Tue, 2 Jan 2024 10:48:52 -0500 Subject: [PATCH] day16 --- src/day16.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 146 insertions(+) create mode 100644 src/day16.rs diff --git a/src/day16.rs b/src/day16.rs new file mode 100644 index 0000000..90c7199 --- /dev/null +++ b/src/day16.rs @@ -0,0 +1,145 @@ +use std::{ops::RangeInclusive, collections::HashSet}; + +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::Itertools; +use regex::Regex; + +lazy_static!( + static ref RULE_RE: Regex = Regex::new(r"(.*): (\d+)-(\d+) or (\d+)-(\d+)").unwrap(); +); + +#[aoc_generator(day16)] +fn parse(input: &str) -> (Vec<(String, RangeInclusive, RangeInclusive)>, Vec, Vec>) { + let (rules, my_ticket, tickets) = input + .split("\n\n") + .collect_tuple() + .unwrap(); + + let rules = RULE_RE + .captures_iter(rules) + .filter_map(|captures| { + Some(( + captures.get(1)?.as_str().to_string(), + captures.get(2)?.as_str().parse::().ok()?..=captures.get(3)?.as_str().parse::().ok()?, + captures.get(4)?.as_str().parse::().ok()?..=captures.get(5)?.as_str().parse::().ok()?, + )) + }).collect_vec(); + + let my_ticket = my_ticket + .lines() + .last() + .unwrap() + .split(',') + .filter_map(|num| num.parse::().ok()) + .collect_vec(); + + let tickets = tickets + .lines() + .skip(1) + .map(|line| { + line + .split(',') + .filter_map(|num| num.parse::().ok()) + .collect_vec() + }).collect_vec(); + + (rules, my_ticket, tickets) +} + +#[aoc(day16, part1)] +fn part1((rules, _, tickets): &(Vec<(String, RangeInclusive, RangeInclusive)>, Vec, Vec>)) -> usize { + let mut invalid = 0; + for ticket in tickets { + for item in ticket { + if !rules.iter().any(|rule| { + rule.1.contains(item) || rule.2.contains(item) + }) { + invalid += item; + } + } + } + + invalid +} + +#[aoc(day16, part2)] +fn part2((rules, my_ticket, tickets): &(Vec<(String, RangeInclusive, RangeInclusive)>, Vec, Vec>)) -> usize { + let mut tickets = tickets.clone(); + let mut rem = 0; + for (i, ticket) in tickets.clone().iter().enumerate() { + for item in ticket { + if !rules.iter().any(|rule| { + rule.1.contains(item) || rule.2.contains(item) + }) { + tickets.remove(i - rem); + rem += 1; + } + } + } + + let mut possible_rules = get_possible_rules(&tickets, rules); + let mut assigned_rules = [0; 20]; + while let Some(i) = possible_rules.iter().position(|s| s.len() == 1) { + let v = *possible_rules[i].iter().next().unwrap(); + assigned_rules[i] = v; + for s in &mut possible_rules { s.remove(&v); } + } + assigned_rules.iter() + .enumerate() + .filter(|(_,&rule)| rule < 6) + .map(|(i,_)| my_ticket[i]) + .product() +} + +fn get_possible_rules(tickets: &Vec>, rules: &Vec<(String, RangeInclusive, RangeInclusive)>) -> Vec> { + (0..20).map(|i| + (0..20).filter(|&j| + tickets.iter().all(|t| fits_rule(&rules[j], t[i])) + ).collect() + ).collect() +} + +fn fits_rule((_, r1,r2): &(String, RangeInclusive, RangeInclusive), v: usize) -> bool { + r1.contains(&v) || r2.contains(&v) +} + + +#[cfg(test)] +mod tests { + use super::*; + +const EX: &str = r"class: 1-3 or 5-7 +row: 6-11 or 33-44 +seat: 13-40 or 45-50 + +your ticket: +7,1,14 + +nearby tickets: +7,3,47 +40,4,50 +55,2,20 +38,6,12"; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EX)), 71); + } + +const EX2: &str = r"class: 0-1 or 4-19 +row: 0-5 or 8-19 +seat: 0-13 or 16-19 + +your ticket: +11,12,13 + +nearby tickets: +3,9,18 +15,1,5 +5,14,9"; + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EX2)), 1716); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7ac4585..c9ca0f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod day16; mod day15; mod day14; mod day13;