| 1 |
use std::ops;
|
| 2 |
use std::collections::{HashMap, HashSet};
|
| 3 |
use std::hash::Hash;
|
| 4 |
use rand::{Rng, thread_rng};
|
| 5 |
|
| 6 |
type Index = (i32, i32);
|
| 7 |
|
| 8 |
pub struct Rule<Cell> {
|
| 9 |
pub rule_name: Option<String>,
|
| 10 |
pub requires: HashSet<Cell>,
|
| 11 |
pub lhs: HashMap<Index, Cell>,
|
| 12 |
pub rhs: HashMap<Index, Cell>,
|
| 13 |
}
|
| 14 |
|
| 15 |
pub struct Board<Cell> {
|
| 16 |
pub width: u32,
|
| 17 |
pub height: u32,
|
| 18 |
pub cells: Vec<Cell>,
|
| 19 |
pub contents: HashSet<Cell>,
|
| 20 |
}
|
| 21 |
|
| 22 |
impl<Cell: Clone + Hash + Eq> Board<Cell> {
|
| 23 |
pub fn new(width: u32, height: u32, default: Cell) -> Board<Cell> {
|
| 24 |
let cells = (0..width*height).map(|_| default.clone()).collect();
|
| 25 |
let contents = vec![default].into_iter().collect();
|
| 26 |
Board { width, height, cells, contents }
|
| 27 |
}
|
| 28 |
|
| 29 |
pub fn get<'a>(&'a self, (w, h): Index) -> Option<&'a Cell> {
|
| 30 |
if w > 0 && w < self.width as i32 && h > 0 && h < self.height as i32 {
|
| 31 |
Some(&self[(w, h)])
|
| 32 |
} else {
|
| 33 |
None
|
| 34 |
}
|
| 35 |
}
|
| 36 |
|
| 37 |
pub fn indices(&self) -> Vec<Index> {
|
| 38 |
let mut v = Vec::new();
|
| 39 |
for x in 0..self.width {
|
| 40 |
for y in 0..self.height {
|
| 41 |
v.push((x as i32, y as i32))
|
| 42 |
}
|
| 43 |
}
|
| 44 |
v
|
| 45 |
}
|
| 46 |
|
| 47 |
pub fn random_indices(&self) -> Vec<Index> {
|
| 48 |
let mut v = self.indices();
|
| 49 |
{
|
| 50 |
let slice = v.as_mut_slice();
|
| 51 |
thread_rng().shuffle(slice);
|
| 52 |
}
|
| 53 |
v
|
| 54 |
}
|
| 55 |
}
|
| 56 |
|
| 57 |
impl Board<char> {
|
| 58 |
pub fn print(&self) {
|
| 59 |
for x in 0..self.width {
|
| 60 |
for y in 0..self.height {
|
| 61 |
print!("{} ", self[(x as i32, y as i32)]);
|
| 62 |
}
|
| 63 |
println!("");
|
| 64 |
}
|
| 65 |
}
|
| 66 |
}
|
| 67 |
|
| 68 |
impl<Cell> ops::Index<Index> for Board<Cell> {
|
| 69 |
type Output = Cell;
|
| 70 |
|
| 71 |
fn index(&self, (w, h): Index) -> &Cell {
|
| 72 |
let n: usize = (w + (h * self.width as i32)) as usize;
|
| 73 |
&self.cells[n as usize]
|
| 74 |
}
|
| 75 |
}
|
| 76 |
|
| 77 |
impl<Cell> ops::IndexMut<Index> for Board<Cell> {
|
| 78 |
fn index_mut(&mut self, (w, h): Index) -> &mut Cell {
|
| 79 |
let n: usize = (w + (h * self.width as i32)) as usize;
|
| 80 |
&mut self.cells[n as usize]
|
| 81 |
}
|
| 82 |
}
|
| 83 |
|
| 84 |
impl<Cell: Clone + Hash + Eq> Rule<Cell> {
|
| 85 |
pub fn new(
|
| 86 |
lhs: HashMap<Index, Cell>,
|
| 87 |
rhs: HashMap<Index, Cell>,
|
| 88 |
) -> Rule<Cell> {
|
| 89 |
let rule_name = None;
|
| 90 |
let requires = lhs.values().cloned().collect();
|
| 91 |
Rule { rule_name, requires, lhs, rhs }
|
| 92 |
}
|
| 93 |
|
| 94 |
pub fn apply_to_board(&self, b: &mut Board<Cell>) -> bool {
|
| 95 |
'outer: for (x, y) in b.random_indices() {
|
| 96 |
for (&(i, j), v) in self.lhs.iter() {
|
| 97 |
match b.get((x + i, y + j)) {
|
| 98 |
Some(r) if v == r => (),
|
| 99 |
_ => continue 'outer,
|
| 100 |
}
|
| 101 |
}
|
| 102 |
|
| 103 |
for (&(i, j), r) in self.rhs.iter() {
|
| 104 |
b[(x + i, y + j)] = r.clone();
|
| 105 |
}
|
| 106 |
|
| 107 |
return true;
|
| 108 |
}
|
| 109 |
false
|
| 110 |
}
|
| 111 |
}
|
| 112 |
|
| 113 |
|
| 114 |
pub fn grammar_test() {
|
| 115 |
let rule1: Rule<char> = Rule::new(
|
| 116 |
vec![ ((0, 0), 'x') ].into_iter().collect(),
|
| 117 |
vec![ ((0, 0), 'y'), ((1, 0), 'y') ].into_iter().collect(),
|
| 118 |
);
|
| 119 |
let rule2: Rule<char> = Rule::new(
|
| 120 |
vec![ ((0, 0), 'y') ].into_iter().collect(),
|
| 121 |
vec![ ((0, 0), 'z') ].into_iter().collect(),
|
| 122 |
);
|
| 123 |
let mut board = Board::new(8, 8, '.');
|
| 124 |
board[(2, 2)] = 'x';
|
| 125 |
let _ = rule1.apply_to_board(&mut board);
|
| 126 |
let _ = rule2.apply_to_board(&mut board);
|
| 127 |
board.print();
|
| 128 |
}
|