diff --git a/04_Awari/rust/Cargo.toml b/04_Awari/rust/Cargo.toml index 1ec69633..1c2935d4 100644 --- a/04_Awari/rust/Cargo.toml +++ b/04_Awari/rust/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rand = "0.8.5" \ No newline at end of file diff --git a/04_Awari/rust/src/main.rs b/04_Awari/rust/src/main.rs index 4c1b4a14..7aa00831 100644 --- a/04_Awari/rust/src/main.rs +++ b/04_Awari/rust/src/main.rs @@ -1,3 +1,9 @@ +use std::{thread, time::Duration}; + +use rand::Rng; + +// AI "learning" is not implemented. Don't have the time. - Ugur + fn main() { loop { let mut game = Game::default(); @@ -12,11 +18,13 @@ fn main() { } enum DistributeResult { - Normal, // Leftover beans - EndOnHomePit(bool), // "true" if ended on Player Home Pit - EndOnEmptyPit(usize), // "index" of the empty pit within the Row + Normal, + // Leftover beans + EndOnHomePit(bool), + // "true" if ended on Player Home Pit + EndOnEmptyPit(usize), + // "index" of the empty pit within the Row ChosenEmpty, - GameOver, } struct Game { @@ -26,7 +34,7 @@ struct Game { impl Default for Game { fn default() -> Self { - println!("\t\t\t AWARI"); + println!("\n\n\t\t AWARI"); println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); Self { @@ -39,35 +47,68 @@ impl Default for Game { impl Game { fn step_through(&mut self, mut index: usize) -> usize { let mut bean_amount = self.pits[index]; + self.pits[index] = 0; loop { + index += 1; + + if index > self.pits.len() - 1 { + index = 0; + } + self.pits[index] += 1; bean_amount -= 1; if bean_amount == 0 { return index; } - - index += 1; - if index > self.pits.len() - 1 { - index = 0; - } } } fn play_turn(&mut self, is_repeat: bool) -> bool { use DistributeResult::*; + if self.is_game_over() { + println!("\nGame Over!"); + let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); + if player_beans == ai_beans { + println!("It's a draw") + } else if player_beans > ai_beans { + println!("You win by {}", player_beans - ai_beans); + } else { + println!("I win by {}", ai_beans - player_beans); + } + return true; + } + let chosen_index = if self.player_turn { - player_prompt(if is_repeat { "Again?" } else { "Your move?" }) + player_prompt(if is_repeat { "Again?" } else { "Your move?" }) - 1 } else { - println!("My move is "); - 0 // ai choice + println!("========================"); + + thread::sleep(Duration::from_secs(1)); + + let non_empty_pits: Vec = self + .pits + .iter() + .enumerate() + .filter(|&(i, p)| (7..13).contains(&i) && *p > 0) + .map(|(i, _)| i) + .collect(); + let random_index = rand::thread_rng().gen_range(0..non_empty_pits.len()); + let ai_move = non_empty_pits[random_index]; + + println!("My move is {}", ai_move - 6); + + println!("========================"); + ai_move }; match self.process_choice(chosen_index) { Normal => (), EndOnHomePit(player) => { + self.draw(); + if player == self.player_turn && !is_repeat { self.play_turn(true); } @@ -85,34 +126,25 @@ impl Game { println!("Chosen pit is empty"); return self.play_turn(is_repeat); } - GameOver => { - let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); - if player_beans == ai_beans { - println!("It's a draw") - } else if player_beans > ai_beans { - println!("You win by {}", player_beans - ai_beans); - } else { - println!("I win by {}", ai_beans - player_beans); - } - return true; - } } - self.player_turn = !self.player_turn; + + if !is_repeat { + self.player_turn = !self.player_turn; + } + false } pub fn process_choice(&mut self, index: usize) -> DistributeResult { use DistributeResult::*; - if self.pits[index + 1] == 0 { + if self.pits[index] == 0 { return ChosenEmpty; } - let last_index = self.step_through(index + 1); + let last_index = self.step_through(index); - if self.is_gameover() { - return GameOver; - } else if last_index == 6 && self.player_turn { + if last_index == 6 && self.player_turn { return EndOnHomePit(true); } else if last_index == 13 && !self.player_turn { return EndOnHomePit(false); @@ -123,31 +155,34 @@ impl Game { Normal } - fn is_gameover(&self) -> bool { - for (i, p) in self.pits.iter().enumerate() { - if i != 6 || i != 13 { - if *p > 0 { - return false; - } - } - } - true + fn is_game_over(&self) -> bool { + let player_empty = !(0..6).any(|i| self.pits[i] > 0); + let ai_empty = !(7..13).any(|i| self.pits[i] > 0); + player_empty || ai_empty } fn draw(&self) { let row_as_string = |player: bool| -> String { let mut row_as_string = String::new(); + let range = if player { 0..6 } else { 7..13 }; + range.for_each(|i| { let mut bean_amount_as_string = self.pits[i].to_string(); bean_amount_as_string.push_str(" "); - row_as_string.push_str(&bean_amount_as_string); + + if player { + row_as_string.push_str(&bean_amount_as_string); + } else { + row_as_string.insert_str(0, &bean_amount_as_string); + } }); - return row_as_string; + + row_as_string }; println!( - " {}\n{}\t\t {}\n {}", + "\n {}\n{} {}\n {}\n", row_as_string(false), self.pits[13].to_string(), self.pits[6].to_string(),