use std::array; use std::simd::u32x64; use rayon::prelude::*; use std::fs::File; use std::io::{BufReader, BufWriter}; use std::path::Path; use bincode::{Decode, Encode}; const SEED_BITWISE: usize = 32; const BLOCK_BITWISE: usize = 2048; const BLOCK_LENGTH: usize = BLOCK_BITWISE / SEED_BITWISE; const LUT_LENGTH: usize = (u32::MAX as usize + 1) / SEED_BITWISE; #[derive(Encode, Decode)] pub struct SlimeChunkLut { lut: Vec, } impl SlimeChunkLut { pub fn new() -> Self { Self { lut: (0..(LUT_LENGTH / BLOCK_LENGTH) as u32) .into_par_iter() .map(|chunk_i| { let seed_base = chunk_i * (SEED_BITWISE * BLOCK_LENGTH) as u32; Self::process_block(seed_base) }) .collect::>() .concat(), } } fn process_block(seed_base: u32) -> [u32; BLOCK_LENGTH] { const M: u32 = 397; const MATRIX_A: u32 = 0x9908_b0df; const UPPER_MASK: u32 = 0x8000_0000; const LOWER_MASK: u32 = 0x7fff_ffff; let mut result = u32x64::splat(0); for offset in 0..(SEED_BITWISE as u32) { // 用simd批量计算,种子间距32,这样可以直接快速压位 let seed = u32x64::from_array(array::from_fn(|i| { seed_base + offset + (i as u32) * (SEED_BITWISE as u32) })); // 初始化丐版mt19937的内部状态 let mut m = seed; let m0 = m; m = u32x64::splat(1_812_433_253) * (m ^ m >> 30) + u32x64::splat(1); let m1 = m; for i in 2..=M { m = u32x64::splat(1_812_433_253) * (m ^ m >> 30) + u32x64::splat(i); } let mm = m; // 生成一个伪随机数 let mut y = (m0 & u32x64::splat(UPPER_MASK)) | (m1 & u32x64::splat(LOWER_MASK)); let y_mask = !((y & u32x64::splat(1)) - u32x64::splat(1)); y = mm ^ (y >> 1) ^ (y_mask & u32x64::splat(MATRIX_A)); y ^= y >> 11; y ^= y << 7 & u32x64::splat(0x9d2c_5680); y ^= y << 15 & u32x64::splat(0xefc6_0000); y ^= y >> 18; // 判断是否是10的整数倍 let mut is_slime_chunk = y % u32x64::splat(10); is_slime_chunk = (is_slime_chunk - u32x64::splat(1)) >> (SEED_BITWISE - 1) as u32; // 压位成bitmap result |= is_slime_chunk << u32x64::splat(offset); } result.to_array() } pub fn save_to_file>(&self, path: P) -> Result<(), Box> { let config = slime_chunk_lut_config(); let file = File::create(path)?; let mut writer = BufWriter::new(file); bincode::encode_into_std_write(self, &mut writer, config)?; Ok(()) } pub fn load_from_file>(path: P) -> Result> { let config = slime_chunk_lut_config(); let file = File::open(path)?; let mut reader = BufReader::new(file); let lut = bincode::decode_from_std_read(&mut reader, config)?; Ok(lut) } pub fn is_slime_chunk(&self, seed: u32) -> bool { self.lut[seed as usize / SEED_BITWISE] & (1 << (seed % SEED_BITWISE as u32)) != 0 } } fn slime_chunk_lut_config( ) -> bincode::config::Configuration { bincode::config::standard() .with_little_endian() .with_fixed_int_encoding() }