Added test, and enums -- slick, but kind of gratuitous

This commit is contained in:
David Lotts
2022-03-02 03:28:42 -05:00
committed by David
parent ba5ee8b915
commit bbfe11764a
2 changed files with 86 additions and 37 deletions

View File

@@ -6,4 +6,6 @@ edition = "2021"
[dependencies]
text_io = "0.1.10"
#num-integer = "0.1"
rand = "0.8.5"
rand = "0.8.5"
strum = "0.24"
strum_macros = "0.24"

View File

@@ -1,11 +1,13 @@
/*
* Rock paper scissors
* Port from book _Basic Computer Games_
* By David Lotts
* Originally from the wonderful book: _Basic Computer Games_
* Port to Rust By David Lotts
*/
use rand::Rng;
use rand::{prelude::ThreadRng, Rng}; //Large code. Switch to https://crates.io/crates/oorandom
use std::io::{self, Write};
use text_io::{try_read};
use strum::EnumCount;
use strum_macros::{Display, EnumCount, FromRepr};
use text_io::try_read;
fn main() {
let mut computer_wins = 0;
let mut human_wins = 0;
@@ -25,10 +27,10 @@ fn main() {
for game_number in 1..=qty_games {
println!();
println!("GAME NUMBER {}", game_number);
let my_choice: i32 = rng.gen_range(1..=3); // basic: X=INT(RND(1)*3+1)
//let my_choice: i32 = rng.gen_range(1..=3); // basic: X=INT(RND(1)*3+1)
let mut your_choice = 0;
loop {
println!("3=ROCK...2=SCISSORS...1=PAPER");
println!("3=ROCK...2=SCISSORS...1=PAPER");
input_int("1...2...3...WHAT'S YOUR CHOICE", &mut your_choice);
// interesting validation in original BASIC: IF (K-1)*(K-2)*(K-3)==0
if (1..=3).contains(&your_choice) {
@@ -36,61 +38,106 @@ fn main() {
}
println!("INVALID.");
}
// Convert number to enum. Note the type change. Really it is a new variable.
let your_choice = Choice::from_repr((your_choice-1) as usize).unwrap();
let my_choice = Choice::new_random(&mut rng);
println!("THIS IS MY CHOICE...");
println!(
"...{}",
match my_choice {
1 => "PAPER",
2 => "SCISSORS",
3 => "ROCK",
_ => "um, what?",
println!("...{}", my_choice.to_string());
let winner = Winner::decide_winner(my_choice, your_choice);
println!("{}", match winner {
Winner::Tie => {
"TIE GAME. NO WINNER."
}
);
if my_choice == your_choice {
//THEN 250
println!("TIE GAME. NO WINNER.");
} else {
//if (my_choice == 1 && your_choice == 3)
// || (my_choice > your_choice)
if 1 == (3 + my_choice - your_choice) % 3
{
println!("WOW! I WIN!!!");
computer_wins = computer_wins + 1;
} else {
println!("YOU WIN!!!");
human_wins = human_wins + 1;
Winner::Computer => {
computer_wins = computer_wins + 1; "WOW! I WIN!!!"
}
}
Winner::Human => {
human_wins = human_wins + 1; "YOU WIN!!!"
}
})
}
println!();
println!("HERE IS THE FINAL GAME SCORE:");
println!("I HAVE WON {} GAME(S).", computer_wins);
println!("YOU HAVE WON {} GAME(S).", human_wins);
println!("AND {} GAME(S) ENDED IN A TIE.", qty_games - (computer_wins + human_wins));
println!(
"AND {} GAME(S) ENDED IN A TIE.",
qty_games - (computer_wins + human_wins)
);
println!();
println!("THANKS FOR PLAYING!!");
}
#[derive(FromRepr, Debug, PartialEq, EnumCount, Display)]
enum Choice {
PAPER,
SCISSORS,
ROCK,
}
impl Choice {
/// Returns randomly selected paper..rock.
fn new_random(rng: &mut ThreadRng) -> Choice {
Choice::from_repr((rng).gen_range(0..Choice::COUNT)).unwrap()
}
}
#[derive(FromRepr, Debug, PartialEq, EnumCount)]
pub enum Winner {
Human,
Computer,
Tie,
}
impl Winner {
/// take opponent's choices and decide the winner
// I really learned alot about enums here, and now you can too!
// Originally I broke this out for auto testing.
fn decide_winner(my_choice: Choice, your_choice: Choice) -> Winner {
let my_choice = my_choice as u8;
let your_choice = your_choice as u8;
if my_choice == your_choice {
return Winner::Tie;
}
// wordy but clear way:
// if (my_choice == 1 && your_choice == 3) || (my_choice > your_choice)
// consice but opaque way:
if 1 == (3 + my_choice - your_choice) % 3 {
return Winner::Computer
}
return Winner::Human
}
}
/// print the prompt, wait for a number and newline. Loop if invalid.
fn input_int(prompt: &str, number: &mut i32) {
loop {
print!("{} ? ", prompt);
io::stdout().flush().unwrap();
match try_read!() {
Ok(n) => {
if let Ok(n) = try_read!() {
*number = n;
return;
}
Err(_) => println!("{}", prompt),
}
}
}
// TODO break out the winner decider and test it.
#[cfg(test)]
mod tests {
#[test]
fn winner_test() {
assert_eq!(true,true);
use super::*;
use Winner::*;
use Choice::*; //decide_winner(my_choice=computer, your_choice=human)
assert_eq!(Winner::decide_winner(PAPER ,PAPER ), Tie);
assert_eq!(Winner::decide_winner(PAPER ,SCISSORS), Human);
assert_eq!(Winner::decide_winner(PAPER ,ROCK), Computer);
assert_eq!(Winner::decide_winner(SCISSORS,PAPER ), Computer);
assert_eq!(Winner::decide_winner(SCISSORS,SCISSORS), Tie);
assert_eq!(Winner::decide_winner(SCISSORS,ROCK), Human);
assert_eq!(Winner::decide_winner(ROCK ,PAPER ), Human);
assert_eq!(Winner::decide_winner(ROCK ,SCISSORS), Computer);
assert_eq!(Winner::decide_winner(ROCK ,ROCK), Tie);
}
}
}