rust(day16): Implement day 16
This commit is contained in:
parent
87fdcce197
commit
1271eb0e98
1 changed files with 148 additions and 0 deletions
148
rust/src/main.rs
148
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<usize>;
|
||||||
|
|
||||||
|
#[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<Ticket> = 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::<BTreeSet<_>>())
|
||||||
|
.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() {
|
fn main() {
|
||||||
let days = [
|
let days = [
|
||||||
day01::run,
|
day01::run,
|
||||||
|
@ -535,6 +682,7 @@ fn main() {
|
||||||
day13::run,
|
day13::run,
|
||||||
day14::run,
|
day14::run,
|
||||||
day15::run,
|
day15::run,
|
||||||
|
day16::run,
|
||||||
];
|
];
|
||||||
|
|
||||||
if let Some(day) = std::env::args().nth(1) {
|
if let Some(day) = std::env::args().nth(1) {
|
||||||
|
|
Loading…
Reference in a new issue