#[derive(Clone, Copy, PartialEq)] //pub struct Cell(u8); //pub const Cell::CellEmpty: Cell = Cell(0); //pub const Cell::CellX: Cell = Cell(1); //pub const Cell::CellO: Cell = Cell(2); pub enum Cell { CellEmpty, CellX, CellO, } impl std::fmt::Display for Cell { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let s: &str; match *self { Cell::CellX => s = "X", Cell::CellO => s = "O", Cell::CellEmpty => 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 { return Board { cells: vec![Cell::CellEmpty; 9], next: Cell::CellX, }; } pub fn reset(&mut self) { self.cells = vec![Cell::CellEmpty; 9]; self.next = Cell::CellX; } pub fn put(&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::CellX => self.next = Cell::CellO, Cell::CellO => self.next = Cell::CellX, _ => {} } 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::CellEmpty } pub fn has_winner(&self) -> Option { // rows and cols for i in 0..3 { if (self.cells[i] == self.cells[i + 3] && self.cells[i] == self.cells[i + 6]) && (self.cells[i] != Cell::CellEmpty && self.cells[i + 3] != Cell::CellEmpty && self.cells[i + 6] != Cell::CellEmpty) { return Some(self.cells[i]); } else if (self.cells[i * 3] == self.cells[i * 3 + 1] && self.cells[i * 3] == self.cells[i * 3 + 2]) && (self.cells[i * 3] != Cell::CellEmpty && self.cells[i * 3 + 1] != Cell::CellEmpty && self.cells[i * 3 + 2] != Cell::CellEmpty) { return Some(self.cells[i * 3]); } } // diagonals if (self.cells[0] == self.cells[4] && self.cells[0] == self.cells[8]) && (self.cells[0] != Cell::CellEmpty && self.cells[4] != Cell::CellEmpty && self.cells[8] != Cell::CellEmpty) { return Some(self.cells[0]); } if (self.cells[2] == self.cells[4] && self.cells[2] == self.cells[6]) && (self.cells[2] != Cell::CellEmpty && self.cells[4] != Cell::CellEmpty && self.cells[6] != Cell::CellEmpty) { 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 => s.push_str(&format!("Next: {}", self.next)), } write!(f, "{s}") } }