This commit is contained in:
Andrew Glaze 2024-01-02 10:48:52 -05:00
parent f9d58356cd
commit 272761b05c
2 changed files with 146 additions and 0 deletions

145
src/day16.rs Normal file
View File

@ -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<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>) {
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::<usize>().ok()?..=captures.get(3)?.as_str().parse::<usize>().ok()?,
captures.get(4)?.as_str().parse::<usize>().ok()?..=captures.get(5)?.as_str().parse::<usize>().ok()?,
))
}).collect_vec();
let my_ticket = my_ticket
.lines()
.last()
.unwrap()
.split(',')
.filter_map(|num| num.parse::<usize>().ok())
.collect_vec();
let tickets = tickets
.lines()
.skip(1)
.map(|line| {
line
.split(',')
.filter_map(|num| num.parse::<usize>().ok())
.collect_vec()
}).collect_vec();
(rules, my_ticket, tickets)
}
#[aoc(day16, part1)]
fn part1((rules, _, tickets): &(Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> 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<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> 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<Vec<usize>>, rules: &Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>) -> Vec<HashSet<usize>> {
(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<usize>, RangeInclusive<usize>), 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);
}
}

View File

@ -1,3 +1,4 @@
mod day16;
mod day15;
mod day14;
mod day13;