day16
This commit is contained in:
parent
f9d58356cd
commit
272761b05c
145
src/day16.rs
Normal file
145
src/day16.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod day16;
|
||||
mod day15;
|
||||
mod day14;
|
||||
mod day13;
|
||||
|
Loading…
Reference in New Issue
Block a user