gdritter repos palladio / 92ccad7
Started to document the Grammar modules Getty Ritter 5 years ago
1 changed file(s) with 49 addition(s) and 6 deletion(s). Collapse all Expand all
33 use std::hash::Hash;
44 use rand::{Rng, thread_rng};
55
6 /// Our indices here are two 32-bit signed values.
67 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>;
718
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.
825 pub struct Rule<Cell> {
926 pub rule_name: Option<String>,
1027 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>,
1330 }
1431
1532 pub struct Board<Cell> {
8299 }
83100
84101 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
85104 pub fn new(
86 lhs: HashMap<Index, Cell>,
87 rhs: HashMap<Index, Cell>,
105 lhs: SparseBoard<Cell>,
106 rhs: SparseBoard<Cell>,
88107 ) -> Rule<Cell> {
89108 let rule_name = None;
90109 let requires = lhs.values().cloned().collect();
91110 Rule { rule_name, requires, lhs, rhs }
92111 }
93112
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
94128 pub fn apply_to_board(&self, b: &mut Board<Cell>) -> bool {
129 // for each random location in the board
95130 'outer: for (x, y) in b.random_indices() {
131 // find out whether each of our tiles matche
96132 for (&(i, j), v) in self.lhs.iter() {
133 // if it doesn't, then skip ahead
97134 match b.get((x + i, y + j)) {
98135 Some(r) if v == r => (),
99136 _ => continue 'outer,
100137 }
101138 }
102139
140 // if all of them match, then do the rewrites!
103141 for (&(i, j), r) in self.rhs.iter() {
104142 b[(x + i, y + j)] = r.clone();
105143 }
106144
145 // and because the rule applied, we can quit now
107146 return true;
108147 }
148 // if we've tried them all and none of them worked, then we've
149 // failed
109150 false
110151 }
111152 }
112153
113154
155 #[cfg(test)]
156 #[test]
114157 pub fn grammar_test() {
115158 let rule1: Rule<char> = Rule::new(
116159 vec![ ((0, 0), 'x') ].into_iter().collect(),
122165 );
123166 let mut board = Board::new(8, 8, '.');
124167 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));
127170 board.print();
128171 }