Skip to content

Commit

Permalink
DI stdin
Browse files Browse the repository at this point in the history
  • Loading branch information
a-barwick committed May 21, 2023
1 parent 5f9f447 commit 5a72087
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 11 deletions.
44 changes: 36 additions & 8 deletions src/game/game.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use super::board::Board;
use super::player::{Player, PlayerSymbol};

use std::io;
use crate::io::input::Input;

/// Represents the game state and logic
pub struct Game<'a> {
pub board: Board,
pub current_player: &'a Player,
pub input: &'a dyn Input,
}

impl<'a> Game<'a> {
/// Creates a new game with the current player
pub fn new(current_player: &'a Player) -> Game<'a> {
pub fn new(current_player: &'a Player, input: &'a dyn Input) -> Game<'a> {
Game {
board: Board::new(),
current_player,
input,
}
}

Expand Down Expand Up @@ -126,10 +128,13 @@ impl<'a> Game<'a> {
fn get_player_selection(&self) -> Result<usize, &'static str> {
println!("Type the number from one of the available cells:");
self.draw_board();
let mut user_input = String::new();
if let Err(_) = io::stdin().read_line(&mut user_input) {
println!("No input, don't be typin nothin!");
}
let user_input = match self.input.read() {
Ok(input) => input,
Err(msg) => {
println!("{}", msg);
return self.get_player_selection();
}
};
match user_input.trim().parse::<usize>() {
Ok(result) if result < 9 => return Ok(result),
Ok(_) => return Err("Pick an available number from the board:"),
Expand Down Expand Up @@ -165,14 +170,37 @@ enum GameState {

#[cfg(test)]
mod tests {
use crate::io::input::MockInput;

use super::*;

#[test]
fn test_new() {
let player_one = Player {
symbol: PlayerSymbol::X,
};
let game = Game::new(&player_one);
assert_eq!(game.current_player.symbol, PlayerSymbol::X);
let mock_input = MockInput {
input: "1".to_string(),
};
let game = Game::new(&player_one, &mock_input);
assert_eq!(game.current_player.symbol, player_one.symbol);
assert_eq!(game.board.cells.len(), 9);
assert_eq!(game.board.cells[0].value, None);
}

#[test]
fn test_run() {
let player_one = Player {
symbol: PlayerSymbol::X,
};
let player_two = Player {
symbol: PlayerSymbol::O,
};
let mock_input = MockInput {
input: "1".to_string(),
};
let mut game = Game::new(&player_one, &mock_input);
game.run(&player_one, &player_two);
assert_eq!(game.board.cells[0].value, Some(PlayerSymbol::X));
}
}
6 changes: 4 additions & 2 deletions src/game/session.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use super::game::Game;
use super::player::{Player, PlayerSymbol};

use crate::io::input::Input;

/// Initializes players and starts the game loop
pub fn start() {
pub fn start(input: &dyn Input) {
println!("Welcome to Tic-Tac-Toe!");
let player_one = Player {
symbol: PlayerSymbol::X,
};
let player_two = Player {
symbol: PlayerSymbol::O,
};
Game::new(&player_one).run(&player_one, &player_two);
Game::new(&player_one, input).run(&player_one, &player_two);
}
23 changes: 23 additions & 0 deletions src/io/input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pub trait Input {
fn read(&self) -> std::io::Result<String>;
}

pub struct StdinInput;

impl Input for StdinInput {
fn read(&self) -> std::io::Result<String> {
let mut user_input = String::new();
std::io::stdin().read_line(&mut user_input)?;
Ok(user_input)
}
}

pub struct MockInput {
pub input: String,
}

impl Input for MockInput {
fn read(&self) -> std::io::Result<String> {
Ok(self.input.clone())
}
}
1 change: 1 addition & 0 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod input;
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod game;
mod io;

fn main() {
game::session::start();
let input = io::input::StdinInput;
game::session::start(&input);
}

0 comments on commit 5a72087

Please sign in to comment.