Skip to main content

fyrox_autotile/
wave.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Wave function collapse algorithm based upon [fast-wfc](https://github.com/math-fehr/fast-wfc).
22
23use std::{
24    error::Error,
25    fmt::Display,
26    ops::{Deref, DerefMut},
27};
28
29use super::*;
30
31type Entropy = f64;
32
33/// A `WavePosition` is like an `OffsetPosition` but it also has a counter type
34/// that the wave propagator can use to keep count of how many possible matching
35/// patterns are available from each `Offset`.
36pub trait WavePosition: OffsetPosition {
37    /// The type that holds count of patterns in each direction.
38    type Counter: WaveOffsetCounter<Offset = Self::Offset>;
39}
40
41impl WavePosition for Vector2<i32> {
42    type Counter = Vector2OffsetCounter;
43}
44
45/// A trait for counting types that store a `usize` for each of the offsets from
46/// some `OffsetPosition` type. During the wave function collapse process, these
47/// counts can be reduced as adjacent patterns possibilities are removed so
48/// that the algorithm can keep track of how many ways a pattern is possible.
49/// For a pattern to be possible, it must match some possible pattern in all
50/// offsets, so if any of these counts become 0 the algorithm will know to
51/// remove the corresponding pattern.
52pub trait WaveOffsetCounter: Default + Clone {
53    /// The type that will be the index into the array of `usize` counts.
54    type Offset;
55    /// The count for the given offset.
56    fn count(&self, offset: &Self::Offset) -> usize;
57    /// The count for the given offset.
58    fn count_mut(&mut self, offset: &Self::Offset) -> &mut usize;
59}
60
61/// A [`WaveOffsetCounter`] for `Vector3` offsets, containing 4 `usize` values,
62/// one for each adjacent cell of a pattern in 2D.
63#[derive(Debug, Clone, Default)]
64pub struct Vector2OffsetCounter([usize; 4]);
65
66impl WaveOffsetCounter for Vector2OffsetCounter {
67    type Offset = Vector2Offset;
68
69    fn count(&self, offset: &Vector2Offset) -> usize {
70        self.0[offset.0]
71    }
72
73    fn count_mut(&mut self, offset: &Vector2Offset) -> &mut usize {
74        &mut self.0[offset.0]
75    }
76}
77
78impl WavePosition for Vector3<i32> {
79    type Counter = Vector3OffsetCounter;
80}
81
82/// A [`WaveOffsetCounter`] for `Vector3` offsets, containing 6 `usize` values,
83/// one for each adjacent cell of a pattern in 3D.
84#[derive(Debug, Clone, Default)]
85pub struct Vector3OffsetCounter([usize; 6]);
86
87impl WaveOffsetCounter for Vector3OffsetCounter {
88    type Offset = Vector3Offset;
89
90    fn count(&self, offset: &Vector3Offset) -> usize {
91        self.0[offset.0]
92    }
93
94    fn count_mut(&mut self, offset: &Vector3Offset) -> &mut usize {
95        &mut self.0[offset.0]
96    }
97}
98
99/// Trait for an object that specifies the rules by which wave function collapse
100/// tiles are chosen.
101pub trait WfcConstrain {
102    /// The offset type that is used to specify the ways in which one pattern
103    /// may be adjacent to another pattern.
104    type Offset;
105    /// The type of patterns that wave function collapse will choose.
106    type Pattern: Eq + Hash + Clone;
107    /// Iterator for all the patterns that wave function collapse is allowed to choose.
108    /// Note that any pattern with a probability of 0.0 must not be included.
109    fn all_patterns(&self) -> impl Iterator<Item = &Self::Pattern>;
110    /// The probability of choosing a given pattern when there are no restrictions on patterns
111    /// in any of the adjacent cells. This should be between 0.0 and 1.0.
112    fn probability_of(&self, pattern: &Self::Pattern) -> f32;
113    /// True if the `from` pattern may be chosen when the `to` pattern has already been chosen
114    /// for the cell at position `offset` relative to `from`.
115    fn is_legal(&self, from: &Self::Pattern, offset: &Self::Offset, to: &Self::Pattern) -> bool;
116}
117
118/// An implementation for `WfcConstrain` that stores the information for each pattern
119/// in a hash table and also keeps track of a which values each pattern may represent,
120/// so that patterns may be translated into tiles after wave function collapse is complete.
121pub struct HashWfcConstraint<Pat, V> {
122    pattern_map: FxHashMap<Pat, WfcPatternConstraint<V>>,
123}
124
125/// The data for a pattern, with probability of the pattern
126/// and probability of each tile that matches the pattern.
127struct WfcPatternConstraint<V> {
128    /// The probability of the pattern being chosen, between 0.0 and 1.0.
129    probability: f32,
130    /// The set of values that may be randomly chosen to represent the pattern
131    /// when patterns are converted into tiles.
132    value_set: ProbabilitySet<V>,
133}
134
135impl<V> Default for WfcPatternConstraint<V> {
136    fn default() -> Self {
137        Self {
138            probability: 0.0,
139            value_set: ProbabilitySet::default(),
140        }
141    }
142}
143
144impl<Pat, V> Default for HashWfcConstraint<Pat, V> {
145    fn default() -> Self {
146        Self {
147            pattern_map: FxHashMap::default(),
148        }
149    }
150}
151
152impl<Pat, V> HashWfcConstraint<Pat, V>
153where
154    Pat: Eq + Hash,
155{
156    /// True if this constraint contains no patterns.
157    pub fn is_empty(&self) -> bool {
158        self.pattern_map.is_empty()
159    }
160    /// Remove all data, reseting this object to empty so it is ready
161    /// to be reused with new pattern data.
162    pub fn clear(&mut self) {
163        self.pattern_map.clear();
164    }
165    /// Add a new value to the data with the given pattern and frequency.
166    /// The frequency does not need to be between 0.0 and 1.0.
167    /// Frequencies of 0.0 or less will be silently ignored, and
168    /// frequencies will be automatically normalized into probabilities
169    /// when [`finalize`](Self::finalize) is called.
170    pub fn add(&mut self, pattern: Pat, frequency: f32, value: V)
171    where
172        Pat: Debug,
173        V: Debug,
174    {
175        if frequency <= 0.0 {
176            return;
177        }
178        self.pattern_map
179            .entry(pattern)
180            .or_default()
181            .value_set
182            .add(frequency, value);
183    }
184    /// Calculate the probability of each pattern based on the frequencies
185    /// of all values that were added with [`add`](Self::add).
186    /// The sum of the frequencies is calculated and then each frequency is
187    /// divided by the sum to normalize the frequencies into probabilities between
188    /// 0.0 and 1.0.
189    pub fn finalize(&mut self) {
190        let sum: f32 = self
191            .pattern_map
192            .values()
193            .map(|v| v.value_set.total_frequency())
194            .sum();
195        if sum > 0.0 {
196            for v in self.pattern_map.values_mut() {
197                v.probability = v.value_set.total_frequency() / sum;
198            }
199        }
200    }
201    /// Calculate the probability of each pattern based on the frequencies
202    /// of all values that were added with [`add`](Self::add).
203    /// Divide the frequency of each pattern by the total number of patterns
204    /// in that pattern's terrain so that terrains with many patterns are not
205    /// given an advantage over terrains with few patterns.
206    /// The `terrain` function is used to determine the terrain of each pattern.
207    /// The sum of the frequencies is calculated and then each frequency is
208    /// divided by the sum to normalize the frequencies into probabilities between
209    /// 0.0 and 1.0.
210    pub fn finalize_with_terrain_normalization<Ter, F>(&mut self, terrain: F)
211    where
212        Ter: Hash + Eq,
213        F: Fn(&Pat) -> Ter,
214    {
215        let mut terrain_count = FxHashMap::<Ter, usize>::default();
216        for p in self.pattern_map.keys() {
217            *terrain_count.entry(terrain(p)).or_default() += 1;
218        }
219        let sum: f32 = self
220            .pattern_map
221            .iter()
222            .map(|(p, v)| {
223                let count = terrain_count.get(&terrain(p)).copied().unwrap_or_default() as f32;
224                if count > 0.0 {
225                    v.value_set.total_frequency() / count
226                } else {
227                    1.0
228                }
229            })
230            .sum();
231        if sum > 0.0 {
232            for v in self.pattern_map.values_mut() {
233                v.probability = v.value_set.total_frequency() / sum;
234            }
235        }
236    }
237    /// A random value that matches the given pattern, based upon previous calls to
238    /// [`add`](Self::add). Often there may be more than one tile that matches a particular
239    /// pattern, and so this method helps with the final step after wave function collapse:
240    /// converting the chosen patterns into actual tiles.
241    pub fn get_random<R: Rng + ?Sized>(&self, rng: &mut R, pattern: &Pat) -> Option<&V> {
242        self.pattern_map.get(pattern)?.value_set.get_random(rng)
243    }
244}
245
246impl<Pat, V> WfcConstrain for HashWfcConstraint<Pat, V>
247where
248    Pat: Eq + Hash + Clone + TilePattern,
249{
250    type Offset = Pat::Offset;
251    type Pattern = Pat;
252
253    fn all_patterns(&self) -> impl Iterator<Item = &Self::Pattern> {
254        self.pattern_map.keys()
255    }
256
257    fn probability_of(&self, pattern: &Self::Pattern) -> f32 {
258        self.pattern_map
259            .get(pattern)
260            .map(|s| s.probability)
261            .unwrap_or_default()
262    }
263
264    fn is_legal(&self, from: &Self::Pattern, offset: &Self::Offset, to: &Self::Pattern) -> bool {
265        from.is_legal(offset, to)
266    }
267}
268
269#[derive(Debug, Clone)]
270struct Wave<Pos: WavePosition, Pat>(FxHashMap<Pos, WaveCell<Pos::Counter, Pat>>);
271
272impl<K: WavePosition, P> Default for Wave<K, P> {
273    fn default() -> Self {
274        Self(FxHashMap::default())
275    }
276}
277
278impl<Pos: WavePosition, Pat> Deref for Wave<Pos, Pat> {
279    type Target = FxHashMap<Pos, WaveCell<Pos::Counter, Pat>>;
280
281    fn deref(&self) -> &Self::Target {
282        &self.0
283    }
284}
285
286impl<Pos: WavePosition, Pat> DerefMut for Wave<Pos, Pat> {
287    fn deref_mut(&mut self) -> &mut Self::Target {
288        &mut self.0
289    }
290}
291
292#[derive(Debug, Clone)]
293struct WaveCell<Count, Pat> {
294    /// The possible patterns, each with a count of the possible patterns in other
295    /// cells that make this pattern possible.
296    pattern_possibilities: FxHashMap<Pat, Count>,
297    /// The sum of p(P) * log(p(P)) for all possible patterns P in the cell.
298    plogp_sum: Entropy,
299    /// The sum of p(P) for all possible patterns P in the cell.
300    sum: Entropy,
301    /// The log of `sum`.
302    log_sum: Entropy,
303    /// The entropy of the cell
304    entropy: Entropy,
305}
306
307impl<Count, Pat> Default for WaveCell<Count, Pat> {
308    fn default() -> Self {
309        Self {
310            pattern_possibilities: FxHashMap::default(),
311            plogp_sum: 0.0,
312            sum: 0.0,
313            log_sum: 0.0,
314            entropy: 0.0,
315        }
316    }
317}
318
319impl<Count, Pat> WaveCell<Count, Pat> {
320    pub fn single_pattern(&self) -> Option<&Pat> {
321        let mut keys = self.pattern_possibilities.keys();
322        let pat = keys.next();
323        if keys.next().is_none() {
324            pat
325        } else {
326            None
327        }
328    }
329}
330
331/// Statistical information derived from a [`WfcConstrain`] object.
332/// A  `WaveLimits` object is only valid for a particular `WfcConstrain` object
333/// so long as the output of the `WfcConstrain` object's methods do not change.
334#[derive(Debug, Clone)]
335struct WaveLimits<Count, Pat> {
336    max_cell: WaveCell<Count, Pat>,
337    plogp_map: FxHashMap<Pat, Entropy>,
338    maximum_noise: Entropy,
339}
340
341impl<Count, Pat> Default for WaveLimits<Count, Pat> {
342    fn default() -> Self {
343        Self {
344            max_cell: WaveCell::default(),
345            plogp_map: FxHashMap::default(),
346            maximum_noise: 0.0,
347        }
348    }
349}
350
351impl<Count: WaveOffsetCounter, Pat: Clone + Hash + Eq> WaveLimits<Count, Pat> {
352    /// Use the data in a [`WfcConstrain`] object to initialize the limits
353    /// for a new wave function collapse using the given constraint.
354    pub fn fill_from<
355        Pos: WavePosition<Counter = Count, Offset = Count::Offset>,
356        Con: WfcConstrain<Pattern = Pat, Offset = Count::Offset>,
357    >(
358        &mut self,
359        constraint: &Con,
360    ) {
361        self.plogp_map.clear();
362        let mut plogp_sum = 0.0;
363        let mut sum = 0.0;
364        let mut min_abs_plogp = Entropy::INFINITY;
365        self.max_cell.pattern_possibilities.clear();
366        for pattern in constraint.all_patterns() {
367            let p = constraint.probability_of(pattern) as Entropy;
368            let plogp = p * p.ln();
369            self.plogp_map.insert(pattern.clone(), plogp);
370            let abs_plogp = plogp.abs();
371            if abs_plogp < min_abs_plogp {
372                min_abs_plogp = abs_plogp;
373            }
374            plogp_sum += plogp;
375            sum += p;
376            let mut count = Count::default();
377            for offset in Pos::all_offsets() {
378                *count.count_mut(&offset) = constraint
379                    .all_patterns()
380                    .filter(|p| constraint.is_legal(p, &offset, pattern))
381                    .count();
382            }
383            self.max_cell
384                .pattern_possibilities
385                .insert(pattern.clone(), count);
386        }
387        let log_sum = sum.log10();
388        self.max_cell.plogp_sum = plogp_sum;
389        self.max_cell.sum = sum;
390        self.max_cell.log_sum = log_sum;
391        self.max_cell.entropy = log_sum - plogp_sum / sum;
392        self.maximum_noise = min_abs_plogp / 2.0;
393    }
394}
395
396/// Wave function collapse is a multi-step that may require a significant amount of time,
397/// depending on how may cells need to be filled. `WfcControlFlow` allows wave propagation
398/// methods to specify in their return value whether they have completed their task or whether
399/// further work is required. This allows the user to spread the wave function collapse
400/// across multiple method calls so it can be mixed with other work or even aborted.
401#[derive(Debug, Clone, Copy, Eq, PartialEq)]
402pub enum WfcControlFlow {
403    /// More work is required.
404    Continue,
405    /// The method has finished whatever it was trying to do.
406    Finish,
407}
408
409/// Wave function collapse failed to find a solution. Due to the randomization of the algorithm,
410/// a failed attempt does not necessarily indicate a problem, but may instead be due to chance.
411/// Another attempt my succeed where a previous one failed.
412#[derive(Debug)]
413pub struct WfcFailure;
414
415impl Error for WfcFailure {}
416
417impl Display for WfcFailure {
418    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419        f.write_str("Wave function collapse failed to find a solution.")
420    }
421}
422
423/// The propagator is responsible for the wave function collapse algorithm and
424/// it contains all the necessary data except for the [`WfcConstrain`] object
425/// that contains the rules for which patterns may be chosen.
426///
427/// The contraint object is not owned by the propagator because the wave function
428/// collapse algorithm may be spread out across many steps and it may be necessary
429/// for the constraint object to not live as long as the propagator, and be
430/// reconstructed at each step.
431///
432/// Every constraint object at each step should always fully agree with the constraint
433/// objects at all previous steps, or else the algorithm may produce undesired results.
434#[derive(Debug, Default, Clone)]
435pub struct WfcPropagator<Pos: WavePosition, Pat> {
436    limits: WaveLimits<Pos::Counter, Pat>,
437    wave: Wave<Pos, Pat>,
438    propagating: Vec<(Pos, Pat)>,
439    pending: Vec<(Pos, Pat)>,
440    backtrack_cells: Vec<WaveCell<Pos::Counter, Pat>>,
441    backtrack_map: FxHashMap<Pos, WaveCell<Pos::Counter, Pat>>,
442}
443
444impl<Pos: WavePosition + Debug, Pat: Clone + Hash + Eq + Debug> WfcPropagator<Pos, Pat> {
445    /// This propagator contains no cells.
446    pub fn is_empty(&self) -> bool {
447        self.wave.is_empty()
448    }
449    /// An iterator over the positions of every cell of the wave.
450    pub fn positions(&self) -> impl Iterator<Item = &Pos> {
451        self.wave.keys()
452    }
453    /// True if the wave has a cell at the given position.
454    pub fn contains_cell(&self, position: &Pos) -> bool {
455        self.wave.contains_key(position)
456    }
457    /// Iterator over the cells that have been given a pattern by the wave function collapse.
458    pub fn assigned_patterns(&self) -> impl Iterator<Item = (&Pos, &Pat)> {
459        self.wave
460            .iter()
461            .filter_map(|(p, c)| Some((p, c.single_pattern()?)))
462    }
463    /// Use the data in a [`WfcConstrain`] object to initialize the propagator
464    /// for a new wave function collapse using the given constraint.
465    /// After calling this method, the next step is to call [`add_cell`](Self::add_cell) for each
466    /// cell that needs to be filled by wave function collapse.
467    pub fn fill_from<Con: WfcConstrain<Pattern = Pat, Offset = <Pos as OffsetPosition>::Offset>>(
468        &mut self,
469        constraint: &Con,
470    ) {
471        self.limits.fill_from::<Pos, Con>(constraint);
472        self.wave.clear();
473        self.propagating.clear();
474    }
475    /// Create a new cell at the given position, assuming that wave function collapse has not yet begun
476    /// and all the surrounding cells have no restrictions.
477    /// Calling this after [`restrict_edge`](Self::restrict_edge), [`observe_random_cell`](Self::observe_random_cell),
478    /// or [`observe_all`](Self::observe_all) may produce undesirable consequences.
479    /// After all the cells have been added, the next step is to optionally call `restrict_edge` to constrain which patterns
480    /// the may be put into the border cells.
481    pub fn add_cell(&mut self, position: Pos) {
482        let _ = self.wave.insert(position, self.limits.max_cell.clone());
483    }
484    fn save_cell(&mut self, position: Pos) {
485        if let Entry::Vacant(entry) = self.backtrack_map.entry(position.clone()) {
486            let Some(cell) = self.wave.get(&position) else {
487                return;
488            };
489            let mut backtrack_cell = self.backtrack_cells.pop().unwrap_or_default();
490            backtrack_cell.clone_from(cell);
491            entry.insert(backtrack_cell);
492        }
493    }
494    fn clear_backtrack(&mut self) {
495        for (_, backtrack_cell) in self.backtrack_map.drain() {
496            self.backtrack_cells.push(backtrack_cell);
497        }
498    }
499    fn backtrack(&mut self) {
500        for (pos, backtrack_cell) in self.backtrack_map.drain() {
501            let Some(cell) = self.wave.get_mut(&pos) else {
502                continue;
503            };
504            cell.clone_from(&backtrack_cell);
505            self.backtrack_cells.push(backtrack_cell);
506        }
507    }
508    /// Randomly choose a low-entropy cell. This is used by [`observe_random_cell`](Self::observe_random_cell)
509    /// to decide which cell will be observed.
510    pub fn find_min_entropy<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<Pos>
511    where
512        Pos::Counter: Debug,
513    {
514        let mut min_pos = None;
515        let mut min_entropy = Entropy::INFINITY;
516        for (position, cell) in self.wave.iter() {
517            if cell.pattern_possibilities.len() <= 1 || cell.entropy >= min_entropy {
518                continue;
519            }
520            let noise = rng.gen_range(0.0..=self.limits.maximum_noise);
521            let entropy = cell.entropy + noise;
522            if entropy < min_entropy {
523                min_entropy = entropy;
524                min_pos = Some(position.clone());
525            }
526        }
527        min_pos
528    }
529    /// Choose a random pattern from among the potential patterns for the given cell based
530    /// on probabilities given in `constraint`. This is called by
531    /// [`observe_random_cell`](Self::observe_random_cell) to decide which pattern to assign.
532    pub fn choose_random_pattern<R, Con>(
533        &self,
534        position: &Pos,
535        rng: &mut R,
536        constraint: &Con,
537    ) -> Option<Pat>
538    where
539        R: Rng + ?Sized,
540        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
541    {
542        let cell = self.wave.get(position)?;
543        let mut target = rng.gen_range(0.0..cell.sum);
544        for pattern in cell.pattern_possibilities.keys() {
545            let p = constraint.probability_of(pattern) as Entropy;
546            target -= p;
547            if target <= 0.0 {
548                return Some(pattern.clone());
549            }
550        }
551        cell.pattern_possibilities.keys().next().cloned()
552    }
553    /// Constrain the cells around the given position based on the assumption that the given
554    /// position has the given pattern. Calling this method twice on the same position may put
555    /// the surrounding cells into an invalid state, even if both calls have the same pattern.
556    /// This should be called after all cells have been added using [`add_cell`](Self::add_cell),
557    /// and there should be no cell at the given position.
558    ///
559    /// The next step is to call [`observe_random_cell`](Self::observe_random_cell) or
560    /// [`observe_all`](Self::observe_all) to begin collapsing the wave function.
561    pub fn restrict_edge<Con>(
562        &mut self,
563        position: &Pos,
564        pattern: &Pat,
565        constraint: &Con,
566    ) -> Result<(), WfcFailure>
567    where
568        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
569        Pos: Debug,
570    {
571        for offset in Pos::all_offsets() {
572            let other_pos = position.clone() + offset.clone();
573            let Some(other_cell) = self.wave.get_mut(&other_pos) else {
574                continue;
575            };
576            other_cell
577                .pattern_possibilities
578                .retain(|other_pattern, _counter| {
579                    if !constraint.is_legal(pattern, &offset, other_pattern) {
580                        self.pending
581                            .push((other_pos.clone(), other_pattern.clone()));
582                        false
583                    } else {
584                        true
585                    }
586                });
587            if other_cell.pattern_possibilities.is_empty() {
588                return Err(WfcFailure);
589            }
590        }
591        Ok(())
592    }
593    fn set_cell<Con>(
594        &mut self,
595        position: &Pos,
596        pattern: &Pat,
597        constraint: &Con,
598    ) -> Result<(), WfcFailure>
599    where
600        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
601    {
602        let cell = self.wave.get_mut(position).expect("Missing wave cell");
603        let mut possibilities = std::mem::take(&mut cell.pattern_possibilities);
604        let (pattern, count) = possibilities
605            .remove_entry(pattern)
606            .expect("Missing pattern");
607        for (p, _) in possibilities.drain() {
608            self.after_restrict(position, &p, constraint)?;
609        }
610        possibilities.insert(pattern, count);
611        let cell = self.wave.get_mut(position).unwrap();
612        cell.pattern_possibilities = possibilities;
613        self.verify(position, constraint)
614    }
615    /// Completely collapse the wave function. This method repeatedly observes a random cell and
616    /// propagates each observation until all cells have been observed or the wave function collapse
617    /// fails due to not being able to find a valid pattern for some cell.
618    ///
619    /// If the number of cells is large, this method may be slow. Use [`observe_random_cell`](Self::observe_random_cell)
620    /// to progress the collapse one cell at a time and thereby have more control over the process
621    /// and allow the possibility of aborting.
622    pub fn observe_all<R, Con>(&mut self, rng: &mut R, constraint: &Con) -> Result<(), WfcFailure>
623    where
624        R: Rng + ?Sized,
625        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
626        Pos: Debug,
627        Pos::Counter: Debug,
628    {
629        while self.observe_random_cell(rng, constraint)? == WfcControlFlow::Continue {}
630        Ok(())
631    }
632    /// Observing a cell means choosing a random pattern for that cell from all the potential patterns
633    /// for that particular cell. Each cell keeps its own independent list of possible patterns,
634    /// and after a cell has been observed the possibilities for the surrounding cells may need to be
635    /// restricted. The restriction of the surrounding cells is called *propagation* and it should be
636    /// performed after each observation by calling [`propagate`](Self::propagate) or
637    /// [`propagate_until_finished`](Self::propagate_until_finished).
638    ///
639    /// If propagation is not complete when this method is called, then `propagate_until_finished` is
640    /// automatically called before the cell is observed.
641    ///
642    /// [`WfcControlFlow::Continue`] is returned if a cell was successfully observed, meaning that propagation
643    /// and more observations may be required to complete the collapse.
644    /// [`WfcControlFlow::Finish`] is returned if no cell could be observed because the pattern for all
645    /// cells has already been determined and the wave function collapse is complete.
646    pub fn observe_random_cell<R, Con>(
647        &mut self,
648        rng: &mut R,
649        constraint: &Con,
650    ) -> Result<WfcControlFlow, WfcFailure>
651    where
652        R: Rng + ?Sized,
653        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
654        Pos: Debug,
655        Pos::Counter: Debug,
656    {
657        self.propagate_until_finished(constraint)?;
658        let Some(position) = self.find_min_entropy(rng) else {
659            return Ok(WfcControlFlow::Finish);
660        };
661        let pattern = self
662            .choose_random_pattern(&position, rng, constraint)
663            .unwrap();
664        self.save_cell(position.clone());
665        for offset in Pos::all_offsets() {
666            let p = position.clone() + offset;
667            self.save_cell(p);
668        }
669        match self.set_cell(&position, &pattern, constraint) {
670            Ok(()) => {
671                self.clear_backtrack();
672                self.propagating.append(&mut self.pending);
673            }
674            Err(_) => {
675                self.backtrack();
676                self.pending.clear();
677                self.restrict(&position, &pattern, constraint)?;
678                self.propagating.append(&mut self.pending);
679            }
680        }
681        Ok(WfcControlFlow::Continue)
682    }
683    /// Repeatedly call [`propagate`](Self::propagate) until it returns [`WfcControlFlow::Finish`],
684    /// thus ensuring that all the cells are prepared for the next observation. This is called
685    /// automatically by [`observe_random_cell`](Self::observe_random_cell).
686    pub fn propagate_until_finished<Con>(&mut self, constraint: &Con) -> Result<(), WfcFailure>
687    where
688        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
689    {
690        while self.propagate(constraint)? == WfcControlFlow::Continue {}
691        Ok(())
692    }
693    /// Propagate the restrictions from the most recent calls to [`observe_random_cell`](Self::observe_random_cell)
694    /// or [`restrict_edge`](Self::restrict_edge) by one step, so that appropriate restrictions are spread across
695    /// the cells of the wave. This method should be repeatedly called until it returns [`WfcControlFlow::Finish`]
696    /// before another cell is observed so that the observation is based upon an accurate list of possible patterns
697    /// for the cell.
698    pub fn propagate<Con>(&mut self, constraint: &Con) -> Result<WfcControlFlow, WfcFailure>
699    where
700        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
701    {
702        let Some((position, pattern)) = self.propagating.pop() else {
703            return Ok(WfcControlFlow::Finish);
704        };
705        self.restrict(&position, &pattern, constraint)?;
706        self.propagating.append(&mut self.pending);
707        Ok(WfcControlFlow::Continue)
708    }
709    /// The given pattern is no longer valid at the given position. Update the surrouding cells
710    /// to reflect this restriction and if any of the surrounding cells need to be restricted,
711    /// add that restriction to the propagation list for future consideration.
712    /// Return false if the restriction was impossible due to leaving the cell with no remaining
713    /// possibilities.
714    fn restrict<Con>(
715        &mut self,
716        position: &Pos,
717        pattern: &Pat,
718        constraint: &Con,
719    ) -> Result<(), WfcFailure>
720    where
721        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
722    {
723        let Some(cell) = self.wave.get_mut(position) else {
724            return Ok(());
725        };
726        match cell.pattern_possibilities.entry(pattern.clone()) {
727            Entry::Occupied(entry) => drop(entry.remove()),
728            Entry::Vacant(_) => return Ok(()),
729        }
730        match cell.pattern_possibilities.len() {
731            0 => return Err(WfcFailure),
732            1 => self.verify(position, constraint)?,
733            _ => (),
734        }
735        let Some(cell) = self.wave.get_mut(position) else {
736            return Ok(());
737        };
738        if let Some(plogp) = self.limits.plogp_map.get(pattern) {
739            let p = constraint.probability_of(pattern) as Entropy;
740            cell.plogp_sum -= plogp;
741            cell.sum -= p;
742            cell.log_sum = cell.sum.ln();
743            cell.entropy = cell.log_sum - cell.plogp_sum / cell.sum;
744            self.after_restrict(position, pattern, constraint)
745        } else {
746            Ok(())
747        }
748    }
749    fn after_restrict<Con>(
750        &mut self,
751        position: &Pos,
752        pattern: &Pat,
753        constraint: &Con,
754    ) -> Result<(), WfcFailure>
755    where
756        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
757        Pos: Debug,
758    {
759        for offset in Pos::all_offsets() {
760            let other_pos = position.clone() + offset.clone();
761            let Some(other_cell) = self.wave.get_mut(&other_pos) else {
762                continue;
763            };
764            other_cell
765                .pattern_possibilities
766                .retain(|other_pattern, counter| {
767                    if constraint.is_legal(pattern, &offset, other_pattern) {
768                        let c = counter.count_mut(&offset);
769                        *c -= 1;
770                        if *c == 0 {
771                            self.pending
772                                .push((other_pos.clone(), other_pattern.clone()));
773                        }
774                        *c > 0
775                    } else {
776                        true
777                    }
778                });
779            if other_cell.pattern_possibilities.is_empty() {
780                return Err(WfcFailure);
781            }
782        }
783        Ok(())
784    }
785    fn verify<Con>(&self, position: &Pos, constraint: &Con) -> Result<(), WfcFailure>
786    where
787        Con: WfcConstrain<Pattern = Pat, Offset = Pos::Offset>,
788    {
789        let Some(cell) = self.wave.get(position) else {
790            return Ok(());
791        };
792        let Some(pat) = cell.single_pattern() else {
793            return Ok(());
794        };
795        for offset in Pos::all_offsets() {
796            let other_pos = position.clone() + offset.clone();
797            let Some(other_cell) = self.wave.get(&other_pos) else {
798                continue;
799            };
800            if !other_cell
801                .pattern_possibilities
802                .keys()
803                .any(|p| constraint.is_legal(pat, &offset, p))
804            {
805                return Err(WfcFailure);
806            }
807        }
808        Ok(())
809    }
810}