mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-31 15:07:42 -08:00
230 lines
5.6 KiB
Rust
230 lines
5.6 KiB
Rust
use std::io;
|
|
|
|
fn print_intro() {
|
|
println!(
|
|
"Welcome to Even Wins!
|
|
Based on evenwins.bas from Creative Computing
|
|
|
|
Even Wins is a two-person game. You start with
|
|
27 marbles in the middle of the table.
|
|
|
|
Players alternate taking marbles from the middle.
|
|
A player can take 1 to 4 marbles on their turn, and
|
|
turns cannot be skipped. The game ends when there are
|
|
no marbles left, and the winner is the one with an even
|
|
number of marbles.
|
|
"
|
|
);
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum PlayerType {
|
|
Human,
|
|
Computer,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Game {
|
|
turn: PlayerType,
|
|
middle: u32,
|
|
human: u32,
|
|
computer: u32,
|
|
min_take: u32,
|
|
max_take: u32,
|
|
}
|
|
|
|
impl Game {
|
|
fn get_max_take(&mut self) -> u32 {
|
|
if self.max_take > self.middle {
|
|
return self.middle;
|
|
}
|
|
return self.max_take;
|
|
}
|
|
|
|
fn take(&mut self, num: u32) -> bool {
|
|
let max_take = self.get_max_take();
|
|
if num > max_take {
|
|
println!("You can take at most {} marbles", max_take);
|
|
return false;
|
|
}
|
|
if num < self.min_take {
|
|
println!("You must take at least {} marble!", self.min_take);
|
|
return false;
|
|
}
|
|
|
|
self.middle -= num;
|
|
match self.turn {
|
|
PlayerType::Computer => self.computer += num,
|
|
PlayerType::Human => self.human += num,
|
|
}
|
|
return true;
|
|
}
|
|
|
|
fn next(&mut self) {
|
|
self.turn = match self.turn {
|
|
PlayerType::Computer => PlayerType::Human,
|
|
PlayerType::Human => PlayerType::Computer,
|
|
}
|
|
}
|
|
|
|
fn info(&mut self) {
|
|
println!("");
|
|
println!(
|
|
"marbles in the middle: {} **************************",
|
|
self.middle
|
|
);
|
|
println!("# marbles you have: {}", self.human);
|
|
println!("# marbles computer has: {}", self.computer);
|
|
println!("");
|
|
}
|
|
|
|
fn wininfo(&mut self) {
|
|
if self.middle != 0 {
|
|
return;
|
|
}
|
|
println!("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!! All the marbles are taken: Game Over!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
self.info();
|
|
|
|
if self.human % 2 == 0 {
|
|
println!("You are the winner! Congratulations!");
|
|
} else {
|
|
println!("The computer wins: all hail mighty silicon!");
|
|
}
|
|
|
|
println!("");
|
|
}
|
|
}
|
|
|
|
fn human_play(game: &mut Game) {
|
|
println!("It's your turn!");
|
|
loop {
|
|
let max_take = game.get_max_take();
|
|
println!("Marbles to take? ({} - {}) --> ", game.min_take, max_take);
|
|
|
|
let mut num = String::new();
|
|
io::stdin()
|
|
.read_line(&mut num)
|
|
.expect("Failed to read line");
|
|
|
|
let _: u32 = match num.trim().to_uppercase().parse() {
|
|
Ok(num) => {
|
|
if game.take(num) {
|
|
println!("Okay, taking {} marble ...", num);
|
|
break;
|
|
};
|
|
println!("");
|
|
continue;
|
|
}
|
|
_ => {
|
|
println!("Please enter a whole number from 1 to 4");
|
|
println!("");
|
|
continue;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
fn compute_play(game: &mut Game) {
|
|
println!("It's the computer's turn ...");
|
|
|
|
let marbles_to_take: u32;
|
|
|
|
// the magic 6 and 1.5, 5.3 3.4 4.7 3.5 was copy from python implement
|
|
let r: f32 = (game.middle % 6) as f32;
|
|
if game.human % 2 == 0 {
|
|
if r < 1.5 || r > 5.3 {
|
|
marbles_to_take = 1;
|
|
} else {
|
|
marbles_to_take = (r - 1.0) as u32;
|
|
}
|
|
} else if game.middle <= 4 {
|
|
marbles_to_take = game.middle
|
|
} else if r > 3.4 {
|
|
if r < 4.7 || r > 3.5 {
|
|
marbles_to_take = 4;
|
|
} else {
|
|
marbles_to_take = 1;
|
|
}
|
|
} else {
|
|
marbles_to_take = (r + 1.0) as u32;
|
|
}
|
|
|
|
game.take(marbles_to_take);
|
|
println!("Computer takes {} marble ...", marbles_to_take);
|
|
}
|
|
|
|
fn run_game(turn: PlayerType) {
|
|
let mut game = Game {
|
|
turn: turn,
|
|
middle: 27,
|
|
computer: 0,
|
|
human: 0,
|
|
min_take: 1,
|
|
max_take: 4,
|
|
};
|
|
|
|
while game.middle > 0 {
|
|
match game.turn {
|
|
PlayerType::Computer => {
|
|
compute_play(&mut game);
|
|
}
|
|
PlayerType::Human => {
|
|
human_play(&mut game);
|
|
}
|
|
}
|
|
game.info();
|
|
game.next();
|
|
}
|
|
game.wininfo();
|
|
}
|
|
|
|
fn choose_first_player() -> PlayerType {
|
|
loop {
|
|
println!("Do you want to play first? (y/n) -->");
|
|
|
|
let mut flag = String::new();
|
|
io::stdin()
|
|
.read_line(&mut flag)
|
|
.expect("Failed to read line");
|
|
|
|
match flag.trim().to_uppercase().as_str() {
|
|
"Y" => return PlayerType::Human,
|
|
"N" => return PlayerType::Computer,
|
|
_ => {
|
|
println!("Please enter \"y\" if you want to play first,\nor \"n\" if you want to play second.\n");
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
fn choose_play_again() -> bool {
|
|
println!("Would you like to play again? (y/n) --> ");
|
|
let mut flag = String::new();
|
|
io::stdin()
|
|
.read_line(&mut flag)
|
|
.expect("Failed to read line");
|
|
|
|
match flag.trim().to_uppercase().as_str() {
|
|
"Y" => {
|
|
println!("\nOk, let's play again ...\n");
|
|
return true;
|
|
}
|
|
_ => {
|
|
println!("\nOk, thanks for playing ... goodbye!\n");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
print_intro();
|
|
loop {
|
|
let first = choose_first_player();
|
|
run_game(first);
|
|
|
|
if !choose_play_again() {
|
|
return;
|
|
}
|
|
}
|
|
}
|