1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
extern crate wfc;
extern crate coord_2d;

use std::collections::HashSet;

use rand::Rng;
use coord_2d::Coord;

use wfc::{ForbidPattern, Wrap, PatternId, ForbidInterface};

use crate::tile_pattern::TilePattern;

/// Used to prevent wrapping on the edges in the result
/// 
/// 
/// # Examples
/// A fully functional example can be found under `examples/anchor.rs`
/// ```
/// let pattern = TilePattern::from_csv(input_path, 
///     NonZeroU32::new(pattern_size).unwrap(), 
///     &[Orientation::Original]).expect("Error while creating pattern");
/// 
/// let forbid = ForceBorderForbid::new(&pattern, pattern_size);
/// let grid = pattern.run_collapse(output_size, attempts,
///  WrapXY, forbid, &mut rand::thread_rng()).expect("Error in WFC");
/// ```
pub struct ForceBorderForbid {
    pattern_ids: HashSet<PatternId>,
    offset: i32,
}

impl ForbidPattern for ForceBorderForbid {
    fn forbid<W: Wrap, R: Rng>(&mut self, fi: &mut ForbidInterface<W>, rng: &mut R) {
        let output_size = fi.wave_size();
        (0..(output_size.width() as i32))
            .map(|x| Coord::new(x, output_size.height() as i32 - self.offset as i32))
            .chain(
                (0..(output_size.width() as i32)).map(|y| {
                    Coord::new(output_size.width() as i32 - self.offset as i32, y)
                }),
            )
            .for_each(|coord| {
                self.pattern_ids.iter().for_each(|&pattern_id| {
                    fi.forbid_all_patterns_except(coord, pattern_id, rng)
                        .unwrap();
                });
            });
    }
}
impl ForceBorderForbid {
    pub fn new(pattern: &TilePattern, pattern_size: u32) -> ForceBorderForbid{
        let input_size = pattern.overlapping_patterns.grid().size();
        let bottom_right_offset = pattern_size - (pattern_size / 2);
        let id_grid = pattern.overlapping_patterns.id_grid();
        let bottom_right_coord = Coord::new(
            input_size.width() as i32 - bottom_right_offset as i32,
            input_size.height() as i32 - bottom_right_offset as i32,
        );
        let bottom_right_ids = id_grid
            .get_checked(bottom_right_coord)
            .iter()
            .cloned()
            .collect::<HashSet<_>>();
        return ForceBorderForbid {
            pattern_ids: bottom_right_ids,
            offset: bottom_right_offset as i32,
        };
    }
}