diff --git a/2024/Cargo.lock b/2024/Cargo.lock index 54b8365..b8b08b2 100644 --- a/2024/Cargo.lock +++ b/2024/Cargo.lock @@ -51,6 +51,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "atools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b8fc827c2d2ad4c1fa0d458efc9716e2f458c135f3f4f2332ed9ddd85c037e" + [[package]] name = "autocfg" version = "1.4.0" @@ -133,12 +139,16 @@ dependencies = [ name = "day01" version = "0.1.0" dependencies = [ + "atools", "bstr", "divan", "helper", + "hinted", + "itertools", "memchr", "nom", "num-traits", + "radsort", "rustc-hash", ] @@ -167,6 +177,12 @@ dependencies = [ "syn", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "errno" version = "0.3.10" @@ -186,12 +202,27 @@ dependencies = [ "nom", ] +[[package]] +name = "hinted" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9965bbdc3ee9917c5bc2b59da94906fce9e3693fc7609c8b178f15bf5077ba69" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "libc" version = "0.2.167" @@ -253,6 +284,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radsort" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "019b4b213425016d7d84a153c4c73afb0946fbb4840e4eece7ba8848b9d6da22" + [[package]] name = "regex-automata" version = "0.4.9" diff --git a/2024/day01/Cargo.toml b/2024/day01/Cargo.toml index bfbef6e..7a1b57f 100644 --- a/2024/day01/Cargo.toml +++ b/2024/day01/Cargo.toml @@ -13,6 +13,10 @@ rustc-hash = "2.1.0" memchr = "2.7.4" num-traits = "0.2.19" bstr = "1.11.0" +atools = "0.1.5" +hinted = "0.0.1" +radsort = "0.1.1" +itertools = "0.13.0" [[bench]] name = "benches" diff --git a/2024/day01/src/lib.rs b/2024/day01/src/lib.rs index 680521d..74026ee 100644 --- a/2024/day01/src/lib.rs +++ b/2024/day01/src/lib.rs @@ -1,4 +1,21 @@ #![feature(portable_simd)] +#![feature( + slice_swap_unchecked, + generic_const_exprs, + iter_array_chunks, + get_many_mut, + maybe_uninit_uninit_array, + iter_collect_into, + let_chains, + anonymous_lifetime_in_impl_trait, + array_windows, + slice_take, + test, + slice_as_chunks, + array_chunks, + slice_split_once, + core_intrinsics +)]#![feature(hint_assert_unchecked)] use core::str; use std::{collections::HashMap, hash::BuildHasherDefault}; @@ -28,6 +45,7 @@ helper::define_variants! { nora => crate::part2_simd; clubby => crate::part2_clubby; part2_max397 => crate::part2_max397; + bendn => crate::part2_bendn; } } @@ -532,6 +550,1507 @@ fn part2_max397(input: &str) -> u64 { part2(input) } +pub fn part2_bendn(i: &str) -> u64 { + use util::Widen; + extern crate test; + mod util { + #![allow(non_snake_case, unused_macros)] + + use rustc_hash::FxHashMap as HashMap; + use rustc_hash::FxHashSet as HashSet; + use std::{ + cmp::Reverse, + collections::{hash_map::Entry, BinaryHeap}, + fmt::{Debug, Display, Write}, + hash::Hash, + mem::swap, + ops::RangeInclusive, + str::FromStr, + }; + + pub mod prelude { + #[allow(unused_imports)] + pub(crate) use super::{bits, dang, leek, mat, shucks, C}; + pub use super::{ + even, gcd, gt, l, lcm, lt, pa, r, rand, reading, reading::Ext, sort, Dir, FilterBy, + FilterBy3, GreekTools, IntoCombinations, IntoLines, IterͶ, NumTupleIterTools, + ParseIter, Printable, Skip, TakeLine, TupleIterTools2, TupleIterTools2R, + TupleIterTools3, TupleUtils, UnifiedTupleUtils, UnsoundUtilities, Widen, Ͷ, Α, Κ, + Λ, Μ, + }; + pub use itertools::izip; + pub use itertools::Itertools; + pub use rustc_hash::FxHashMap as HashMap; + pub use rustc_hash::FxHashSet as HashSet; + pub use std::{ + cmp::Ordering::*, + cmp::{max, min}, + collections::{hash_map::Entry, VecDeque}, + fmt::{Debug, Display}, + hint::black_box as boxd, + io::{self, Read, Write}, + iter, + mem::{replace as rplc, swap, transmute as rint}, + ops::Range, + }; + } + + macro_rules! C { + ($obj:ident.$what:ident$($tt:tt)+) => {{ + let x = &mut $obj.$what; + C!( x$($tt)+ ) + }}; + (&$buf:ident[$n:expr]) => {{ + #[allow(unused_unsafe)] + unsafe { + $buf.get_unchecked($n) + } + }}; + ($buf:ident[$n:expr]) => {{ + #[allow(unused_unsafe)] + *unsafe { + $buf.get_unchecked($n) + } + }}; + (&mut $buf:ident[$n:expr]) => {{ + #[allow(unused_unsafe)] + unsafe { + $buf.get_unchecked_mut($n) + } + }}; + ($buf:ident[$a:expr] = $rbuf:ident[$b:expr]) => { + *unsafe { $buf.get_unchecked_mut($a) } = unsafe { *$rbuf.get_unchecked($b) } + }; + ($buf:ident[$n:expr] = $e:expr) => { + *unsafe { $buf.get_unchecked_mut($n) } = $e + }; + ($buf:ident[$a:expr][$b:expr]) => { + unsafe { *$buf.get_unchecked($a).get_unchecked($b) } + }; + ($buf:ident[$a:expr][$b:expr] = $rbuf:ident[$ra:expr]) => { + *unsafe { $buf.get_unchecked_mut($a).get_unchecked_mut($b) } = + unsafe { *$rbuf.get_unchecked($ra) } + }; + ($buf:ident[$a:expr][$b:expr] = $rbuf:ident[$ra:expr][$rb:expr]) => { + *unsafe { $buf.get_unchecked_mut($a).get_unchecked_mut($b) } = + unsafe { *$rbuf.get_unchecked($ra).get_unchecked($rb) } + }; + ($buf:ident[$a:expr][$b:expr] = $c:expr) => {{ + #[allow(unused_unsafe)] + { + *unsafe { $buf.get_unchecked_mut($a).get_unchecked_mut($b) } = unsafe { $c } + } + }}; +} + pub(crate) use C; + + macro_rules! shucks { + () => { + if cfg!(debug_assertions) { + unreachable!(); + } else { + unsafe { std::hint::unreachable_unchecked() } + } + }; + ($fmt:literal $(, $args:expr)* $(,)?) => { + if cfg!(debug_assertions) { + unreachable!($fmt $(, $args)*); + } else { + unsafe { std::hint::unreachable_unchecked() } + } + }; + (if $x:expr) => { + if $x { + if cfg!(debug_assertions) { + unreachable!(); + } else { + unsafe { std::hint::unreachable_unchecked() } + } + } + }; +} + pub(crate) use shucks; + + macro_rules! dang { + () => { + panic!() + }; + } + pub(crate) use dang; + + macro_rules! leek { + ($($allocation:ident)+) => { + $(std::mem::forget($allocation);)+ + }; +} + pub(crate) use leek; + + macro_rules! mat { + ($thing:ident { $($what:pat => $b:expr,)+ }) => { + match $thing { $($what => { $b })+ _ => shucks!() } + }; +} + pub(crate) use mat; + + #[cfg(target_feature = "avx2")] + unsafe fn count_avx(hay: &[u8; N], needle: u8) -> usize { + use std::arch::x86_64::*; + let find = _mm256_set1_epi8(needle as i8); + let mut counts = _mm256_setzero_si256(); + for i in 0..(N / 32) { + counts = _mm256_sub_epi8( + counts, + _mm256_cmpeq_epi8( + _mm256_loadu_si256(hay.as_ptr().add(i * 32) as *const _), + find, + ), + ); + } + const MASK: [u8; 64] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, + ]; + counts = _mm256_sub_epi8( + counts, + _mm256_and_si256( + _mm256_cmpeq_epi8( + _mm256_loadu_si256(hay.as_ptr().add(N - 32) as *const _), + find, + ), + _mm256_loadu_si256(MASK.as_ptr().add(N % 32) as *const _), + ), + ); + + let sums = _mm256_sad_epu8(counts, _mm256_setzero_si256()); + (_mm256_extract_epi64(sums, 0) + + _mm256_extract_epi64(sums, 1) + + _mm256_extract_epi64(sums, 2) + + _mm256_extract_epi64(sums, 3)) as usize + } + + pub fn count(hay: &[u8; N], what: u8) -> usize { + #[cfg(target_feature = "avx2")] + return unsafe { count_avx(hay, what) }; + #[cfg(not(target_feature = "avx2"))] + hay.iter().filter(|&&x| x == what).count() + } + + pub fn lcm(n: impl IntoIterator) -> u64 { + let mut x = n.into_iter(); + let mut lcm = x.by_ref().next().expect("cannot compute LCM of 0 numbers"); + let mut g; + for x in x { + g = gcd(x, lcm); + lcm = (lcm * x) / g; + } + lcm + } + + #[repr(u8)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] + pub enum Dir { + N = b'U', + E = b'R', + S = b'D', + W = b'L', + } + + pub trait UnsoundUtilities { + fn ψ(self) -> T; + } + + impl UnsoundUtilities for Option { + fn ψ(self) -> T { + if cfg!(debug_assertions) && self.is_none() { + panic!(); + } + unsafe { self.unwrap_unchecked() } + } + } + + impl UnsoundUtilities for Result { + #[cfg_attr(debug_assertions, track_caller)] + fn ψ(self) -> T { + if cfg!(debug_assertions) && self.is_err() { + panic!(); + } + unsafe { self.unwrap_unchecked() } + } + } + + pub struct LMap(HashMap, F) + where + F: Fn(K) -> Option, + K: Eq + Hash + Copy; + impl LMap + where + F: Fn(K) -> Option, + { + pub fn new(f: F) -> Self { + Self { + 0: HashMap::default(), + 1: f, + } + } + + pub fn get(&mut self, k: K) -> Option<&mut V> { + match self.0.entry(k) { + Entry::Occupied(x) => Some(x.into_mut()), + Entry::Vacant(e) => match self.1(k) { + Some(v) => Some(e.insert(v)), + None => None, + }, + } + } + } + + pub fn countg>( + start: N, + graph: &mut impl Fn(N) -> I, + sum: &mut usize, + end: &mut impl Fn(N) -> bool, + has: &mut HashSet, + ) { + if end(start) { + *sum += 1; + } else { + graph(start) + .map(|x| { + if has.insert(x) { + countg(x, graph, sum, end, has); + } + }) + .Θ(); + } + } + + // pub fn appearances(x: ) + + pub fn iterg>( + start: N, + graph: &mut impl Fn(N) -> I, + end: &mut impl Fn(N) -> bool, + finally: &mut impl FnMut(N), + ) { + if end(start) { + finally(start); + } else { + graph(start).map(|x| iterg(x, graph, end, finally)).Θ(); + }; + } + + pub fn show, D: Display>( + graph: impl Fn(N) -> I, + start: N, + end: impl Fn(N) -> bool, + name: impl Fn(N) -> D, + ) { + println!("digraph {{"); + let mut s = HashSet::default(); + let mut q = BinaryHeap::new(); + q.push(Reverse((0, start))); + while let Some(Reverse((c, n))) = q.pop() { + if end(n) { + println!("}}"); + return; + } + if !s.insert(n) { + continue; + } + print!("\t{}", name(n)); + for (n, d) in graph(n) { + if s.contains(&n) { + continue; + } + print!(" -> {}", name(n)); + q.push(Reverse((c + d, n))); + } + println!(";"); + } + dang!(); + } + + pub fn dijkstra_h>( + graph: impl Fn(N) -> I, + start: N, + end: impl Fn(N) -> bool, + h: impl Fn(N) -> u16, + ) -> u16 { + let mut q = BinaryHeap::new(); + let mut s = HashSet::default(); + q.push(Reverse((h(start), 0, start))); + while let Some(Reverse((_, c, n))) = q.pop() { + if end(n) { + return c; + } + if !s.insert(n) { + continue; + } + for (n, d) in graph(n) { + if s.contains(&n) { + continue; + } + q.push(Reverse((h(n) + c + d, c + d, n))); + } + } + dang!() + } + + pub fn dijkstra>( + graph: impl Fn(N) -> I, + start: N, + end: impl Fn(N) -> bool, + ) -> u16 { + let mut q = BinaryHeap::new(); + let mut s = HashSet::default(); + q.push(Reverse((0, start))); + while let Some(Reverse((c, n))) = q.pop() { + if end(n) { + return c; + } + if !s.insert(n) { + continue; + } + for (n, d) in graph(n) { + if s.contains(&n) { + continue; + } + q.push(Reverse((c + d, n))); + } + } + dang!() + } + + impl std::ops::Add<(i64, i64)> for Dir { + type Output = (i64, i64); + fn add(self, (x, y): (i64, i64)) -> Self::Output { + match self { + Dir::N => (x, y - 1), + Dir::E => (x + 1, y), + Dir::S => (x, y + 1), + Dir::W => (x - 1, y), + } + } + } + + impl std::ops::Add<(i32, i32)> for Dir { + type Output = (i32, i32); + fn add(self, (x, y): (i32, i32)) -> Self::Output { + match self { + Dir::N => (x, y - 1), + Dir::E => (x + 1, y), + Dir::S => (x, y + 1), + Dir::W => (x - 1, y), + } + } + } + + impl std::ops::Add<(u16, u16)> for Dir { + type Output = (u16, u16); + + fn add(self, (x, y): (u16, u16)) -> Self::Output { + match self { + Dir::N => (x, y - 1), + Dir::E => (x + 1, y), + Dir::S => (x, y + 1), + Dir::W => (x - 1, y), + } + } + } + + impl std::ops::Add<(i16, i16)> for Dir { + type Output = (i16, i16); + fn add(self, (x, y): (i16, i16)) -> Self::Output { + match self { + Dir::N => (x, y - 1), + Dir::E => (x + 1, y), + Dir::S => (x, y + 1), + Dir::W => (x - 1, y), + } + } + } + + impl std::ops::Add<(u8, u8)> for Dir { + type Output = Option<(u8, u8)>; + + fn add(self, (x, y): (u8, u8)) -> Self::Output { + match self { + Dir::N => Some((x, y.checked_sub(1)?)), + Dir::E => Some((x + 1, y)), + Dir::S => Some((x, y + 1)), + Dir::W => Some((x.checked_sub(1)?, y)), + } + } + } + + pub fn pa(a: &[T]) { + for e in a { + print!("{e:?}"); + } + println!(); + } + + pub fn gcd(mut a: u64, mut b: u64) -> u64 { + if a == 0 || b == 0 { + return a | b; + } + let shift = (a | b).trailing_zeros(); + a >>= shift; + loop { + b >>= b.trailing_zeros(); + if a > b { + swap(&mut a, &mut b); + } + b -= a; + if b == 0 { + break; + } + } + a << shift + } + + pub trait Λ { + fn λ(&self) -> T + where + ::Err: std::fmt::Display; + } + + impl Λ for String { + fn λ(&self) -> T + where + ::Err: std::fmt::Display, + { + self.as_str().λ() + } + } + impl Λ for &[u8] { + fn λ(&self) -> T + where + ::Err: std::fmt::Display, + { + std::str::from_utf8(self).α().λ() + } + } + impl Λ for &str { + /// parse, unwrap + fn λ(&self) -> T + where + ::Err: std::fmt::Display, + { + match self.parse() { + Ok(v) => v, + Err(e) => { + panic!( + "{e}: {self} should parse into {}", + std::any::type_name::() + ) + } + } + } + } + pub trait Κ { + fn κ(self) -> impl Iterator + where + ::Err: std::fmt::Display; + } + + impl Κ for &[u8] { + fn κ(self) -> impl Iterator + where + ::Err: std::fmt::Display, + { + std::str::from_utf8(self).unwrap().κ() + } + } + + impl Κ for &str { + fn κ(self) -> impl Iterator + where + ::Err: std::fmt::Display, + { + self.split_ascii_whitespace().map(|x| x.λ()) + } + } + + pub trait Α { + fn α(self) -> T; + } + + impl Α for Result { + #[cfg_attr(debug_assertions, track_caller)] + fn α(self) -> T { + match self { + Ok(v) => v, + Err(e) => { + panic!("unwrap failed: {e}"); + } + } + } + } + impl Α for Option { + #[cfg_attr(debug_assertions, track_caller)] + fn α(self) -> T { + match self { + Some(v) => v, + None => panic!("nothingness!"), + } + } + } + + pub trait Ͷ { + fn ͷ(self) -> impl Iterator; + } + + macro_rules! digs { + ($for:ty) => { + impl Ͷ for $for { + fn ͷ(self) -> impl Iterator { + let digits = (self.ilog10() + 1) as u8; + (0..digits) + .rev() + .map(move |n| ((self / (10 as $for).pow(n as _)) % 10) as u8) + } + } + }; + } + digs!(u64); + digs!(i64); + digs!(i32); + digs!(u32); + digs!(u16); + digs!(i16); + digs!(u8); + digs!(i8); + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + pub struct Ronge { + pub begin: u16, + pub end: u16, + } + + impl Debug for Ronge { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}..{}", self.begin, self.end) + } + } + + impl Display for Ronge { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}..{}", self.begin, self.end) + } + } + + impl From> for Ronge { + fn from(value: RangeInclusive) -> Self { + Self { + begin: *value.start(), + end: *value.end(), + } + } + } + + impl PartialEq> for Ronge { + fn eq(&self, other: &RangeInclusive) -> bool { + self == &Self::from(other.clone()) + } + } + + impl Ronge { + pub fn sane(self) -> bool { + self.end >= self.begin + } + pub fn checked_len(self) -> Option { + self.sane().then(|| self.len()) + } + pub fn len(self) -> u16 { + self.end - self.begin + } + + /// push up + pub fn pushu(&mut self, to: u16) { + self.begin = self.begin.max(to); + } + + /// push down + pub fn pushd(&mut self, to: u16) { + self.end = self.end.min(to); + } + + pub fn intersect(self, with: Self) -> Self { + Self { + begin: self.begin.max(with.begin), + end: self.end.min(with.end), + } + } + + pub fn news(&self, begin: u16) -> Self { + Self { + begin, + end: self.end, + } + } + + pub fn newe(&self, end: u16) -> Self { + Self { + begin: self.begin, + end, + } + } + + pub fn shrink(&mut self, with: Ronge) { + self.pushu(with.begin); + self.pushd(with.end); + } + } + + impl IntoIterator for Ronge { + type Item = u16; + + type IntoIter = std::ops::Range; + + fn into_iter(self) -> Self::IntoIter { + self.begin..self.end + } + } + + pub trait Μ where + Self: Sized, + { + fn μ(self, d: char) -> (Self, Self); + fn μκ(self, d: char) -> impl Iterator + where + ::Err: std::fmt::Display; + + fn μ1(self, d: char) -> Self { + self.μ(d).1 + } + + fn μ0(self, d: char) -> Self { + self.μ(d).0 + } + + fn between(self, a: char, b: char) -> Self { + self.μ1(a).μ0(b) + } + } + + impl Μ for &[u8] { + fn μ(self, d: char) -> (Self, Self) { + let i = self + .iter() + .position(|&x| x == d as u8) + .unwrap_or_else(|| shucks!("{} should split at {d} fine", self.p())); + (&self[..i], &self[i + 1..]) + } + + fn μκ(self, d: char) -> impl Iterator + where + ::Err: std::fmt::Display, + { + let (α, β) = self.μ(d); + α.κ::().zip(β.κ::()) + } + } + + pub fn gt, T>(n: T) -> impl Fn(A) -> bool { + move |a| a > n + } + + pub fn lt, T>(n: T) -> impl Fn(A) -> bool { + move |a| a < n + } + + impl Μ for &str { + fn μ(self, d: char) -> (Self, Self) { + self.split_once(d) + .unwrap_or_else(|| shucks!("{self} should split at {d} fine")) + } + + fn μκ(self, d: char) -> impl Iterator + where + ::Err: std::fmt::Display, + { + let (α, β) = self.μ(d); + α.κ::().zip(β.κ::()) + } + } + + pub trait IterͶ: Iterator { + fn ͷ(self) -> impl Iterator; + } + + impl> IterͶ for I { + fn ͷ(self) -> impl Iterator { + self.flat_map(Ͷ::ͷ) + } + } + + pub trait TupleIterTools3: Iterator { + fn l(self) -> impl Iterator; + fn m(self) -> impl Iterator; + fn r(self) -> impl Iterator; + fn lm(self) -> impl Iterator; + fn lr(self) -> impl Iterator; + fn mr(self) -> impl Iterator; + } + + pub trait TupleIterTools2: Iterator { + fn l(self) -> impl Iterator; + fn r(self) -> impl Iterator; + } + + pub trait TupleIterTools2R: Iterator { + fn l(self) -> impl Iterator; + fn r(self) -> impl Iterator; + } + + pub fn l(f: impl Fn(T) -> R) -> impl Fn((T, U)) -> R { + move |(x, _)| f(x) + } + pub fn r(f: impl Fn(U) -> R) -> impl Fn((T, U)) -> R { + move |(_, x)| f(x) + } + + pub trait FilterBy3: Iterator { + fn fl(self, f: impl Fn(T) -> bool) -> impl Iterator; + fn fm(self, f: impl Fn(U) -> bool) -> impl Iterator; + fn fr(self, f: impl Fn(V) -> bool) -> impl Iterator; + } + + impl> FilterBy3 for I { + fn fl(self, f: impl Fn(T) -> bool) -> impl Iterator { + self.filter(move |(x, _, _)| f(*x)) + } + + fn fm(self, f: impl Fn(U) -> bool) -> impl Iterator { + self.filter(move |(_, x, _)| f(*x)) + } + fn fr(self, f: impl Fn(V) -> bool) -> impl Iterator { + self.filter(move |(_, _, x)| f(*x)) + } + } + pub trait FilterBy: Iterator { + fn fl(self, f: impl Fn(T) -> bool) -> impl Iterator; + fn fr(self, f: impl Fn(U) -> bool) -> impl Iterator; + } + + impl> FilterBy for I { + fn fl(self, f: impl Fn(T) -> bool) -> impl Iterator { + self.filter(move |(x, _)| f(*x)) + } + + fn fr(self, f: impl Fn(U) -> bool) -> impl Iterator { + self.filter(move |(_, x)| f(*x)) + } + } + + pub trait NumTupleIterTools { + fn πολλαπλασιάζω_και_αθροίζω(&mut self) -> u64; + } + + impl> NumTupleIterTools for I { + fn πολλαπλασιάζω_και_αθροίζω(&mut self) -> u64 { + self.map(|(a, b)| a * b).sum() + } + } + + impl> TupleIterTools2 for I { + fn l(self) -> impl Iterator { + self.map(|(x, _)| x) + } + + fn r(self) -> impl Iterator { + self.map(|(_, x)| x) + } + } + + impl<'a, T: Copy + 'a, U: Copy + 'a, I: Iterator> TupleIterTools2R for I { + fn l(self) -> impl Iterator { + self.map(|&(x, _)| x) + } + fn r(self) -> impl Iterator { + self.map(|&(_, x)| x) + } + } + + impl> TupleIterTools3 for I { + fn l(self) -> impl Iterator { + self.map(|(x, _, _)| x) + } + + fn m(self) -> impl Iterator { + self.map(|(_, x, _)| x) + } + + fn r(self) -> impl Iterator { + self.map(|(_, _, x)| x) + } + + fn lm(self) -> impl Iterator { + self.map(|(a, b, _)| (a, b)) + } + + fn lr(self) -> impl Iterator { + self.map(|(a, _, b)| (a, b)) + } + + fn mr(self) -> impl Iterator { + self.map(|(_, a, b)| (a, b)) + } + } + + pub trait GreekTools: Iterator { + fn Δ(&mut self) -> T; + fn ι(&mut self) -> impl Iterator + where + Self: Ι; + fn ι1(&mut self) -> impl Iterator + where + Self: Ι; + fn ν(&mut self, into: &mut [T; N]) -> usize; + fn Θ(&mut self); + } + + pub trait ParseIter { + fn κ(&mut self) -> impl Iterator + where + ::Err: std::fmt::Display; + } + + impl<'x, I: Iterator> ParseIter for I { + fn κ(&mut self) -> impl Iterator + where + ::Err: std::fmt::Display, + { + self.flat_map(|x| x.κ()) + } + } + + pub trait Ι: Iterator { + fn ι(&mut self) -> impl Iterator; + fn ι1(&mut self) -> impl Iterator; + } + + macro_rules! ι { + ($t:ty) => { + impl> Ι for I { + fn ι(&mut self) -> impl Iterator { + self.zip(0..) + } + + fn ι1(&mut self) -> impl Iterator { + self.zip(1..) + } + } + }; + } + ι!(u8); + ι!(u16); + ι!(u32); + ι!(u64); + ι!(usize); + + pub fn nail(x: &[u8]) -> [u8; N] { + unsafe { (x.as_ptr() as *const [u8; N]).read() } + } + + pub mod reading { + pub fn 八(n: u64) -> u64 { + // reinterpret as u64 ("92233721" => 92233721) + // let n = u64::from_le_bytes(s); + // combine 4 pairs of single digits: + // split pieces into odd and even + // 1_7_3_2_ (le repr) + // _2_3_2_9 + // then combine + // _21_37_23_92 (le repr, each byte as 2 digits) + let n = ((n & 0x0f000f000f000f00) >> 8) + ((n & 0x000f000f000f000f) * 10); + // combine 2 pairs of 2 digits: + // split again + // _21___23__ + // ___37___92 + // then combine + // __14|137__36|7 (le repr, pipes separating bytes) + let n = ((n & 0x00ff000000ff0000) >> 16) + ((n & 0x000000ff000000ff) * 100); + // combine pair of 4 digits + // split again + // __14|137____ (then moved to ______14|137, as u64:3721) + // ______36|07 (as u64: 9223) + // then combine + ((n & 0x0000ffff00000000) >> 32) + ((n & 0x000000000000ffff) * 10000) + } + + use std::{ + io::{self, Read}, + ops::{Add, BitOrAssign, Shl}, + }; + pub trait Ext { + fn rd(&mut self) -> io::Result<[u8; N]>; + fn by(&mut self) -> io::Result { + Ok(self.rd::<1>()?[0]) + } + } + + impl Ext for T { + fn rd(&mut self) -> io::Result<[u8; N]> { + let mut buf = [0; N]; + self.read_exact(&mut buf)?; + Ok(buf) + } + } + use super::prelude::*; + pub fn κ(x: &[u8], v: &mut Vec) { + let mut s = 0; + for &b in x { + match b { + b' ' => { + v.push(s); + s = 0; + } + b => { + s = s * 10 + (b - b'0') as u64; + } + } + } + } + pub trait Ten { + fn ten() -> Self; + } + macro_rules! tenz { + ($for:ty) => { + impl Ten for $for { + fn ten() -> $for { + 10 + } + } + }; + } + tenz!(u8); + tenz!(u16); + tenz!(u32); + tenz!(u64); + tenz!(u128); + tenz!(i8); + tenz!(i16); + tenz!(i32); + tenz!(i64); + tenz!(i128); + + const DIG: [u8; 256] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ]; + + pub fn hex_dig(b: u8) -> u8 { + DIG[b.nat()] + // (b & 0xF) + 9 * (b >> 6) + } + + pub fn hexN< + T: From + TryFrom + Shl + BitOrAssign, + const N: usize, + >( + a: [u8; N], + ) -> T { + let mut c = T::from(hex_dig(a[0])) << T::try_from((N - 1) * 4).ψ(); + for (&n, sh) in a[1..].iter().zip((0..N - 1).rev()) { + c |= T::from(hex_dig(n)) << T::try_from(sh * 4).ψ(); + } + c + } + + pub fn hex(mut d: &[u8]) -> Result { + let &b = d.take_first().ok_or(())?; + let mut num = hex_dig(b) as u32; + while let Some(&b) = d.take_first() { + num = num * 16 + hex_dig(b) as u32; + } + Ok(num) + } + + pub fn 迄または完了< + T: Default + std::ops::Mul + Add + From + Copy + Ten, + >( + x: &mut &[u8], + until: u8, + ) -> T { + let mut n = T::default(); + while let Ok(x) = x.by() { + if x == until { + return n; + } + n = n * T::ten() + T::from(x - b'0') + } + n + } + + pub fn 負迄(x: &mut &[u8], until: u8) -> i64 { + let (sign, mut n) = match x.by().ψ() { + b'-' => (-1, 0), + b => (1, i64::from(b - b'0')), + }; + loop { + let byte = x.by().ψ(); + if byte == until { + return n * sign as i64; + } + n = n * 10 + i64::from(byte - b'0'); + } + } + + pub fn 迄< + T: Default + std::ops::Mul + Add + From + Copy + Ten, + >( + x: &mut &[u8], + until: u8, + ) -> T { + let mut n = T::default(); + loop { + let byte = x.by().ψ(); + if byte == until { + return n; + } + n = n * T::ten() + T::from(byte - b'0'); + } + } + + pub fn all< + T: Default + std::ops::Mul + Add + From + Copy + Ten, + >( + x: &[u8], + ) -> T { + let mut n = T::default(); + for &byte in x { + n = n * T::ten() + T::from(byte - b'0'); + } + n + } + } + + pub fn even(x: &usize) -> bool { + x % 2 == 0 + } + + impl> GreekTools for I { + #[cfg_attr(debug_assertions, track_caller)] + fn Δ(&mut self) -> T { + self.next().α() + } + + fn ν(&mut self, into: &mut [T; N]) -> usize { + let mut set = 0; + for e in into { + let Some(y) = self.next() else { break }; + *e = y; + set += 1; + } + set + } + + fn ι(&mut self) -> impl Iterator + where + Self: Ι, + { + self.ι() + } + + fn ι1(&mut self) -> impl Iterator + where + Self: Ι, + { + self.ι1() + } + + fn Θ(&mut self) { + for _ in self {} + } + } + + pub trait TupleUtils { + fn mr(self, f: impl FnOnce(U) -> W) -> (T, W); + fn ml(self, f: impl FnOnce(T) -> V) -> (V, U); + fn rev(self) -> (U, T); + } + + pub trait Widen { + fn nat(self) -> usize; + fn widen(self) -> Wide; + } + + macro_rules! wide { + ($t:ty: $upper:ty) => { + impl Widen<$upper> for $t { + fn nat(self) -> usize { + self as _ + } + + fn widen(self) -> $upper { + self as _ + } + } + }; + } + wide!(u8: u16); + wide!(u16: u32); + wide!(u32: u64); + wide!(u64: u128); + + pub trait UnifiedTupleUtils { + fn mb(self, f: impl FnMut(T) -> U) -> (U, U); + } + + impl UnifiedTupleUtils for (T, T) { + fn mb(self, mut f: impl FnMut(T) -> U) -> (U, U) { + (f(self.0), f(self.1)) + } + } + + impl TupleUtils for (T, U) { + fn mr(self, f: impl FnOnce(U) -> W) -> (T, W) { + (self.0, f(self.1)) + } + fn ml(self, f: impl FnOnce(T) -> V) -> (V, U) { + (f(self.0), self.1) + } + fn rev(self) -> (U, T) { + (self.1, self.0) + } + } + + #[allow(dead_code)] + fn cast_to>(x: bool, _to: T) -> T { + x.into() + } + + #[allow(unused_macros)] + macro_rules! bits { + ($bitset:ident + $bit:expr) => { + $bitset |= 1 << $bit + }; + ($holder:ident[$index:expr] + $bit:expr) => { + $holder[$index] |= 1 << $bit; + }; + ($bitset:ident[$bit:expr]) => { + ($bitset & 1 << $bit) != 0 + }; + ($holder:ident[$index:expr][$bit:expr]) => { + ($holder[$index] & 1 << $bit) != 0 + }; + ($holder:ident[$index:expr][$index2:expr][$bit:expr]) => { + ($holder[$index][$index2] & 1 << $bit) != 0 + }; + ($holder:ident[$index:expr][$index2:expr] + $bit:expr) => { + $holder[$index][$index2] |= 1 << $bit + }; + ($bitset:ident[$bit:expr] = $val:expr) => { + $bitset = ($bitset & !(1 << $bit)) | (util::cast_to($val, $bitset) << $bit) + }; + ($bitset:ident - $bit:expr) => { + $bitset &= !(1 << $bit) + }; + ($bitset:ident ! $bit:expr) => { + $bitset ^= 1 << $bit + }; + } + pub(crate) use bits; + + pub struct Lines<'a> { + bytes: &'a [u8], + } + + impl<'a> Iterator for Lines<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + self.bytes.take_line() + } + } + + impl<'a> std::iter::FusedIterator for Lines<'a> {} + + impl<'a> DoubleEndedIterator for Lines<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.bytes.take_backline() + } + } + + pub trait IntoLines { + fn 行(&self) -> Lines<'_>; + } + + impl> IntoLines for T { + fn 行(&self) -> Lines<'_> { + Lines { + bytes: self.as_ref(), + } + } + } + + pub trait Printable { + fn p(&self) -> impl std::fmt::Display; + } + + struct PrintU8s<'a>(&'a [u8]); + impl std::fmt::Display for PrintU8s<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for &b in self.0 { + if b.is_ascii() { + f.write_char(b as char)?; + } else { + write!(f, "\\x{b:x}")?; + } + } + Ok(()) + } + } + + struct PrintManyU8s<'a, T: AsRef<[u8]>>(&'a [T]); + impl> std::fmt::Display for PrintManyU8s<'_, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for row in self.0.as_ref() { + write!(f, "{},", row.as_ref().p())?; + } + Ok(()) + } + } + impl Printable for [Vec] { + fn p(&self) -> impl std::fmt::Display { + PrintManyU8s(self) + } + } + + impl Printable for [&&[u8]] { + fn p(&self) -> impl std::fmt::Display { + PrintManyU8s(self) + } + } + + impl Printable for [&[u8]] { + fn p(&self) -> impl std::fmt::Display { + PrintManyU8s(self) + } + } + + impl Printable for [u8] { + fn p(&self) -> impl std::fmt::Display { + PrintU8s(self) + } + } + + impl Printable for Vec { + fn p(&self) -> impl std::fmt::Display { + PrintU8s(self) + } + } + + pub fn sort(mut x: Vec) -> Vec { + x.sort_unstable(); + x + } + + pub trait TakeLine<'b> { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]>; + fn take_backline<'a>(&'a mut self) -> Option<&'b [u8]>; + } + + impl<'b> TakeLine<'b> for &'b [u8] { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]> { + match memchr::memchr(b'\n', self) { + None if self.is_empty() => None, + None => Some(std::mem::replace(self, b"")), + Some(end) => { + let line = &self[..end]; + *self = &self[end + 1..]; + Some(line) + } + } + } + + fn take_backline<'a>(&'a mut self) -> Option<&'b [u8]> { + let end = self.len().checked_sub(1)?; + match memchr::memrchr(b'\n', &self[..end]) { + None => Some(std::mem::replace(self, b"")), + Some(end) => { + let line = &self[end + 1..]; + *self = &self[..end]; + Some(line) + } + } + } + } + + impl<'b> TakeLine<'b> for &'b str { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]> { + match memchr::memchr(b'\n', self.as_bytes()) { + None if self.is_empty() => None, + None => Some(std::mem::replace(self, "").as_bytes()), + Some(end) => { + let line = self[..end].as_bytes(); + *self = &self[end + 1..]; + Some(line) + } + } + } + + fn take_backline<'a>(&'a mut self) -> Option<&'b [u8]> { + let end = self.len().checked_sub(1)?; + match memchr::memrchr(b'\n', &self.as_bytes()[..end]) { + None => Some(std::mem::replace(self, "").as_bytes()), + Some(end) => { + let line = &self[end + 1..]; + *self = &self[..end]; + Some(line.as_bytes()) + } + } + } + } + + pub trait IntoCombinations: Iterator { + /// LEAKY + fn combine(self) -> impl Iterator; + } + + impl> IntoCombinations for I { + fn combine(self) -> impl Iterator { + let x = Box::leak(self.collect::>()); + x.iter() + .enumerate() + .flat_map(|(i, &a)| x[i..].iter().map(move |&b| (a, b))) + } + } + + pub trait Skip { + fn skip(&mut self, n: usize); + } + + impl Skip for &[T] { + #[cfg_attr(debug_assertions, track_caller)] + fn skip(&mut self, n: usize) { + if cfg!(debug_assertions) { + *self = &self[n..]; + } else { + *self = C! { &self[n..] }; + } + } + } + + impl Skip for &str { + #[cfg_attr(debug_assertions, track_caller)] + fn skip(&mut self, n: usize) { + if cfg!(debug_assertions) { + *self = &self[n..]; + } else { + *self = C! { &self[n..] }; + } + } + } + + /// WYRAND based rng's + pub mod rand { + /// WYRAND + pub fn u64() -> u64 { + static mut STATE: u64 = 0; + let tmp = unsafe { + STATE = STATE.wrapping_add(0x60bee2bee120fc15); + (STATE as u128).wrapping_mul(0xa3b195354a39b70d) + }; + let m1 = (tmp >> 64) ^ tmp; + let tmp = m1.wrapping_mul(0x1b03738712fad5c9); + ((tmp >> 64) ^ tmp) as u64 + } + + /// 0..N + pub mod limit { + use super::super::Widen; + + pub fn u64(of: u64) -> u64 { + ((super::u64().widen().wrapping_mul(of.widen())) >> 64) as u64 + } + } + + pub fn u32() -> u32 { + u64() as u32 + } + + pub fn u16() -> u16 { + u64() as u16 + } + + pub fn f32() -> f32 { + (1.0 / ((1u32 << 24) as f32)) * ((u32() >> 8) as f32) + } + + pub fn f64() -> f64 { + (1.0 / ((1u64 << 53) as f64)) * ((u64() >> 11) as f64) + } + } + } + use atools::prelude::*; + use hinted::HintExt; + pub use util::prelude::*; + fn p1(i: &str) -> impl Display { + static mut a: [i32; 1000] = [0; 1000]; + static mut b: [i32; 1000] = [0; 1000]; + + unsafe { + i.as_bytes() + .as_chunks_unchecked::<14>() + .into_iter() + .map(|x| (reading::all(&x[0..5]), reading::all(&x[8..13]))) + .enumerate() + .for_each(|(i, (x, y))| { + *a.get_unchecked_mut(i) = x; + *b.get_unchecked_mut(i) = y; + }); + radsort::sort(&mut a); + radsort::sort(&mut b); + a.iter() + .copied() + .zip(b) + .map(|(x, y)| (x - y).abs()) + .sum::() + } + } + + static mut a: [u32; 1000] = [0; 1000]; + static mut map: [u32; 100000] = [0; 100000]; + let i = i.as_bytes(); + + unsafe { + let x = C! { &i[..14] }; + let (x, y) = (reading::all(&x[0..5]), reading::all::(&x[8..13])); + *a.get_unchecked_mut(0) = x; + *map.get_unchecked_mut(y as usize) += 1; + + for n in 1..1000 { + let x = util::reading::八( + u64::from_le_bytes(util::nail::<8>(i.get_unchecked(n * 14 - 3..))) + & 0xffffffffff000000, + ); + let y = util::reading::八(u64::from_le_bytes(util::nail::<8>( + i.get_unchecked(n * 14 + 5..), + ))); + *a.get_unchecked_mut(n) = x as u32; + *map.get_unchecked_mut(y as usize) += 1; + } + a.iter() + .copied() + .map(|x| x * map.get_unchecked(x as usize)) + .sum::() as u64 + } +} + helper::tests! { day01 Day01; part1 {