gdritter repos palladio / master src / grammar.rs
master

Tree @master (Download .tar.gz)

grammar.rs @master

5517327
 
 
 
 
92ccad7
5517327
92ccad7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5517327
 
 
92ccad7
 
5517327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92ccad7
 
5517327
92ccad7
 
5517327
 
 
 
 
 
92ccad7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5517327
92ccad7
5517327
92ccad7
5517327
92ccad7
5517327
 
 
 
 
 
92ccad7
5517327
 
 
 
92ccad7
5517327
 
92ccad7
 
5517327
 
 
 
 
92ccad7
 
5517327
 
 
 
 
 
 
 
 
 
 
92ccad7
 
5517327
 
use std::ops;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use rand::{Rng, thread_rng};

/// Our indices here are two 32-bit signed values.
type Index = (i32, i32);
/// A `SparseBoard` here is a board that may or may not have every
/// tile filled in, which we represent as a hashmap from indices to
/// cells. When we use a `SparseBoard` as the LHS of a rule, we try to
/// match every cell provided, but don't bother matching the cells
/// which aren't provided; when we use one as the RHS of a rule, we
/// instead overwrite only those cells provided in the board.
///
/// A `SparseBoard` has a conceptual center, which is the cell at
/// index `(0, 0)`. Indices in a `SparseBoard` can be negative.
type SparseBoard<Cell> = HashMap<Index, Cell>;

/// The most important parts of a `Rule` are its LHS and its
/// RHS. These correspond respectively to the patterns which are
/// matched, and the cells that are used to replace those
/// patterns. Note that both of these are sparse boards: a pattern may
/// be an arbitrary shape, and its replacement may replace all, some,
/// or none of the cells matched by the LHS.
pub struct Rule<Cell> {
    pub rule_name: Option<String>,
    pub requires: HashSet<Cell>,
    pub lhs: SparseBoard<Cell>,
    pub rhs: SparseBoard<Cell>,
}

pub struct Board<Cell> {
    pub width: u32,
    pub height: u32,
    pub cells: Vec<Cell>,
    pub contents: HashSet<Cell>,
}

impl<Cell: Clone + Hash + Eq> Board<Cell> {
    pub fn new(width: u32, height: u32, default: Cell) -> Board<Cell> {
        let cells = (0..width*height).map(|_| default.clone()).collect();
        let contents = vec![default].into_iter().collect();
        Board { width, height, cells, contents }
    }

    pub fn get<'a>(&'a self, (w, h): Index) -> Option<&'a Cell> {
        if w > 0 && w < self.width as i32 && h > 0 && h < self.height as i32 {
            Some(&self[(w, h)])
        } else {
            None
        }
    }

    pub fn indices(&self) -> Vec<Index> {
        let mut v = Vec::new();
        for x in 0..self.width {
            for y in 0..self.height {
                v.push((x as i32, y as i32))
            }
        }
        v
    }

    pub fn random_indices(&self) -> Vec<Index> {
        let mut v = self.indices();
        {
            let slice = v.as_mut_slice();
            thread_rng().shuffle(slice);
        }
        v
    }
}

impl Board<char> {
    pub fn print(&self) {
        for x in 0..self.width {
            for y in 0..self.height {
                print!("{} ", self[(x as i32, y as i32)]);
            }
            println!("");
        }
    }
}

impl<Cell> ops::Index<Index> for Board<Cell> {
    type Output = Cell;

    fn index(&self, (w, h): Index) -> &Cell {
        let n: usize = (w + (h * self.width as i32)) as usize;
        &self.cells[n as usize]
    }
}

impl<Cell> ops::IndexMut<Index> for Board<Cell> {
    fn index_mut(&mut self, (w, h): Index) -> &mut Cell {
        let n: usize = (w + (h * self.width as i32)) as usize;
        &mut self.cells[n as usize]
    }
}

impl<Cell: Clone + Hash + Eq> Rule<Cell> {
    /// Create a new `Rule` from two sparse grids of cells,
    /// corresponding respectively to the LHS and the RHS
    pub fn new(
        lhs: SparseBoard<Cell>,
        rhs: SparseBoard<Cell>,
    ) -> Rule<Cell> {
        let rule_name = None;
        let requires = lhs.values().cloned().collect();
        Rule { rule_name, requires, lhs, rhs }
    }

    /// Get mutable access to the LHS of the `Rule`, for modification
    /// later
    pub fn lhs_mut(&mut self) -> &mut SparseBoard<Cell> {
        &mut self.lhs
    }

    /// Get mutable access to the RHS of the `Rule`, for modification
    /// later
    pub fn rhs_mut(&mut self) -> &mut SparseBoard<Cell> {
        &mut self.lhs
    }

    /// Attempt to apply this rule to the provided board at random
    /// (i.e. if there are multiple possible applications of this
    /// rule, then it should choose one of them entirely at random
    pub fn apply_to_board(&self, b: &mut Board<Cell>) -> bool {
        // for each random location in the board
        'outer: for (x, y) in b.random_indices() {
            // find out whether each of our tiles matche
            for (&(i, j), v) in self.lhs.iter() {
                // if it doesn't, then skip ahead
                match b.get((x + i, y + j)) {
                    Some(r) if v == r => (),
                    _ => continue 'outer,
                }
            }

            // if all of them match, then do the rewrites!
            for (&(i, j), r) in self.rhs.iter() {
                b[(x + i, y + j)] = r.clone();
            }

            // and because the rule applied, we can quit now
            return true;
        }
        // if we've tried them all and none of them worked, then we've
        // failed
        false
    }
}


#[cfg(test)]
#[test]
pub fn grammar_test() {
    let rule1: Rule<char> = Rule::new(
        vec![ ((0, 0), 'x') ].into_iter().collect(),
        vec![ ((0, 0), 'y'), ((1, 0), 'y') ].into_iter().collect(),
    );
    let rule2: Rule<char> = Rule::new(
        vec![ ((0, 0), 'y') ].into_iter().collect(),
        vec![ ((0, 0), 'z') ].into_iter().collect(),
    );
    let mut board = Board::new(8, 8, '.');
    board[(2, 2)] = 'x';
    assert!(true, rule1.apply_to_board(&mut board));
    assert!(true, rule2.apply_to_board(&mut board));
    board.print();
}