Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • 01-simple-board
  • 02-typed-squares
  • 03-board-struct
  • 04-impl-for-board
  • 05-unit-tests
  • 06-trait
  • 07-trait-derive
  • 08-Display
  • 09-modules
  • 09.5-before-main-generic
  • 10-generics
  • 11-flip-coin
13 results

Target

Select target project
  • michael.hauspie/intro-rust-game
1 result
Select Git revision
  • main
  • 01-simple-board
  • 02-typed-squares
  • 03-board-struct
  • 04-impl-for-board
  • 05-unit-tests
  • 06-trait
  • 07-trait-derive
  • 08-Display
  • 09-modules
  • 09.5-before-main-generic
  • 10-generics
  • 11-flip-coin
13 results
Show changes
Commits on Source (3)
//! A module that implements several board games
pub mod tictactoe;
/// A trait that defines a Board for a game where we can make a player
/// play a move and check if a player has won
pub trait Board<Move, Player> {
/// Apply a move to the board
fn do_move(&mut self, turn: Player, m: &Move);
/// Returns if a given player has won the game considering this
/// board
fn has_won(&self, player: Player) -> bool;
}
use std::str::FromStr;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum Square { pub enum Player {
Empty,
Cross, Cross,
Circle, Circle,
} }
impl std::fmt::Display for Player {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Player::Cross => write!(f, "X"),
Player::Circle => write!(f, "O"),
}
}
}
/// A Tictactoe square is either empty (None) or Player
#[derive(Clone, Copy, Debug, PartialEq)]
enum Square {
Empty,
Full(Player),
}
impl std::fmt::Display for Square { impl std::fmt::Display for Square {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Square::Empty => write!(f, "."), Square::Empty => write!(f, "."),
Square::Cross => write!(f, "X"), Square::Full(p) => write!(f, "{}", p),
Square::Circle => write!(f, "O"),
} }
} }
} }
/// A TicTacToe board
pub struct Board { pub struct Board {
board: [Square; 9], board: [Square; 9],
} }
/// A TicTacToe Move
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Move {
A1 = 0,
B1 = 1,
C1 = 2,
A2 = 3,
B2 = 4,
C2 = 5,
A3 = 6,
B3 = 7,
C3 = 8,
}
// impl std::fmt::FromStr for Move {
// }
impl Board { impl Board {
/// Creates a new empty board /// Creates a new empty board
pub fn new() -> Self { pub fn new() -> Self {
...@@ -36,12 +70,16 @@ impl Board { ...@@ -36,12 +70,16 @@ impl Board {
impl std::fmt::Display for Board { impl std::fmt::Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, " A B C")?;
for row in 0..3 { for row in 0..3 {
writeln!(f, " {} | {} | {}", writeln!(
self.board[row * 3], f,
self.board[row * 3 + 1], " {} | {} | {} {}",
self.board[row * 3 + 2], self.board[row * 3],
)?; self.board[row * 3 + 1],
self.board[row * 3 + 2],
row + 1,
)?;
if row == 0 || row == 1 { if row == 0 || row == 1 {
writeln!(f, "---+---+---")?; writeln!(f, "---+---+---")?;
} }
...@@ -50,10 +88,49 @@ impl std::fmt::Display for Board { ...@@ -50,10 +88,49 @@ impl std::fmt::Display for Board {
} }
} }
// Implementations of the Board trait for Tictactoe
impl super::Board<Move, Player> for Board {
/// Apply a move to the board
fn do_move(&mut self, turn: Player, m: &Move) {
let idx = *m as usize;
if self.board[idx] == Square::Empty {
self.board[idx] = Square::Full(turn);
}
}
/// Returns if a given player has won the game considering this
/// board
fn has_won(&self, player: Player) -> bool {
for (s1, s2, s3) in [
// rows
(0, 1, 2),
(3, 4, 5),
(6, 7, 8),
// columns
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
// diagonals
(0, 4, 8),
(2, 4, 6),
] {
if (
Square::Full(player),
Square::Full(player),
Square::Full(player),
) == (self.board[s1], self.board[s2], self.board[s3])
{
return true;
}
}
return false;
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn new_board_squares_are_empty() { fn new_board_squares_are_empty() {
let board = Board::new(); let board = Board::new();
...@@ -65,11 +142,12 @@ mod tests { ...@@ -65,11 +142,12 @@ mod tests {
#[test] #[test]
fn empty_board_to_string() { fn empty_board_to_string() {
let expected = " . | . | . let expected = " A B C
. | . | . 1
---+---+--- ---+---+---
. | . | . . | . | . 2
---+---+--- ---+---+---
. | . | . . | . | . 3
"; ";
assert_eq!(expected, format!("{}", Board::new())); assert_eq!(expected, format!("{}", Board::new()));
} }
...@@ -79,12 +157,19 @@ mod tests { ...@@ -79,12 +157,19 @@ mod tests {
assert_eq!(".", format!("{}", Square::Empty)); assert_eq!(".", format!("{}", Square::Empty));
} }
#[test] #[test]
fn cross_player_to_string_x() {
assert_eq!("X", format!("{}", Player::Cross));
}
#[test]
fn circle_player_to_string_big_o() {
assert_eq!("O", format!("{}", Player::Circle));
}
#[test]
fn cross_square_to_string_x() { fn cross_square_to_string_x() {
assert_eq!("X", format!("{}", Square::Cross)); assert_eq!("X", format!("{}", Square::Full(Player::Cross)));
} }
#[test] #[test]
fn circle_square_to_string_big_o() { fn circle_square_to_string_big_o() {
assert_eq!("O", format!("{}", Square::Circle)); assert_eq!("O", format!("{}", Square::Full(Player::Circle)));
} }
} }
mod board; mod board;
use board::Board; use board::tictactoe::Board as TicTacToe;
fn main() { fn main() {
let board = Board::new(); let board = TicTacToe::new();
board.display(); board.display();
} }
......