diff --git a/29_Craps/rust/Cargo.toml b/29_Craps/rust/Cargo.toml new file mode 100644 index 00000000..3b1d02f5 --- /dev/null +++ b/29_Craps/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/29_Craps/rust/src/craps_game.rs b/29_Craps/rust/src/craps_game.rs new file mode 100644 index 00000000..1818c9c0 --- /dev/null +++ b/29_Craps/rust/src/craps_game.rs @@ -0,0 +1,141 @@ +use crate::util; + +enum GameState { + ComeOut, + PointRolls, + GameOver, +} + +pub struct CrapsGame { + wallet: usize, + bet: usize, + point: u8, + state: GameState, +} + +impl CrapsGame { + pub fn new() -> Self { + let wallet = util::read_numeric("\nHow much money do you want to start with?"); + + CrapsGame { + wallet, + bet: 0, + point: 0, + state: GameState::ComeOut, + } + } + + pub fn tick(&mut self) -> bool { + use GameState::*; + + match self.state { + ComeOut => self.new_round(), + PointRolls => self.point_roll(), + GameOver => false, + } + } + + fn point_roll(&mut self) -> bool { + let point = self.point; + + println!("Rolling {point} wins. 7 loses."); + + self.prompt_roll(); + let roll = CrapsGame::roll(); + + if roll == point { + self.player_win(); + } else if roll == 7 { + self.player_lose(); + } + + true + } + + fn new_round(&mut self) -> bool { + println!("\nCome out roll."); + println!("7 and 11 win. 2, 3 and 12 lose.\n"); + + loop { + self.bet = util::read_numeric("Enter your bet:"); + + if self.bet <= self.wallet { + break; + } else { + println!("You don't have that much money!"); + } + } + + self.prompt_roll(); + let point = CrapsGame::roll(); + + match point { + 11 | 7 => { + self.player_win(); + } + 2 | 3 | 12 => { + self.player_lose(); + } + _ => { + self.point = point; + self.state = GameState::PointRolls + } + } + + true + } + + fn player_win(&mut self) { + let bet = self.bet; + + println!("You won ${bet}!"); + + self.wallet += bet; + self.print_wallet(); + + self.state = GameState::ComeOut; + } + + fn player_lose(&mut self) { + let bet = self.bet; + + println!("You lost ${bet}!"); + + self.wallet -= bet; + self.print_wallet(); + + if self.wallet == 0 { + self.game_over(); + } else { + self.state = GameState::ComeOut; + } + } + + fn print_wallet(&self) { + println!("\nYou have ${} in your wallet.", self.wallet); + } + + fn roll() -> u8 { + use rand::Rng; + + let roll = rand::thread_rng().gen_range(2..13); + println!("\nYou rolled {}.", roll); + + roll + } + + fn game_over(&mut self) { + self.state = GameState::GameOver; + } + + fn prompt_roll(&mut self) { + use util::Response::*; + + let response = util::prompt("Ready to roll?"); + + match response { + Yes => (), + No => self.game_over(), + } + } +} diff --git a/29_Craps/rust/src/main.rs b/29_Craps/rust/src/main.rs new file mode 100644 index 00000000..f19e3718 --- /dev/null +++ b/29_Craps/rust/src/main.rs @@ -0,0 +1,27 @@ +mod craps_game; +mod util; +use crate::craps_game::CrapsGame; + +fn main() { + println!("~~Craps~~"); + println!("Creative Computing Morristown, New Jersey\n"); + + let mut quit = false; + + while !quit { + let mut game = CrapsGame::new(); + + loop { + if !game.tick() { + use util::Response::*; + + match util::prompt("New Game?") { + Yes => (), + No => quit = true, + } + + break; + } + } + } +} diff --git a/29_Craps/rust/src/util.rs b/29_Craps/rust/src/util.rs new file mode 100644 index 00000000..9fdd8b98 --- /dev/null +++ b/29_Craps/rust/src/util.rs @@ -0,0 +1,71 @@ +use std::io; + +pub enum Response { + Yes, + No, +} + +pub fn read_line() -> String { + let mut input = String::new(); + + io::stdin() + .read_line(&mut input) + .expect("Error reading line."); + + input +} + +pub fn read_numeric(message: &str) -> usize { + loop { + println!("{}", message); + + let mut ok = true; + + let input = read_line(); + + for c in input.trim().chars() { + if !c.is_numeric() { + println!("You can only enter a number!"); + ok = false; + break; + } + } + + if ok { + let input = input.trim().parse(); + + let _ = match input { + Ok(i) => return i, + Err(e) => { + println!("please input a number ({})", e); + } + }; + } + } +} + +pub fn prompt(msg: &str) -> Response { + use Response::*; + + let mut _r = Response::Yes; + + loop { + println!("\n{}", msg); + + let response = read_line().trim().to_uppercase(); + + match response.as_str() { + "YES" | "Y" => { + _r = Yes; + break; + } + "NO" | "N" => { + _r = No; + break; + } + _ => println!("Please input (Y)es or (N)o."), + }; + } + + _r +}