Started to document the Grammar modules
Getty Ritter
6 years ago
3 | 3 | use std::hash::Hash; |
4 | 4 | use rand::{Rng, thread_rng}; |
5 | 5 | |
6 | /// Our indices here are two 32-bit signed values. | |
6 | 7 | type Index = (i32, i32); |
8 | /// A `SparseBoard` here is a board that may or may not have every | |
9 | /// tile filled in, which we represent as a hashmap from indices to | |
10 | /// cells. When we use a `SparseBoard` as the LHS of a rule, we try to | |
11 | /// match every cell provided, but don't bother matching the cells | |
12 | /// which aren't provided; when we use one as the RHS of a rule, we | |
13 | /// instead overwrite only those cells provided in the board. | |
14 | /// | |
15 | /// A `SparseBoard` has a conceptual center, which is the cell at | |
16 | /// index `(0, 0)`. Indices in a `SparseBoard` can be negative. | |
17 | type SparseBoard<Cell> = HashMap<Index, Cell>; | |
7 | 18 | |
19 | /// The most important parts of a `Rule` are its LHS and its | |
20 | /// RHS. These correspond respectively to the patterns which are | |
21 | /// matched, and the cells that are used to replace those | |
22 | /// patterns. Note that both of these are sparse boards: a pattern may | |
23 | /// be an arbitrary shape, and its replacement may replace all, some, | |
24 | /// or none of the cells matched by the LHS. | |
8 | 25 | pub struct Rule<Cell> { |
9 | 26 | pub rule_name: Option<String>, |
10 | 27 | pub requires: HashSet<Cell>, |
11 | pub lhs: HashMap<Index, Cell>, | |
12 | pub rhs: HashMap<Index, Cell>, | |
28 | pub lhs: SparseBoard<Cell>, | |
29 | pub rhs: SparseBoard<Cell>, | |
13 | 30 | } |
14 | 31 | |
15 | 32 | pub struct Board<Cell> { |
82 | 99 | } |
83 | 100 | |
84 | 101 | impl<Cell: Clone + Hash + Eq> Rule<Cell> { |
102 | /// Create a new `Rule` from two sparse grids of cells, | |
103 | /// corresponding respectively to the LHS and the RHS | |
85 | 104 | pub fn new( |
86 | lhs: HashMap<Index, Cell>, | |
87 | rhs: HashMap<Index, Cell>, | |
105 | lhs: SparseBoard<Cell>, | |
106 | rhs: SparseBoard<Cell>, | |
88 | 107 | ) -> Rule<Cell> { |
89 | 108 | let rule_name = None; |
90 | 109 | let requires = lhs.values().cloned().collect(); |
91 | 110 | Rule { rule_name, requires, lhs, rhs } |
92 | 111 | } |
93 | 112 | |
113 | /// Get mutable access to the LHS of the `Rule`, for modification | |
114 | /// later | |
115 | pub fn lhs_mut(&mut self) -> &mut SparseBoard<Cell> { | |
116 | &mut self.lhs | |
117 | } | |
118 | ||
119 | /// Get mutable access to the RHS of the `Rule`, for modification | |
120 | /// later | |
121 | pub fn rhs_mut(&mut self) -> &mut SparseBoard<Cell> { | |
122 | &mut self.lhs | |
123 | } | |
124 | ||
125 | /// Attempt to apply this rule to the provided board at random | |
126 | /// (i.e. if there are multiple possible applications of this | |
127 | /// rule, then it should choose one of them entirely at random | |
94 | 128 | pub fn apply_to_board(&self, b: &mut Board<Cell>) -> bool { |
129 | // for each random location in the board | |
95 | 130 | 'outer: for (x, y) in b.random_indices() { |
131 | // find out whether each of our tiles matche | |
96 | 132 | for (&(i, j), v) in self.lhs.iter() { |
133 | // if it doesn't, then skip ahead | |
97 | 134 | match b.get((x + i, y + j)) { |
98 | 135 | Some(r) if v == r => (), |
99 | 136 | _ => continue 'outer, |
100 | 137 | } |
101 | 138 | } |
102 | 139 | |
140 | // if all of them match, then do the rewrites! | |
103 | 141 | for (&(i, j), r) in self.rhs.iter() { |
104 | 142 | b[(x + i, y + j)] = r.clone(); |
105 | 143 | } |
106 | 144 | |
145 | // and because the rule applied, we can quit now | |
107 | 146 | return true; |
108 | 147 | } |
148 | // if we've tried them all and none of them worked, then we've | |
149 | // failed | |
109 | 150 | false |
110 | 151 | } |
111 | 152 | } |
112 | 153 | |
113 | 154 | |
155 | #[cfg(test)] | |
156 | #[test] | |
114 | 157 | pub fn grammar_test() { |
115 | 158 | let rule1: Rule<char> = Rule::new( |
116 | 159 | vec![ ((0, 0), 'x') ].into_iter().collect(), |
122 | 165 | ); |
123 | 166 | let mut board = Board::new(8, 8, '.'); |
124 | 167 | board[(2, 2)] = 'x'; |
125 | let _ = rule1.apply_to_board(&mut board); | |
126 | let _ = rule2.apply_to_board(&mut board); | |
168 | assert!(true, rule1.apply_to_board(&mut board)); | |
169 | assert!(true, rule2.apply_to_board(&mut board)); | |
127 | 170 | board.print(); |
128 | 171 | } |