RosettaCodeData/Task/21-game/Rust/21-game.rust

226 lines
6.5 KiB
Plaintext

use rand::Rng;
use std::io;
#[derive(Clone)]
enum PlayerType {
Human,
Computer,
}
#[derive(Clone)]
struct Player {
name: String,
wins: u32, // holds wins
level: u32, // difficulty level of Computer
player_type: PlayerType,
}
trait Choose {
fn choose(&self, game: &Game) -> u8;
}
impl Player {
fn new(name: &str, player_type: PlayerType, level: u32) -> Player {
Player {
name: String::from(name),
wins: 0,
level,
player_type,
}
}
fn get_name(&self) -> &str {
&self.name[..]
}
fn get_level(&self) -> u32 {
self.level
}
fn add_win(&mut self) {
self.wins += 1
}
fn level_up(&mut self) {
self.level += 1
}
}
impl Choose for Player {
fn choose(&self, game: &Game) -> u8 {
match self.player_type {
PlayerType::Human => loop {
let max_choice = game.max_choice();
match max_choice {
1 => println!("Enter a number 1 to win (or quit):"),
_ => println!("Enter a number between 1 and {} (or quit):", max_choice)
}
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
if guess.trim() == "quit" {
return 0
}
let guess: u8 = match guess.trim().parse() {
Ok(num) if num >= 1 && num <= max_choice => num,
Ok(_) => continue,
Err(_) => continue,
};
return guess;
},
PlayerType::Computer => match self.level {
5 => match game.get_total() {
total if total == 20 => 1,
total if total == 19 => 2,
total if total == 18 => 3,
_ => 1,
},
4 => match game.get_total() {
total if total == 20 => 1,
total if total == 19 => 2,
total if total == 18 => 3,
_ => rand::thread_rng().gen_range(1, 3),
},
3 => match game.get_total() {
total if total == 20 => 1,
total if total == 19 => 2,
total if total == 18 => 3,
_ => rand::thread_rng().gen_range(1, 4),
},
2 => match game.get_total() {
total if total == 20 => 1,
total if total == 19 => 2,
_ => rand::thread_rng().gen_range(1, 3),
},
1 => 1,
_ => match game.get_total() {
total if total == 20 => 1,
total if total == 19 => 2,
total if total == 18 => 3,
_ => match game.get_remaining() % 4 {
0 => rand::thread_rng().gen_range(1, 4),
_ => game.get_remaining() % 4,
},
},
},
}
}
}
struct Game {
players: Vec<Player>,
turn: u8,
total: u8,
start: u8, // determines which player goes first
}
impl Game {
fn init(players: &Vec<Player>) -> Game {
Game {
players: players.to_vec(),
turn: 1,
total: 0,
start: rand::thread_rng().gen_range(0, 2),
}
}
fn play(&mut self) -> &Player {
loop {
println!(
"Total now {} (remaining: {})",
self.get_total(),
self.get_remaining()
);
{
let player = self.whose_turn();
println!("Turn: {} ({} turn)", self.get_turn(), player.get_name());
let choice = player.choose(&self);
if choice == 0 {
self.next_turn();
break; // quit
}
println!("{} choose {}", player.get_name(), choice);
self.add_total(choice)
}
if self.get_total() >= 21 {
break;
}
println!("");
self.next_turn();
}
self.whose_turn()
}
fn add_total(&mut self, choice: u8) {
self.total += choice;
}
fn next_turn(&mut self) {
self.turn += 1;
}
fn whose_turn(&self) -> &Player {
let index: usize = ((self.turn + self.start) % 2).into();
&self.players[index]
}
fn get_total(&self) -> u8 {
self.total
}
fn get_remaining(&self) -> u8 {
21 - self.total
}
fn max_choice(&self) -> u8 {
match self.get_remaining() {
1 => 1,
2 => 2,
_ => 3
}
}
fn get_turn(&self) -> u8 {
self.turn
}
}
fn main() {
let mut game_count = 0;
let mut players = vec![
Player::new("human", PlayerType::Human, 0),
Player::new("computer", PlayerType::Computer, 1),
];
println!("21 Game");
println!("Press enter key to start");
{
let _ = io::stdin().read_line(&mut String::new());
}
loop {
game_count += 1;
let mut game = Game::init(&players);
let winner = game.play();
{
let mut index = 0;
while index < players.len() {
if players[index].get_name() == winner.get_name() {
players[index].add_win();
}
index += 1
}
}
println!("\n{} won game {}\n", winner.get_name(), game_count);
// limit game count
if game_count >= 10000 {
break;
}
// ask player if they want to keep on playing
println!("Press enter key to play again (or quit):");
let mut reply = String::new();
io::stdin()
.read_line(&mut reply)
.expect("Failed to read line");
if reply.trim() == "quit" {
break;
}
// level up computer
if winner.get_name() != "computer" {
println!("Computer leveling up ...");
players[1].level_up();
println!("Computer now level {}!", players[1].get_level());
println!("Beware!\n");
}
}
println!("player: {} win: {}", players[0].get_name(), players[0].wins);
println!("player: {} win: {}", players[1].get_name(), players[1].wins);
}