rewrite 2023/19 for part 2
This commit is contained in:
parent
36ca0e4fe8
commit
71f395b2ad
|
@ -1,30 +1,28 @@
|
||||||
#![feature(test)]
|
#![feature(test, iter_array_chunks)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use self::Result::*;
|
use self::Result::*;
|
||||||
use aoc2023::{boilerplate, common::*};
|
use aoc2023::{boilerplate, common::*};
|
||||||
use fnv::FnvHashMap as HashMap;
|
use fnv::FnvHashMap as HashMap;
|
||||||
use itertools::Itertools;
|
|
||||||
use tuple_map::TupleMap4;
|
|
||||||
|
|
||||||
const DAY: usize = 19;
|
const DAY: usize = 19;
|
||||||
type I = u32;
|
type I = u32;
|
||||||
type Rule<'a> = Box<dyn Fn(&Part) -> Result<'a> + 'a>;
|
type Rule<'a> = (Comp, Result<'a>);
|
||||||
type Parsed<'a> = (HashMap<&'a str, Vec<Rule<'a>>>, Vec<Part>);
|
type Parsed<'a> = (HashMap<&'a str, Vec<Rule<'a>>>, Vec<Part>);
|
||||||
|
const LIMIT: I = 4000;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
enum Result<'a> {
|
enum Result<'a> {
|
||||||
Accepted,
|
Accepted,
|
||||||
Rejected,
|
Rejected,
|
||||||
Next,
|
|
||||||
Jump(&'a str),
|
Jump(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
type Part = [I; 4];
|
||||||
struct Part {
|
|
||||||
x: I,
|
enum Comp {
|
||||||
m: I,
|
GT(usize, I),
|
||||||
a: I,
|
LT(usize, I),
|
||||||
s: I,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_target(t: &str) -> Result<'_> {
|
fn parse_target(t: &str) -> Result<'_> {
|
||||||
|
@ -37,35 +35,30 @@ fn parse_target(t: &str) -> Result<'_> {
|
||||||
|
|
||||||
fn parse_rule<'a>(r: &'a str) -> Rule {
|
fn parse_rule<'a>(r: &'a str) -> Rule {
|
||||||
match r.split_once(':') {
|
match r.split_once(':') {
|
||||||
None => {
|
None => (Comp::None, parse_target(r)),
|
||||||
let target = parse_target(r);
|
|
||||||
Box::new(move |_| target)
|
|
||||||
}
|
|
||||||
Some((condition, target)) => {
|
Some((condition, target)) => {
|
||||||
let target = parse_target(target);
|
|
||||||
let value = parse_num(&condition[2..]);
|
let value = parse_num(&condition[2..]);
|
||||||
match &condition[0..2] {
|
let idx = match condition.as_bytes()[0] {
|
||||||
"x<" => Box::new(move |p| if p.x < value { target } else { Next }),
|
b'x' => 0,
|
||||||
"x>" => Box::new(move |p| if p.x > value { target } else { Next }),
|
b'm' => 1,
|
||||||
"m<" => Box::new(move |p| if p.m < value { target } else { Next }),
|
b'a' => 2,
|
||||||
"m>" => Box::new(move |p| if p.m > value { target } else { Next }),
|
b's' => 3,
|
||||||
"a<" => Box::new(move |p| if p.a < value { target } else { Next }),
|
|
||||||
"a>" => Box::new(move |p| if p.a > value { target } else { Next }),
|
|
||||||
"s<" => Box::new(move |p| if p.s < value { target } else { Next }),
|
|
||||||
"s>" => Box::new(move |p| if p.s > value { target } else { Next }),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
};
|
||||||
|
let comp = match condition.as_bytes()[1] {
|
||||||
|
b'<' => Comp::LT(idx, value),
|
||||||
|
b'>' => Comp::GT(idx, value),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
(comp, parse_target(target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input(raw: &str) -> Parsed {
|
fn parse_input(raw: &str) -> Parsed {
|
||||||
let (rules, parts) = raw.split_once("\n\n").unwrap();
|
let (rules, parts) = raw.split_once("\n\n").unwrap();
|
||||||
let parts = parts
|
let parts =
|
||||||
.lines()
|
parts.lines().map(|l| l[1..].trim_matches('}').split(',').array_chunks().next().unwrap().map(|s| parse_num(&s[2..]))).collect();
|
||||||
.map(|l| l[1..].trim_matches('}').split(',').collect_tuple::<(_, _, _, _)>().unwrap().map(|s| parse_num(&s[2..])))
|
|
||||||
.map(|(x, m, a, s)| Part { x, m, a, s })
|
|
||||||
.collect();
|
|
||||||
let rules = rules
|
let rules = rules
|
||||||
.lines()
|
.lines()
|
||||||
.map(|line| line.trim_end_matches('}').split_once('{').unwrap())
|
.map(|line| line.trim_end_matches('}').split_once('{').unwrap())
|
||||||
|
@ -74,11 +67,13 @@ fn parse_input(raw: &str) -> Parsed {
|
||||||
(rules, parts)
|
(rules, parts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve<'a>(part: &Part, rules: &'a [Rule]) -> Result<'a> {
|
fn resolve<'a>(part: &Part, rules: &'a [Rule]) -> &'a Result<'a> {
|
||||||
for rule in rules {
|
for (comp, res) in rules {
|
||||||
match rule(part) {
|
match comp {
|
||||||
Next => continue,
|
Comp::None => return res,
|
||||||
res => return res,
|
&Comp::LT(idx, val) if part[idx] < val => return res,
|
||||||
|
&Comp::GT(idx, val) if part[idx] > val => return res,
|
||||||
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -92,9 +87,8 @@ fn part1((rules, parts): &Parsed) -> I {
|
||||||
loop {
|
loop {
|
||||||
match resolve(p, &rule) {
|
match resolve(p, &rule) {
|
||||||
Jump(r) => rule = rules.get(r).unwrap(),
|
Jump(r) => rule = rules.get(r).unwrap(),
|
||||||
Accepted => return p.x + p.m + p.a + p.s,
|
Accepted => return p.iter().sum(),
|
||||||
Rejected => return 0,
|
Rejected => return 0,
|
||||||
Next => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user