// Grid implemented as flat vector pub struct Grid { num_rows: usize, num_cols: usize, elems: Vec, } impl Grid { /// Returns a Grid of the specified size, with all elements pre-initialized to zero. pub fn new(num_rows: usize, num_cols: usize) -> Grid { Grid { num_rows: num_rows, num_cols: num_cols, // This syntax uses the vec! macro to create a vector of zeros, initialized to a // specific length // https://stackoverflow.com/a/29530932 elems: vec![0; num_rows * num_cols], } } pub fn size(&self) -> (usize, usize) { (self.num_rows, self.num_cols) } /// Returns the element at the specified location. If the location is out of bounds, returns /// None. /// /// Note to students: this function also could have returned Result. It's a matter of taste in /// how you define the semantics; many languages raise exceptions for out-of-bounds exceptions, /// but others argue that makes code needlessly complex. Here, we decided to return Option to /// give you more practice with Option :) and because this similar library returns Option: /// https://docs.rs/array2d/0.2.1/array2d/struct.Array2D.html pub fn get(&self, row: usize, col: usize) -> Option { if row >= self.num_rows || col >= self.num_cols { None } else { Some(self.elems[row * self.num_cols + col]) } } /// Sets the element at the specified location to the specified value. If the location is out /// of bounds, returns Err with an error message. pub fn set(&mut self, row: usize, col: usize, val: usize) -> Result<(), &'static str> { if row >= self.num_rows || col >= self.num_cols { Err("Outof Boundry") } else { self.elems[row * self.num_cols + col] = val; Ok(()) } } /// Prints a visual representation of the grid. You can use this for debugging. pub fn display(&self) { for row in 0..self.num_rows { let mut line = String::new(); for col in 0..self.num_cols { line.push_str(&format!("{}, ", self.get(row, col).unwrap())); } println!("{}", line); } } /// Resets all the elements to zero. pub fn clear(&mut self) { for i in self.elems.iter_mut() { *i = 0; } } } #[cfg(test)] mod test { use super::*; #[test] fn test_grid() { let n_rows = 4; let n_cols = 3; let mut grid = Grid::new(n_rows, n_cols); // Initialize grid for r in 0..n_rows { for c in 0..n_cols { assert!( grid.set(r, c, r * n_cols + c).is_ok(), "Grid::set returned Err even though the provided bounds are valid!" ); } } // Note: you need to run "cargo test -- --nocapture" in order to see output printed println!("Grid contents:"); grid.display(); // Make sure the values are what we expect for r in 0..n_rows { for c in 0..n_cols { assert!( grid.get(r, c).is_some(), "Grid::get returned None even though the provided bounds are valid!" ); assert_eq!(grid.get(r, c).unwrap(), r * n_cols + c); } } } }