mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-07 10:50:53 -08:00
Merge pull request #738 from ugurkupeli/62_Mugwump/rust
62 mugwump/rust
This commit is contained in:
9
62_Mugwump/rust/Cargo.toml
Normal file
9
62_Mugwump/rust/Cargo.toml
Normal file
@@ -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"
|
||||||
41
62_Mugwump/rust/src/coordinate.rs
Normal file
41
62_Mugwump/rust/src/coordinate.rs
Normal file
@@ -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,
|
||||||
|
}
|
||||||
67
62_Mugwump/rust/src/draw.rs
Normal file
67
62_Mugwump/rust/src/draw.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use crate::coordinate::{CoordState, Coordinate};
|
||||||
|
|
||||||
|
pub fn draw_board(coords: &Vec<Coordinate>, 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);
|
||||||
|
}
|
||||||
162
62_Mugwump/rust/src/game.rs
Normal file
162
62_Mugwump/rust/src/game.rs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
coordinate::{CoordState, Coordinate},
|
||||||
|
draw::draw_board,
|
||||||
|
util,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Game {
|
||||||
|
pub coords: Vec<Coordinate>,
|
||||||
|
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<bool> {
|
||||||
|
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::<usize>() {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
44
62_Mugwump/rust/src/main.rs
Normal file
44
62_Mugwump/rust/src/main.rs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
62_Mugwump/rust/src/util.rs
Normal file
25
62_Mugwump/rust/src/util.rs
Normal file
@@ -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<bool> {
|
||||||
|
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."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user