#[derive(Clone, Copy, PartialEq)] pub enum Cell { Empty, X, O, } pub struct Move { pub x: usize, pub y: usize, pub piece: Cell, } pub struct Board { cells: Vec, next: Cell, } impl Board { pub fn new() -> Board { Board { cells: vec![Cell::Empty; 9], next: Cell::X, } } pub fn reset(&mut self) { self.cells = vec![Cell::Empty; 9]; self.next = Cell::X; } pub fn apply(&mut self, m: Move) -> Result<(), &str> { if !self.is_valid_move(&m) { return Err("invalid move"); } let i = m.x * 1 + m.y * 3; self.cells[i] = m.piece; match self.next { Cell::X => self.next = Cell::O, Cell::O => self.next = Cell::X, _ => {} } Ok(()) } pub fn is_valid_move(&self, m: &Move) -> bool { if m.x > 2 || m.y > 2 { return false; } let i = m.x * 1 + m.y * 3; m.piece == self.next && self.cells[i] == Cell::Empty } pub fn valid_moves_available(&self) -> bool { // check for draw condition for i in 0..self.cells.len() { if self.cells[i] == Cell::Empty { return true; } } return false; } pub fn has_winner(&self) -> Option { // rows and cols for i in 0..3 { if (self.cells[i] != Cell::Empty) && (self.cells[i] == self.cells[i + 3] && self.cells[i] == self.cells[i + 6]) { return Some(self.cells[i]); } else if (self.cells[i * 3] != Cell::Empty) && (self.cells[i * 3] == self.cells[i * 3 + 1] && self.cells[i * 3] == self.cells[i * 3 + 2]) { return Some(self.cells[i * 3]); } } // diagonals if (self.cells[0] != Cell::Empty) && (self.cells[0] == self.cells[4] && self.cells[0] == self.cells[8]) { return Some(self.cells[0]); } if (self.cells[2] != Cell::Empty) && (self.cells[2] == self.cells[4] && self.cells[2] == self.cells[6]) { return Some(self.cells[2]); } // no winner return None; } pub fn cells(&self) -> Vec { self.cells.clone() } pub fn next_move(&self) -> Cell { self.next } }