#[derive(Clone, Copy, PartialEq)] pub enum Cell { Empty, X, O, } impl std::fmt::Display for Cell { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let s: &str; match *self { Cell::X => s = "X", Cell::O => s = "O", Cell::Empty => s = " ", } write!(f, "{}", s) } } 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> { let i = m.x * 1 + m.y * 3; if !self.is_valid_move(&m) { return Err("invalid move"); } 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 { 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 let mut empty: usize = 0; for i in 0..self.cells.len() { if self.cells[i] == Cell::Empty { empty += 1; } } empty > 0 } 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; } } impl std::fmt::Display for Board { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mut s = String::new(); s.push_str(" 1 2 3 \n"); s.push_str(" ┌───┬───┬───┐\n"); for i in 0..3 { match i { 0 => s.push_str("a "), 1 => s.push_str("b "), 2 => s.push_str("c "), _ => {} } s.push_str(&format!( "│ {} │ {} │ {} │\n", self.cells[i * 3], self.cells[i * 3 + 1], self.cells[i * 3 + 2] )); if i < 2 { s.push_str(" ├───┼───┼───┤\n"); } } s.push_str(" └───┴───┴───┘\n"); match self.has_winner() { Some(w) => s.push_str(&format!("The winner is {w}")), None => match self.valid_moves_available() { true => s.push_str(&format!("Next: {}", self.next)), false => s.push_str("DRAW!"), }, } write!(f, "{s}") } }