Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- let mut wfc_grid = WfcGrid::from_runner(&mut runner);
- while wfc_grid.remaining > 0 && wfc_grid.retraced_time < wfc_grid.max_retrace_time {
- wfc_grid.collapse();
- }
- wfc_grid.generate_data()
- // -------------
- pub struct WfcGrid {
- mode: WfcMode,
- ty: TilemapType,
- area: TileArea,
- rng: StdRng,
- conn_rules: Vec<Vec<u128>>,
- uncollapsed: HashSet<(u8, UVec2)>,
- elements: HashMap<UVec2, WfcElement>,
- remaining: usize,
- history: Vec<Option<WfcHistory>>,
- cur_hist: usize,
- retrace_strength: u32,
- max_retrace_factor: u32,
- max_retrace_time: u32,
- retraced_time: u32,
- sampler: Option<Box<dyn Fn(&WfcElement, &mut StdRng) -> u8 + Send + Sync>>,
- }
- impl WfcGrid {
- pub fn from_runner(runner: &mut WfcRunner) -> Self {
- let mut uncollapsed = HashSet::new();
- let mut elements = HashMap::new();
- let max_psbs = runner.conn_rules.len() as u8;
- for y in 0..runner.area.extent.y {
- for x in 0..runner.area.extent.x {
- elements.insert(
- UVec2 { x, y },
- WfcElement {
- index: UVec2 { x, y },
- element_index: None,
- collapsed: false,
- psbs: (!0) >> (128 - max_psbs),
- },
- );
- uncollapsed.insert((max_psbs, UVec2 { x, y }));
- }
- }
- WfcGrid {
- mode: runner.mode.clone(),
- area: runner.area,
- conn_rules: runner.conn_rules.clone(),
- uncollapsed,
- elements,
- history: vec![None; runner.max_history],
- cur_hist: 0,
- ty: runner.ty,
- rng: match runner.seed {
- Some(seed) => StdRng::seed_from_u64(seed),
- None => StdRng::from_entropy(),
- },
- remaining: runner.area.size(),
- retrace_strength: 1,
- max_retrace_factor: runner.max_retrace_factor,
- max_retrace_time: runner.max_retrace_time,
- retraced_time: 0,
- sampler: runner.sampler.take(),
- }
- }
- pub fn collapse(&mut self) {
- println!("{:?}+{}", self.rng, self.remaining);
- self.history[self.cur_hist] = Some(WfcHistory {
- uncollapsed: self.uncollapsed.clone(),
- elements: self.elements.clone(),
- remaining: self.remaining,
- });
- self.cur_hist = (self.cur_hist + 1) % self.history.len();
- let min = self.get_min();
- let elem = self.elements.get_mut(&min).unwrap();
- self.uncollapsed
- .remove(&(elem.psbs.count_ones() as u8, elem.index));
- let psb = match &self.mode {
- WfcMode::NonWeighted => {
- let psb_vec = elem.get_psbs_vec();
- let result = self.rng.sample(Uniform::new(0, psb_vec.len()));
- println!("{}", result);
- psb_vec[result]
- }
- WfcMode::Weighted(w) => {
- let psb_vec = elem.get_psbs_vec();
- let weights = psb_vec.iter().map(|p| w[*p as usize]).collect::<Vec<_>>();
- psb_vec[self.rng.sample(WeightedIndex::new(weights).unwrap())]
- }
- WfcMode::CustomSampler => {
- let mut rng = self.rng.clone();
- let res = self.sampler.as_ref().unwrap()(&elem, &mut rng) as u8;
- self.rng = rng;
- res
- }
- };
- elem.element_index = Some(psb);
- elem.psbs = 1 << psb;
- elem.collapsed = true;
- self.remaining -= 1;
- self.retrace_strength *= self.max_retrace_factor;
- let index = elem.index;
- self.constrain(index);
- }
- pub fn constrain(&mut self, center: UVec2) {
- let mut queue = VecDeque::from([center]);
- let mut spreaded = HashSet::from([center]);
- while !queue.is_empty() {
- let cur_center = queue.pop_front().unwrap();
- spreaded.insert(cur_center);
- let cur_elem = self.elements.get(&cur_center).cloned().unwrap();
- let neis = cur_center.neighbours(self.ty, false);
- let nei_count = neis.len();
- for dir in 0..nei_count {
- let Some(nei_index) = neis[dir] else {
- continue;
- };
- let Some(nei_elem) = self.elements.get_mut(&nei_index) else {
- continue;
- };
- if nei_elem.collapsed || spreaded.contains(&nei_index) {
- continue;
- }
- let mut psb = 0;
- let psb_rec = nei_elem.psbs;
- cur_elem.get_psbs_vec().into_iter().for_each(|p| {
- psb |= self.conn_rules[p as usize][dir];
- });
- nei_elem.psbs &= psb;
- if nei_elem.psbs.count_ones() == 0 {
- self.retrace();
- return;
- }
- if nei_elem.psbs != psb_rec {
- queue.push_back(nei_index);
- let new_psbs = nei_elem.psbs.count_ones() as u8;
- self.update_entropy(psb_rec.count_ones() as u8, new_psbs as u8, nei_index);
- }
- }
- }
- self.retrace_strength = 1;
- }
- pub fn update_entropy(&mut self, old: u8, new: u8, target: UVec2) {
- self.uncollapsed.remove(&(old, target));
- self.uncollapsed.insert((new, target));
- }
- pub fn retrace(&mut self) {
- let hist = {
- let hist_len = self.history.len();
- let strength = self.retrace_strength as usize;
- if hist_len <= strength {
- // max retrace time exceeded
- self.retraced_time = self.max_retrace_time;
- } else {
- if self.cur_hist >= strength {
- self.cur_hist -= strength;
- } else {
- // need to wrap around
- let hist_to_be = hist_len - (strength - self.cur_hist);
- if self.history[hist_to_be].is_none() {
- // retrace failed
- self.retraced_time = self.max_retrace_time;
- } else {
- self.cur_hist = hist_to_be;
- }
- }
- }
- // in case the cur_hist is 0
- self.history[(self.cur_hist + hist_len - 1) % hist_len]
- .clone()
- .unwrap()
- };
- self.remaining = hist.remaining;
- self.uncollapsed = hist.uncollapsed;
- self.elements = hist.elements;
- self.retraced_time += self.retrace_strength;
- }
- pub fn get_min(&mut self) -> UVec2 {
- let mut min_entropy = u8::MAX;
- let mut candidates = Vec::with_capacity(self.remaining);
- self.uncollapsed.iter().for_each(|(entropy, index)| {
- if entropy < &min_entropy {
- min_entropy = *entropy;
- candidates.clear();
- candidates.push(*index);
- } else if entropy == &min_entropy {
- candidates.push(*index);
- }
- });
- candidates[self.rng.sample(Uniform::new(0, candidates.len()))]
- }
- pub fn generate_data(&mut self) -> Option<WfcData> {
- if self.retraced_time >= self.max_retrace_time {
- return None;
- }
- let mut data = WfcData::new(self.area);
- self.elements.drain().for_each(|(i, e)| {
- data.set(i, e.element_index.unwrap());
- });
- Some(data)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement