Skip to content

Instantly share code, notes, and snippets.

@BSN4
Created January 2, 2025 01:39
Show Gist options
  • Save BSN4/e6f0cf184d9de92b2a2eebe670a266e9 to your computer and use it in GitHub Desktop.
Save BSN4/e6f0cf184d9de92b2a2eebe670a266e9 to your computer and use it in GitHub Desktop.
rock_paper_scissors rust v2
use rand::Rng;
use std::io::{self, Write};
#[derive(Debug, Default)]
struct Score {
player: u32,
computer: u32,
}
#[derive(Debug, PartialEq, Clone, Copy)]
enum Move {
Rock,
Paper,
Scissors,
}
#[derive(Debug)]
enum GameResult {
PlayerWins(Move, Move),
ComputerWins(Move, Move),
Draw(Move),
}
struct Game {
score: Score,
rounds: u32,
}
impl Game {
fn new(rounds: u32) -> Self {
Self {
score: Score::default(),
rounds,
}
}
fn play(&mut self) {
for round in 1..=self.rounds {
println!("\nRound {round}");
self.play_round();
}
self.announce_winner();
self.maybe_play_again();
}
fn play_round(&mut self) {
match self.get_player_move() {
Ok(player_move) => {
let computer_move = Move::random();
println!("Computer chose: {computer_move}");
let result = GameResult::determine(player_move, computer_move);
println!("{result}");
self.update_score(&result);
}
Err(msg) => {
println!("{msg}");
self.play_round();
}
}
}
fn get_player_move(&self) -> Result<Move, &'static str> {
print!("Enter your move (rock/paper/scissors): ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.map_err(|_| "Failed to read input")?;
Move::parse(&input)
}
fn update_score(&mut self, result: &GameResult) {
match result {
GameResult::PlayerWins(_, _) => self.score.player += 1,
GameResult::ComputerWins(_, _) => self.score.computer += 1,
GameResult::Draw(_) => (),
}
}
fn announce_winner(&self) {
println!(
"\nFinal Score - You: {}, Computer: {}",
self.score.player, self.score.computer
);
let result = match self.score.player.cmp(&self.score.computer) {
std::cmp::Ordering::Greater => "You win the series!",
std::cmp::Ordering::Less => "Computer wins the series!",
std::cmp::Ordering::Equal => "The series is a draw!",
};
println!("{result}");
}
fn maybe_play_again(&mut self) {
print!("\nPlay again? (y/n): ");
io::stdout().flush().unwrap();
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) if input.trim().to_lowercase() == "y" => {
self.score = Score::default();
self.play();
}
Ok(_) => println!("Thanks for playing!"),
Err(_) => println!("Error reading input. Game ended."),
}
}
}
impl Move {
fn random() -> Self {
match rand::thread_rng().gen_range(0..3) {
0 => Self::Rock,
1 => Self::Paper,
_ => Self::Scissors,
}
}
fn parse(input: &str) -> Result<Self, &'static str> {
match input.trim().to_lowercase().as_str() {
"rock" => Ok(Self::Rock),
"paper" => Ok(Self::Paper),
"scissors" => Ok(Self::Scissors),
_ => Err("Invalid move. Please enter rock, paper, or scissors."),
}
}
}
impl std::fmt::Display for Move {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Rock => "rock",
Self::Paper => "paper",
Self::Scissors => "scissors",
}
)
}
}
impl GameResult {
fn determine(player: Move, computer: Move) -> Self {
match (player, computer) {
(Move::Rock, Move::Scissors) |
(Move::Paper, Move::Rock) |
(Move::Scissors, Move::Paper) => Self::PlayerWins(player, computer),
(p, c) if p == c => Self::Draw(p),
(p, c) => Self::ComputerWins(c, p),
}
}
}
impl std::fmt::Display for GameResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::PlayerWins(threw, beat) => {
write!(f, "You won by throwing {threw} against {beat}")
}
Self::ComputerWins(threw, beat) => {
write!(f, "Computer won by throwing {threw} against {beat}")
}
Self::Draw(move_) => write!(f, "Draw! Both players threw {move_}"),
}
}
}
fn main() {
Game::new(3).play();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment