heh
-rw-r--r--src/inp.txt34
-rw-r--r--src/main.rs151
-rw-r--r--src/util.rs87
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