diff --git a/62_Mugwump/rust/Cargo.toml b/62_Mugwump/rust/Cargo.toml new file mode 100644 index 00000000..3b1d02f5 --- /dev/null +++ b/62_Mugwump/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/62_Mugwump/rust/src/coordinate.rs b/62_Mugwump/rust/src/coordinate.rs new file mode 100644 index 00000000..f13eb240 --- /dev/null +++ b/62_Mugwump/rust/src/coordinate.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] + +#[derive(Debug)] +pub struct Coordinate { + x: u8, + y: u8, + pub state: CoordState, + pub mugwump_number: u8, +} + +impl Coordinate { + pub fn new(pos: (u8, u8), has_mugwump: bool, mugwump_number: i32) -> Self { + let mut mug_no = 0; + + let state = if has_mugwump { + mug_no = mugwump_number; + CoordState::HasMugwump + } else { + CoordState::Normal + }; + + Coordinate { + x: pos.0, + y: pos.1, + state, + mugwump_number: mug_no as u8, + } + } + + pub fn get_pos(&self) -> (u8, u8) { + (self.x, self.y) + } +} + +#[derive(Debug, PartialEq)] +pub enum CoordState { + Normal, + HasMugwump, + Checked, + FoundMugwump, +} diff --git a/62_Mugwump/rust/src/draw.rs b/62_Mugwump/rust/src/draw.rs new file mode 100644 index 00000000..d7fac325 --- /dev/null +++ b/62_Mugwump/rust/src/draw.rs @@ -0,0 +1,67 @@ +use crate::coordinate::{CoordState, Coordinate}; + +pub fn draw_board(coords: &Vec, show_mugwumps: bool) { + let draw_top_bottom = |is_top: bool| { + let (mut left, mut right) = ("╔", "╗"); + + if !is_top { + (left, right) = ("╚", "╝"); + } + + for i in 0..11 { + if i == 0 { + print!("{}══", left); + } else if i == 10 { + print!("═══{}", right) + } else { + print!("══"); + } + } + println!(""); + }; + + draw_top_bottom(true); + + let mut y: i8 = 9; + + print!("║ {} ", y); + for (i, c) in coords.iter().enumerate() { + { + use CoordState::*; + + let mut _char = ' '; + + match c.state { + Normal => _char = '-', + HasMugwump => _char = if show_mugwumps { 'M' } else { '-' }, + Checked => _char = '*', + FoundMugwump => _char = '𑗌', + } + + print!("{} ", _char); + } + + if ((i + 1) % 10) == 0 { + y -= 1; + + print!("║"); + println!(""); + + if i != 99 { + print!("║ {} ", y); + } + } + } + + print!("║ ♥︎ "); + for i in 0..10 { + print!("{} ", i); + + if i == 9 { + print!("║"); + } + } + println!(""); + + draw_top_bottom(false); +} diff --git a/62_Mugwump/rust/src/game.rs b/62_Mugwump/rust/src/game.rs new file mode 100644 index 00000000..f556dfac --- /dev/null +++ b/62_Mugwump/rust/src/game.rs @@ -0,0 +1,162 @@ +use rand::Rng; + +use crate::{ + coordinate::{CoordState, Coordinate}, + draw::draw_board, + util, +}; + +pub struct Game { + pub coords: Vec, + tries: u8, + show_board: bool, +} + +impl Game { + pub fn new(show_board: bool) -> Self { + let mut coords = Vec::new(); + let mut random_indexes = Vec::new(); + let get_random_index = || -> i32 { rand::thread_rng().gen_range(0..100) }; + + for _ in 0..4 { + let mut i = get_random_index(); + while random_indexes.contains(&i) { + i = get_random_index(); + } + random_indexes.push(i); + } + + let mut x = 0; + let mut y: i8 = 9; + + let mut mugwump_number = 0; + + for i in 0..100 { + let mut has_mugwump = false; + + if random_indexes.contains(&i) { + has_mugwump = true; + mugwump_number += 1; + } + + coords.push(Coordinate::new((x, y as u8), has_mugwump, mugwump_number)); + + x += 1; + + if ((i + 1) % 10) == 0 { + x = 0; + y -= 1; + } + } + + Game { + coords, + tries: 0, + show_board, + } + } + + pub fn tick(&mut self) -> Option { + let mut game_over = false; + + if self.tries >= 10 { + println!("SORRY THAT'S 10 TRIES. HERE IS WHERE THEY ARE HIDING"); + + for m in self.get_mugwumps() { + println!("MUGWUMP {} IS AT {:?}", m.mugwump_number, m.get_pos()); + } + + if self.show_board { + draw_board(&self.coords, true); + } + + game_over = true; + } + + if self.get_mugwumps().len() == 0 { + println!("YOU HAVE FOUND ALL MUGWUMPS!"); + + game_over = true; + } + + if game_over { + return util::prompt_bool("THAT WAS FUN! PLAY AGAIN (Y/n)?"); + } + + self.tries += 1; + + if self.show_board { + draw_board(&self.coords, true); + } + + let entered_position = self.input_coordinate(); + self.check_position(entered_position); + + None + } + + fn check_position(&mut self, pos: (u8, u8)) { + if let Some(coord) = self.coords.iter_mut().find(|c| c.get_pos() == pos) { + use CoordState::*; + + match coord.state { + Normal => { + coord.state = Checked; + self.print_distances(pos); + } + HasMugwump => { + coord.state = FoundMugwump; + println!("YOU FOUND MUGWUMP {}", coord.mugwump_number); + self.print_distances(pos); + } + Checked | FoundMugwump => println!("YOU ALREADY LOOKED HERE!"), + } + } + } + + fn print_distances(&self, (x, y): (u8, u8)) { + let print = |m: &Coordinate| { + let (mx, my) = m.get_pos(); + let (x, y, mx, my) = (x as i32, y as i32, mx as i32, my as i32); + let distance = (((x - mx).pow(2) + (y - my).pow(2)) as f32).sqrt(); + + println!( + "YOU ARE {} UNITS FROM MUGWUMP {}", + distance, m.mugwump_number + ); + }; + + for m in self.get_mugwumps() { + print(m); + } + } + + fn input_coordinate(&self) -> (u8, u8) { + let msg = format!("TURN NO. {} WHAT IS YOUR GUESS?", self.tries); + let input = util::prompt(msg.as_str()); + + if !input.contains(",") { + println!("YOU MUST ENTER A COORDINATE: #,#"); + return (0, 0); + } + + let axes: Vec<&str> = input.split(",").collect(); + let mut pos = [0; 2]; + + for (i, a) in axes.iter().enumerate() { + match a.parse::() { + Ok(p) => pos[i] = p as u8, + Err(_) => println!("YOU MUST ENTER A COORDINATE: #,#"), + } + } + + (pos[0], pos[1]) + } + + fn get_mugwumps(&self) -> Vec<&Coordinate> { + self.coords + .iter() + .filter(|c| c.state == CoordState::HasMugwump) + .collect() + } +} diff --git a/62_Mugwump/rust/src/main.rs b/62_Mugwump/rust/src/main.rs new file mode 100644 index 00000000..fbd4479d --- /dev/null +++ b/62_Mugwump/rust/src/main.rs @@ -0,0 +1,44 @@ +mod coordinate; +mod draw; +mod game; +pub mod util; + +use crate::game::Game; + +fn main() { + println!("\n\nMUGWUMP"); + println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + + println!("THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS"); + println!("HIDDEN ON A 10 BY 10 GRID. HOMEBASE IS POSITION 0,0."); + println!("ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH"); + println!("NUMBER BETWEEN 0 AND 9, INCLUSIVE. FIRST NUMBER"); + println!("IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER"); + println!("IS DISTANCE ABOVE HOMEBASE!\n"); + + println!("YOU GET 10 TRIES. AFTER EACH TRY, I WILL TELL"); + println!("YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\n"); + + let mut _quit = false; + + while !_quit { + let mut show_board = true; + + if let Some(r) = util::prompt_bool("WOULD YOU LIKE TO SEE THE BOARD?") { + show_board = r; + } + + let mut game = Game::new(show_board); + + loop { + if let Some(again) = game.tick() { + if !again { + _quit = true; + } else { + println!("FOUR MORE MUGWUMPS ARE NOW IN HIDING") + } + break; + } + } + } +} diff --git a/62_Mugwump/rust/src/util.rs b/62_Mugwump/rust/src/util.rs new file mode 100644 index 00000000..ff4e9ecb --- /dev/null +++ b/62_Mugwump/rust/src/util.rs @@ -0,0 +1,25 @@ +use std::io; + +pub fn prompt(msg: &str) -> String { + println!("\n{}", msg); + + let mut input = String::new(); + + io::stdin() + .read_line(&mut input) + .expect("Failed to read line."); + + input.trim().to_string() +} + +pub fn prompt_bool(msg: &str) -> Option { + loop { + let response = prompt(msg); + + match response.to_uppercase().as_str() { + "Y" | "YES" => return Some(true), + "N" | "NO" => return Some(false), + _ => println!("PLEASE ENTER (Y)ES or (N)O."), + } + } +}