heh
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs236
1 files changed, 182 insertions, 54 deletions
diff --git a/src/main.rs b/src/main.rs
index 3b441c2..1fa5884 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,70 +18,198 @@ extern crate test;
pub mod util;
pub use util::prelude::*;
-pub fn p1(i: &str) -> u16 {
- let mut y = 0i32;
- let mut a = 0i32;
- let mut b = 0u16;
- let mut i = i.as_bytes();
- loop {
- let d = unsafe {
- rint::<_, Dir>(match i.by() {
- Ok(x) => x,
- Err(_) => break,
- })
- };
- let c = match unsafe { i.rd::<3>().unwrap_unchecked() } {
- [_, b, b' '] => {
- i = C! { &i[10..] };
- b - b'0'
- }
- [_, a, b] => {
- _ = i.read(&mut [0; 11]);
- // i = C! { &i[11..] };
- (a - b'0') * 10 + (b - b'0')
- }
- };
- b += c as u16;
- match d {
- Dir::N => y += c as i32,
- Dir::E => a += c as i32 * y,
- Dir::S => y -= c as i32,
- Dir::W => a -= c as i32 * y,
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum When {
+ // m>N
+ Gt(What, u32),
+ Lt(What, u32),
+ Always,
+}
+
+impl When {
+ fn accepts(self) -> Option<What> {
+ match self {
+ Self::Gt(y, _) | Self::Lt(y, _) => Some(y),
+ Self::Always => None,
+ }
+ }
+
+ fn considers(self, w: What) -> bool {
+ matches!(self, Self::Gt(y, _) | Self::Lt(y, _) if w == y) | (self == Self::Always)
+ }
+
+ fn test(self, w: u32) -> bool {
+ match self {
+ Self::Gt(_, x) => w > x,
+ Self::Lt(_, x) => w < x,
+ Self::Always => true,
}
}
+}
- // use shoelace formula to get the area, then use picks formula to count the number of inner points
- a.abs() as u16 + (1 + b / 2)
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+enum Then<'a> {
+ Go(&'a [u8]),
+ Accept = b'A',
+ Reject = b'R',
}
-pub fn p2(i: &str) -> u64 {
- let mut y = 0;
- let mut a = 0;
- let mut b = 0;
- let mut i = i.as_bytes();
- loop {
- let Ok(_) = i.by() else { break };
- i.skip(2);
- if unsafe { i.by().unwrap_unchecked() == b' ' } {
- i.skip(2);
+impl<'a> Then<'a> {
+ pub fn from(x: u8) -> Self {
+ mat!(x {
+ b'A' => Self::Accept,
+ b'R' => Self::Reject,
+ })
+ }
+
+ pub fn from2(x: &'a [u8]) -> Self {
+ if let &[x] = x {
+ Self::from(x)
} else {
- i.skip(3);
+ Self::Go(x)
}
- let dat = unsafe { i.rd::<6>().unwrap_unchecked() };
- _ = i.read(&mut [0; 2]);
- let c = 読む::hex5(dat[0..5].try_into().unwrap());
- const A: [i64; 4] = [1, 0, -1, 0];
- const Y: [i64; 4] = [0, -1, 0, 1];
- let d = dat[5] - b'0';
- a += C! { A[d.nat()] } * c as i64 * y;
- y += C! { Y[d.nat()] } * c as i64;
- b += c as u64;
}
- a.abs() as u64 + (1 + b / 2)
}
-pub fn run(i: &str) -> impl Display {
- p2(i)
+#[repr(u8)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+enum What {
+ x = b'x',
+ m = b'm',
+ a = b'a',
+ s = b's',
+}
+
+impl What {
+ pub fn select(self, [x, m, a, s]: [u32; 4]) -> u32 {
+ match self {
+ What::x => x,
+ What::m => m,
+ What::a => a,
+ What::s => s,
+ }
+ }
+
+ pub fn from(x: u8) -> Self {
+ unsafe { rint(x) }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+struct Rule<'a> {
+ condition: When,
+ then: Then<'a>,
+}
+
+impl<'a> Rule<'a> {
+ fn takes(self) -> Option<What> {
+ self.condition.accepts()
+ }
+
+ fn consider(self, x: u32) -> Option<Then<'a>> {
+ self.condition.test(x).then_some(self.then)
+ }
+}
+
+struct Workflow<'a> {
+ name: &'a [u8],
+ rules: Box<[Rule<'a>]>,
+}
+
+impl<'a> Workflow<'a> {
+ fn test(&self, x: [u32; 4]) -> Option<Then> {
+ for rule in &*self.rules {
+ if let Some(x) = rule.takes().map(|y| y.select(x)) {
+ if let Some(x) = rule.consider(x) {
+ return Some(x);
+ }
+ } else {
+ return Some(rule.then);
+ }
+ }
+ dang!()
+ }
+
+ fn new(name: &'a [u8], from: impl Iterator<Item = &'a [u8]>) -> Self {
+ let mut rules = vec![];
+ for rule in from {
+ if let &[b] = rule {
+ rules.push(Rule {
+ condition: When::Always,
+ then: Then::from(b),
+ })
+ } else {
+ let Some((cond, then)) = rule.split_once(|&x| x == b':') else {
+ rules.push(Rule {
+ condition: When::Always,
+ then: Then::from2(rule),
+ });
+ continue;
+ };
+
+ if let Some((&[x], y)) = cond.split_once(|&x| x == b'<') {
+ rules.push(Rule {
+ condition: When::Lt(What::from(x), y.λ::<u32>()),
+ then: Then::from2(then),
+ })
+ } else if let Some((&[x], y)) = cond.split_once(|&x| x == b'>') {
+ rules.push(Rule {
+ condition: When::Gt(What::from(x), y.λ::<u32>()),
+ then: Then::from2(then),
+ })
+ } else {
+ shucks!()
+ }
+ }
+ }
+ Self {
+ rules: rules.into_boxed_slice(),
+ name,
+ }
+ }
+}
+
+pub fn run(i: &str) -> u32 {
+ let mut workflows = vec![];
+ let mut first = None;
+ let mut i = i.行();
+ for x in i.by_ref() {
+ if x == b"" {
+ break;
+ }
+ let (work, rules) = x.μ('{').mr(|x| x.μ0('}').split(|&x| x == b','));
+ let flow = Workflow::new(work, rules);
+ if work == b"in" {
+ first = Some(flow)
+ } else {
+ workflows.push(flow);
+ }
+ }
+ let first = first.unwrap();
+ let mut acc = 0;
+ for x in i {
+ let mut w = &first;
+ let a = x
+ .between('{', '}')
+ .split(|&x| x == b',')
+ .map(|x| x.μ1('=').λ())
+ .Ν();
+ loop {
+ if let Some(x) = w.test(a) {
+ match x {
+ Then::Accept => {
+ acc += a.iter().copied().sum::<u32>();
+ break;
+ }
+ Then::Go(y) => w = workflows.iter().find(|x| x.name == y).α(),
+ Then::Reject => break,
+ }
+ }
+ }
+ }
+ acc
}
fn main() {