//! Game board logic. use std::fs::read_to_string; const SIZE: usize = 9; #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Cell { pub value: u8, pub loaded: bool, } #[derive(Debug, PartialEq)] pub struct Gameboard { pub cells: [[Cell; SIZE]; SIZE], } impl Gameboard { pub fn new() -> Gameboard { Gameboard { cells: [[Cell::default(); SIZE]; SIZE], } } pub fn from_cells(cells: [[u8; SIZE]; SIZE]) -> Gameboard { let mut ret = Gameboard::new(); for (i, row) in cells.iter().enumerate() { for (j, &col) in row.iter().enumerate() { ret.cells[i][j] = Cell { value: col, loaded: col != 0, }; } } ret } pub fn char(&self, ind: [usize; 2]) -> Option { Some(match self.cells[ind[1]][ind[0]].value { 1 => '1', 2 => '2', 3 => '3', 4 => '4', 5 => '5', 6 => '6', 7 => '7', 8 => '8', 9 => '9', _ => return None, }) } pub fn set(&mut self, ind: [usize; 2], val: u8) { if !self.cells[ind[1]][ind[0]].loaded { self.cells[ind[1]][ind[0]].value = val; } } pub fn load_sdm(filename: &str) -> Self { let data = read_to_string(filename).expect("failed to read SDM file"); let mut cells = [[Cell::default(); SIZE]; SIZE]; let mut row = 0; let mut col = 0; for c in data.chars() { if col == SIZE { col = 0; row += 1; } if let Some(v) = c.to_digit(10) { let value = v as u8; cells[row][col] = Cell { value, loaded: value != 0, }; col += 1; } } Self { cells } } } #[cfg(test)] mod tests { use super::*; #[test] fn load_sdm() { let got = Gameboard::load_sdm("static/puzzle.sdm"); let want = Gameboard::from_cells([ [0, 1, 6, 4, 0, 0, 0, 0, 0], [2, 0, 0, 0, 0, 9, 0, 0, 0], [4, 0, 0, 0, 0, 0, 0, 6, 2], [0, 7, 0, 2, 3, 0, 1, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 3], [0, 0, 3, 0, 8, 7, 0, 4, 0], [9, 6, 0, 0, 0, 0, 0, 0, 5], [0, 0, 0, 8, 0, 0, 0, 0, 7], [0, 0, 0, 0, 0, 6, 8, 2, 0], ]); assert_eq!(got, want); } }