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 (2)
......@@ -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"
......@@ -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"
//! 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,
}
}
}
//! 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);
......
......@@ -6,6 +6,23 @@ pub enum Player {
Circle,
}
impl Default for Player {
fn default() -> Self {
Player::Cross
}
}
impl std::ops::Not for Player {
type Output = Player;
fn not(self) -> Self::Output {
match self {
Player::Cross => Player::Circle,
Player::Circle => Player::Cross,
}
}
}
impl std::fmt::Display for Player {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
......@@ -50,9 +67,24 @@ pub enum Move {
C3 = 8,
}
// impl std::fmt::FromStr for Move {
// }
impl FromStr for Move {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"A1" => Ok(Move::A1),
"B1" => Ok(Move::B1),
"C1" => Ok(Move::C1),
"A2" => Ok(Move::A2),
"B2" => Ok(Move::B2),
"C2" => Ok(Move::C2),
"A3" => Ok(Move::A3),
"B3" => Ok(Move::B3),
"C3" => Ok(Move::C3),
_ => Err(format!("Illegal move {}", s))
}
}
}
impl Board {
/// Creates a new empty board
......@@ -89,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;
......
mod board;
use board::tictactoe::Board as TicTacToe;
fn main() {
let board = TicTacToe::new();
use board::Game;
use std::io;
use std::io::prelude::*;
fn prompt<Player>(turn: Player)
where
Player: std::fmt::Display,
{
print!("{}>", turn);
io::stdout().flush().unwrap();
}
fn play<G, Move, Player>(mut board: G)
where
G: Game<Move, Player> + std::fmt::Display,
Player: Copy + std::fmt::Display + Default + std::ops::Not<Output = Player>,
Move: std::str::FromStr,
{
let mut stdin = std::io::stdin().lock();
let mut player = Player::default();
println!("Let start");
println!("{board}");
prompt(player);
board.display();
loop {
let mut input = String::default();
stdin.read_line(&mut input).unwrap();
let str_move = input.trim_end();
if let Ok(m) = str_move.parse() {
board.do_move(player, &m);
println!("{board}");
if board.has_won(player) {
println!("Victory!");
return;
}
player = !player;
}
prompt(player);
}
}
fn main() {
//let board = TicTacToe::new();
let board = board::coin_flip::FlipCoin::new(42);
play(board);
}
// Will only be build in 'test' configuration
......