diff --git a/Cargo.lock b/Cargo.lock index 52ce037fc321e2784435224e567c182bcae39860..99a531bba492c43179eb3f1bab1a92bdc87d75b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,12 @@ version = 3 [[package]] name = "intro-rust-game" version = "0.1.0" +dependencies = [ + "random", +] + +[[package]] +name = "random" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474c42c904f04dfe2a595a02f71e1a0e5e92ffb5761cc9a4c02140b93b8dd504" diff --git a/Cargo.toml b/Cargo.toml index 3319a91121db93ec901ff6db12b88caa2c69a9cc..6f5e9a7fefc97cd39ec74a58ac43ee0a0379afd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +random = "0.13.2" diff --git a/src/board/coin_flip.rs b/src/board/coin_flip.rs new file mode 100644 index 0000000000000000000000000000000000000000..2d41065df8f066c3fde5f3bd8099cc461d2153b5 --- /dev/null +++ b/src/board/coin_flip.rs @@ -0,0 +1,103 @@ +//! A flip a coin one player game + +/// A possible move for a flip a coin game +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Move { + Heads, + Tails, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +/// A flip coin player (me...) +pub enum Player { + Me, +} + +impl Default for Player { + fn default() -> Self { + Player::Me + } +} + +impl std::fmt::Display for Player { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "me") + } +} + +impl std::ops::Not for Player { + type Output = Self; + + fn not(self) -> Self::Output { + self + } +} + +impl std::str::FromStr for Move { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "h" | "heads" => Ok(Move::Heads), + "t" | "tails" => Ok(Move::Tails), + _ => Err(format!("Invalid move {}", s)), + } + } +} + +impl std::fmt::Display for Move { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Move::Heads => write!(f, "Heads"), + Move::Tails => write!(f, "Tails"), + } + } +} + +use random::Source; + +pub struct FlipCoin { + random_source: random::Default, + last_flip: Option<Move>, + guessed: Option<Move>, +} + + + +impl FlipCoin { + /// Creates a new flipcoin game from a random seed + pub fn new(seed: u64) -> Self { + Self { + random_source: random::default(seed), + last_flip: None, + guessed: None + } + } +} + +impl std::fmt::Display for FlipCoin { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match (self.last_flip, self.guessed) { + (Some(c), Some(g)) => write!(f, "You chose {} and flipped {}", g, c), + _ => write!(f, "Lets flip a coin!"), + } + } +} + +impl super::Game<Move, Player> for FlipCoin { + fn do_move(&mut self, _turn: Player, m: &Move) { + self.guessed = Some(*m); + self.last_flip = if self.random_source.read_f64() > 0.5 { + Some(Move::Heads) + } else { + Some(Move::Tails) + } + } + + fn has_won(&self, _player: Player) -> bool { + match (self.last_flip, self.guessed) { + (Some(f), Some(g)) => f == g, + _ => false, + } + } +} diff --git a/src/board/mod.rs b/src/board/mod.rs index 052f9155fe217625acc04df4c10c60e94d63bba3..5fd06df4cc23a8f5906a083a7977296c61dac995 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -1,10 +1,11 @@ //! A module that implements several board games pub mod tictactoe; +pub mod coin_flip; /// 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> { +pub trait Game<Move, Player> { /// Apply a move to the board fn do_move(&mut self, turn: Player, m: &Move); diff --git a/src/board/tictactoe.rs b/src/board/tictactoe.rs index b5a44a390c77b6df58ddc90bea46246baf0a0a6f..eb656d6ea88061aa273f1b880c6d0c4e8e5cc470 100644 --- a/src/board/tictactoe.rs +++ b/src/board/tictactoe.rs @@ -121,7 +121,7 @@ impl std::fmt::Display for Board { } // Implementations of the Board trait for Tictactoe -impl super::Board<Move, Player> for Board { +impl super::Game<Move, Player> for Board { /// Apply a move to the board fn do_move(&mut self, turn: Player, m: &Move) { let idx = *m as usize; diff --git a/src/main.rs b/src/main.rs index 6c0d36e2c41d289e2828e335b1970151bde36f9c..52dfb1c3726010dc9653ce61e5f5d216ab45d8de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod board; use board::tictactoe::Board as TicTacToe; -use board::Board; +use board::Game; use std::io; use std::io::prelude::*; @@ -13,9 +13,9 @@ where io::stdout().flush().unwrap(); } -fn play<Game, Move, Player>(mut board: Game) +fn play<G, Move, Player>(mut board: G) where - Game: Board<Move, Player> + std::fmt::Display, + G: Game<Move, Player> + std::fmt::Display, Player: Copy + std::fmt::Display + Default + std::ops::Not<Output = Player>, Move: std::str::FromStr, { @@ -44,7 +44,8 @@ where } fn main() { - let board = TicTacToe::new(); + //let board = TicTacToe::new(); + let board = board::coin_flip::FlipCoin::new(42); play(board); }