heh
2016/11 (!)
| -rw-r--r-- | src/inp.txt | 34 | ||||
| -rw-r--r-- | src/main.rs | 151 | ||||
| -rw-r--r-- | src/util.rs | 87 |
3 files changed, 197 insertions, 75 deletions
diff --git a/src/inp.txt b/src/inp.txt index 3907038..bade1ea 100644 --- a/src/inp.txt +++ b/src/inp.txt @@ -1,30 +1,4 @@ -cpy a d -cpy 11 c -cpy 231 b -inc d -dec b -jnz b -2 -dec c -jnz c -5 -cpy d a -jnz 0 0 -cpy a b -cpy 0 a -cpy 2 c -jnz b 2 -jnz 1 6 -dec b -dec c -jnz c -4 -inc a -jnz 1 -7 -cpy 2 b -jnz c 2 -jnz 1 4 -dec b -dec c -jnz 1 -4 -jnz 0 0 -out b -jnz a -19 -jnz 1 -21 +The first floor contains a 1 generator, a 2 generator, a 2-compatible microchip, a 3 generator, a 4 generator, a 5 generator, a 5-compatible microchip, a 6 generator, a 6-compatible microchip, a 4-compatible microchip, a 7 generator, and a 7-compatible microchip. +The second floor contains a 1-compatible microchip and a 3-compatible microchip. +The third floor contains nothing relevant. +The fourth floor contains nothing relevant. diff --git a/src/main.rs b/src/main.rs index 34442a7..bfa424a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,11 +17,15 @@ step_trait, cmp_minmax, custom_inner_attributes, + pattern_types, + pattern_type_macro, extend_one, slice_as_array, impl_trait_in_bindings, coroutines, stmt_expr_attributes, + pattern_type_range_trait, + const_trait_impl, coroutine_trait, iter_partition_in_place, slice_swap_unchecked, @@ -54,8 +58,9 @@ use regex::bytes::Regex; use rustc_hash::FxBuildHasher; use std::{ cmp::{Reverse, minmax}, + hash::Hash, mem::take, - ops::Coroutine, + ops::{Coroutine, Deref}, pin::Pin, simd::prelude::*, }; @@ -65,51 +70,125 @@ pub use util::prelude::*; #[allow(warnings)] type u32x3 = Simd<u32, 3>; -fn run(code: &[Vec<&[u8]>], a: i32) -> impl Coroutine<Yield = i32, Return = ()> { - let mut ptr = 0i32; - #[coroutine] - move || { - let mut regis = - HashMap::<&[u8], i32>::from_iter([(&b"a"[..], a), (b"b", 0), (b"c", 0), (b"d", 0)]); - while let Some(i) = code.get(ptr as usize).cloned() { - let p = |j: usize| i[j].str().parse::<i32>().unwrap_or_else(|_| regis[i[j]]); - - match i[0] { - b"out" => drop(yield regis[i[1]]), - b"cpy" => *regis.get_mut(i[2]).unwrap() = p(1), - b"inc" => *regis.get_mut(i[1]).unwrap() += 1, - b"dec" => *regis.get_mut(i[1]).unwrap() -= 1, - b"jnz" if p(1) != 0 => { - ptr += p(2); - - continue; - } +impl Debug for Item { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {:?}", self.name.get(), self.kind) + } +} - _ => {} - } +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] - ptr += 1; - } +struct Item { + name: identifier, + kind: ItemK, +} +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +enum identifier { + u1, + u2, + u3, + u4, + u5, + u6, + u7, + u8, + u9, +} +impl identifier { + fn get(self) -> u8 { + self as u8 } } - +impl PartialEq for identifier { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} +impl Eq for identifier {} +impl PartialOrd for identifier { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.get().partial_cmp(&other.get()) + } +} +impl Ord for identifier { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.get().cmp(&other.get()) + } +} +impl Hash for identifier { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.get().hash(state) + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum ItemK { + Chip, + Gen, +} +use ItemK::*; #[unsafe(no_mangle)] #[implicit_fn::implicit_fn] -pub unsafe fn p1(x: &[u8; ISIZE]) -> impl Display { - let x = x - .行() - .map(|x| x.μₙ(b' ').collect::<Vec<_>>()) - .collect::<Vec<_>>(); - for n in 0.. { - dbg!(n); - std::iter::from_coroutine(run(&x, n)).eq([0, 1].iter().copied().cycle()); - } +pub unsafe fn p1(x: &'static [u8; ISIZE]) -> impl Debug { + let re = Regex::new(r"([0-9a-z]+) generator").unwrap(); + let rechip = Regex::new(r"([0-9a-z]+)-compatible microchip").unwrap(); + let mut floors = vec![vec![]; 4]; + x.行().zip(&mut floors).for_each(|(x, to)| { + to.extend(re.captures_iter(x).map(|x| Item { + name: transmute(x.get(1).unwrap().as_bytes()[0] - b'0'), + kind: Gen, + })); + to.extend(rechip.captures_iter(x).map(|x| Item { + name: transmute(x.get(1).unwrap().as_bytes()[0] - b'0'), + kind: Chip, + })); + }); + // if a chip is ever left in the same area as another RTG, and it's not connected to its own RTG, the chip will be fried. + fn not_fried(floor: impl Iterator<Item = Item> + Clone) -> bool { + floor.clone().all(_.kind == Chip) + || floor + .clone() + .filter(_.kind == Chip) // every chip + .all(|x| floor.clone().filter(_.kind == Gen).any(_.name == x.name)) // is connected + }; - 0 + util::steps_astar( + (0, floors), + |(e, floor)| { + [(e < 3).then(|| e + 1), (e > 0).then(|| e - 1)] + .into_iter() + .flatten() + .flat_map(move |v| { + floor[e] + .clone() + .into_iter() + .ι() + .tuple_combinations() + .map(|(a, b)| vec![a, b]) + .chain(floor[e].clone().into_iter().ι().map(|a| vec![a])) + .map({ + let floor = floor.clone(); + move |mut x| { + let mut floor = floor.clone(); + floor[v].extend(x.iter().map(|x| x.0)); + x.sort_by_key(|x| x.1); + x.iter().rev().map(|(_, i)| floor[e].swap_remove(*i)).θ(); + floor[v].sort(); + floor[e].sort(); + (v, floor) + } + }) + }) + .filter(|(e, floor)| not_fried(floor[*e].iter().copied())) + .map(|n| (n, 1)) + }, + |x| -(x.1[3].len() as i16), + |(_, f)| f[0..3].iter().all(_.is_empty()), + ) } const ISIZE: usize = include_bytes!("inp.txt").len(); fn main() { - unsafe { println!("{}", p1(include_bytes!("inp.txt"))) }; + unsafe { println!("{:?}", p1(include_bytes!("inp.txt"))) }; } #[bench] diff --git a/src/util.rs b/src/util.rs index 9613bf1..0afefa4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -42,10 +42,11 @@ pub mod prelude { collections::{VecDeque, hash_map::Entry}, fmt::{Debug, Display}, hint::black_box as boxd, + intrinsics::transmute_unchecked as transmute, io::{self, Read, Write}, iter, iter::{chain, once, repeat_n, successors, zip}, - mem::{replace as rplc, swap, transmute as rint}, + mem::{replace as rplc, swap}, ops::Range, }; } @@ -504,26 +505,64 @@ pub fn dijkstra_h<N: Debug + Eq + Hash + Copy + Ord, I: Iterator<Item = (N, u16) } dang!() } +#[derive(Debug, Clone, Copy)] +pub struct Left<T, U>(T, U); -pub fn steps<N: Debug + Eq + Hash + Clone + Ord, I: Iterator<Item = N>>( +impl<T: Hash, U> Hash for Left<T, U> { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + } +} + +impl<T: PartialEq, U> PartialEq for Left<T, U> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} +impl<T: Eq, U> Eq for Left<T, U> {} +impl<T: PartialOrd, U> PartialOrd for Left<T, U> { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.0.partial_cmp(&other.0) + } +} +impl<T: Ord, U> Ord for Left<T, U> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} +pub fn steps<N: Debug + Eq + Hash + Clone, I: Iterator<Item = N>>( start: N, graph: impl Fn(N) -> I, end: impl Fn(&N) -> bool, -) -> Option<(N, usize)> { +) -> Option<Left<N, usize>> { bfs( - (start, 0usize), - |(n, steps)| graph(n).map(move |x| (x, steps + 1)), + Left(start, 0usize), + |Left(n, steps)| graph(n).map(move |x| Left(x, steps + 1)), |x| end(&x.0), ) } +pub fn steps_astar<N: Debug + Eq + Hash + Clone, I: Iterator<Item = (N, i16)>>( + start: N, + graph: impl Fn(N) -> I, + heuristic: impl Fn(&N) -> i16, + goal: impl Fn(&N) -> bool, +) -> Option<(i16, Left<N, usize>)> { + astar( + Left(start, 0usize), + |Left(n, steps)| graph(n).map(move |(x, cost)| (Left(x, steps + 1), cost)), + |x| heuristic(&x.0), + |x| goal(&x.0), + ) +} + pub fn bfs<N: Debug + Eq + Hash + Clone, I: Iterator<Item = N>>( start: N, graph: impl Fn(N) -> I, end: impl Fn(&N) -> bool, ) -> Option<N> { let mut q = VecDeque::with_capacity(1024); - let mut s = HashSet::default(); + let mut s = HashSet::with_capacity_and_hasher(1024, rustc_hash::FxBuildHasher::default()); q.push_back(start); while let Some(n) = q.pop_front() { if end(&n) { @@ -539,6 +578,36 @@ pub fn bfs<N: Debug + Eq + Hash + Clone, I: Iterator<Item = N>>( // print!("{n:?} "); q.push_back(n); } + if s.len() % (1 << 20) == 0 { + dbg!(s.len()); + } + } + None +} + +pub fn astar<N: Debug + Eq + Hash + Clone, I: Iterator<Item = (N, i16)>>( + start: N, + graph: impl Fn(N) -> I, + heuristic: impl Fn(&N) -> i16, + goal: impl Fn(&N) -> bool, +) -> Option<(i16, N)> { + let mut q = BinaryHeap::with_capacity(1024); + let mut score = HashMap::default(); + score.insert(start.clone(), 0); + q.push(Reverse(Left(heuristic(&start), start))); + while let Some(Reverse(Left(c, n))) = q.pop() { + if goal(&n) { + return Some((c, n)); + } + for (n_, d) in graph(n.clone()) { + let g = score[&n] + d; + let of = score.get(&n_).unwrap_or(&i16::MAX); + if g < *of { + score.insert(n_.clone(), g); + let f = g + heuristic(&n_); + q.push(Reverse(Left(f, n_))); + } + } } None } @@ -550,8 +619,8 @@ pub fn dijkstra<N: Debug + Eq + Hash + Clone + Ord, I: Iterator<Item = (N, u16)> ) -> Option<(u16, N)> { let mut q = BinaryHeap::new(); let mut s = HashSet::default(); - q.push(Reverse((0, start))); - while let Some(Reverse((c, n))) = q.pop() { + q.push(Reverse(Left(0, start))); + while let Some(Reverse(Left(c, n))) = q.pop() { if end(&n) { return Some((c, n)); } @@ -563,7 +632,7 @@ pub fn dijkstra<N: Debug + Eq + Hash + Clone + Ord, I: Iterator<Item = (N, u16)> continue; } // print!("{n:?} "); - q.push(Reverse((c + d, n))); + q.push(Reverse(Left(c + d, n))); } } None |