From e89b7128b6e02cc15e250b2e44e1271a0fb940d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20K=C3=BCpeli?= Date: Fri, 6 May 2022 22:48:24 +0300 Subject: [PATCH 1/2] rust port - draw board - legal move checks --- 72_Queen/rust/Cargo.toml | 9 +++++ 72_Queen/rust/src/draw.rs | 75 +++++++++++++++++++++++++++++++++++++++ 72_Queen/rust/src/main.rs | 9 +++++ 72_Queen/rust/src/util.rs | 34 ++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 72_Queen/rust/Cargo.toml create mode 100644 72_Queen/rust/src/draw.rs create mode 100644 72_Queen/rust/src/main.rs create mode 100644 72_Queen/rust/src/util.rs diff --git a/72_Queen/rust/Cargo.toml b/72_Queen/rust/Cargo.toml new file mode 100644 index 00000000..3b1d02f5 --- /dev/null +++ b/72_Queen/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/72_Queen/rust/src/draw.rs b/72_Queen/rust/src/draw.rs new file mode 100644 index 00000000..4ded922f --- /dev/null +++ b/72_Queen/rust/src/draw.rs @@ -0,0 +1,75 @@ +pub fn draw_board(q: u8) { + let mut blocks = Vec::new(); + let mut block = 91; + + for _ in 0..8 { + for _ in 0..8 { + block -= 10; + blocks.push(block); + println!("{}", block); + } + block += 91; + } + + let draw_h_border = |top: Option| { + let corners; + + if let Some(top) = top { + if top { + corners = ("┌", "┐", "┬"); + } else { + corners = ("└", "┘", "┴"); + } + } else { + corners = ("├", "┤", "┼"); + } + + print!("{}", corners.0); + + for i in 0..8 { + let corner = if i == 7 { corners.1 } else { corners.2 }; + + print!("───{}", corner); + } + println!(); + }; + + draw_h_border(Some(true)); + + let mut column = 0; + let mut row = 0; + + for block in blocks.iter() { + let block = *block as u8; + + let n = if block == q { + " Q ".to_string() + } else { + block.to_string() + }; + + if block > 99 { + print!("│{}", n); + } else { + print!("│{} ", n); + } + + column += 1; + + if column != 1 && (column % 8) == 0 { + column = 0; + row += 1; + + print!("│"); + println!(); + + if row == 8 { + draw_h_border(Some(false)); + } else { + draw_h_border(None); + } + } + } + + println!(); +} diff --git a/72_Queen/rust/src/main.rs b/72_Queen/rust/src/main.rs new file mode 100644 index 00000000..75c3d4de --- /dev/null +++ b/72_Queen/rust/src/main.rs @@ -0,0 +1,9 @@ +use draw::draw_board; + +mod draw; +mod util; + +fn main() { + draw_board(158); + println!("{}",util::is_move_legal(32,63)); +} diff --git a/72_Queen/rust/src/util.rs b/72_Queen/rust/src/util.rs new file mode 100644 index 00000000..291eaa04 --- /dev/null +++ b/72_Queen/rust/src/util.rs @@ -0,0 +1,34 @@ +pub fn is_move_legal(loc: u8, mov: u8) -> bool { + let dt: i32 = (mov - loc).into(); + + if dt.is_negative() { + return false; + } + + if (dt % 21) == 0 || (dt % 10) == 0 || (dt % 11) == 0 { + return true; + } + + false +} + +pub fn is_legal_start(loc: u8) -> bool { + let mut legal_spots = Vec::new(); + let start: u8 = 11; + + legal_spots.push(start); + + for i in 1..=7 { + legal_spots.push(start + (10 * i)); + } + + for i in 1..=7 { + legal_spots.push(start + (11 * i)); + } + + if legal_spots.contains(&loc) { + true + } else { + false + } +} From 21c0faeeb08e5a16ea1a855420cb95fb8ea95041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20K=C3=BCpeli?= Date: Sat, 7 May 2022 01:11:36 +0300 Subject: [PATCH 2/2] rust port final --- 72_Queen/rust/src/ai.rs | 30 +++++++ 72_Queen/rust/src/draw.rs | 75 ---------------- 72_Queen/rust/src/game.rs | 180 ++++++++++++++++++++++++++++++++++++++ 72_Queen/rust/src/main.rs | 28 +++++- 72_Queen/rust/src/util.rs | 82 ++++++++++++++++- 5 files changed, 315 insertions(+), 80 deletions(-) create mode 100644 72_Queen/rust/src/ai.rs delete mode 100644 72_Queen/rust/src/draw.rs create mode 100644 72_Queen/rust/src/game.rs diff --git a/72_Queen/rust/src/ai.rs b/72_Queen/rust/src/ai.rs new file mode 100644 index 00000000..cf4d0310 --- /dev/null +++ b/72_Queen/rust/src/ai.rs @@ -0,0 +1,30 @@ +use crate::util; + +const PREFERRED_MOVES: [u8; 5] = [158, 72, 75, 126, 127]; +const SAFE_MOVES: [u8; 2] = [44, 41]; + +pub fn get_computer_move(loc: u8) -> u8 { + if SAFE_MOVES.contains(&loc) { + return random_move(loc); + } + + for m in PREFERRED_MOVES { + if util::is_move_legal(loc, m) && m != loc { + return m; + } + } + + random_move(loc) +} + +fn random_move(l: u8) -> u8 { + let r: f32 = rand::random(); + + if r > 0.6 { + l + 11 + } else if r > 0.3 { + l + 21 + } else { + l + 10 + } +} diff --git a/72_Queen/rust/src/draw.rs b/72_Queen/rust/src/draw.rs deleted file mode 100644 index 4ded922f..00000000 --- a/72_Queen/rust/src/draw.rs +++ /dev/null @@ -1,75 +0,0 @@ -pub fn draw_board(q: u8) { - let mut blocks = Vec::new(); - let mut block = 91; - - for _ in 0..8 { - for _ in 0..8 { - block -= 10; - blocks.push(block); - println!("{}", block); - } - block += 91; - } - - let draw_h_border = |top: Option| { - let corners; - - if let Some(top) = top { - if top { - corners = ("┌", "┐", "┬"); - } else { - corners = ("└", "┘", "┴"); - } - } else { - corners = ("├", "┤", "┼"); - } - - print!("{}", corners.0); - - for i in 0..8 { - let corner = if i == 7 { corners.1 } else { corners.2 }; - - print!("───{}", corner); - } - println!(); - }; - - draw_h_border(Some(true)); - - let mut column = 0; - let mut row = 0; - - for block in blocks.iter() { - let block = *block as u8; - - let n = if block == q { - " Q ".to_string() - } else { - block.to_string() - }; - - if block > 99 { - print!("│{}", n); - } else { - print!("│{} ", n); - } - - column += 1; - - if column != 1 && (column % 8) == 0 { - column = 0; - row += 1; - - print!("│"); - println!(); - - if row == 8 { - draw_h_border(Some(false)); - } else { - draw_h_border(None); - } - } - } - - println!(); -} diff --git a/72_Queen/rust/src/game.rs b/72_Queen/rust/src/game.rs new file mode 100644 index 00000000..2445980b --- /dev/null +++ b/72_Queen/rust/src/game.rs @@ -0,0 +1,180 @@ +use crate::{ + ai, + util::{self, prompt, PromptResult::*}, +}; + +pub struct Game { + blocks: [u8; 64], + location: Option, + player_move: bool, + show_board: bool, + forfeit: bool, +} + +impl Game { + pub fn new() -> Self { + let mut blocks = [0 as u8; 64]; + + let mut block = 91; + let mut i = 0; + + for _ in 0..8 { + for _ in 0..8 { + block -= 10; + blocks[i] = block; + i += 1; + } + block += 91; + } + + Game { + blocks, + location: None, + player_move: true, + show_board: false, + forfeit: false, + } + } + + pub fn update(&mut self) -> bool { + let mut still_going = true; + + if let Some(l) = self.location { + if self.show_board { + self.draw(l); + } + + match self.player_move { + true => self.player_move(l), + false => { + std::thread::sleep(std::time::Duration::from_secs(1)); + let loc = ai::get_computer_move(l); + println!("COMPUTER MOVES TO SQUARE {}", loc); + self.location = Some(loc); + } + } + + still_going = self.check_location(); + } else { + self.set_start_location(); + } + self.player_move = !self.player_move; + still_going + } + + fn set_start_location(&mut self) { + self.draw(0); + + if let YesNo(yes) = prompt(Some(false), "UPDATE BOARD?") { + self.show_board = yes; + } + + loop { + if let Numeric(n) = prompt(Some(true), "WHERE WOULD YOU LIKE TO START?") { + let n = n as u8; + + if util::is_legal_start(n) { + self.location = Some(n); + break; + } else { + println!("PLEASE READ THE DIRECTIONS AGAIN.\nYOU HAVE BEGUN ILLEGALLY.\n") + } + } + } + } + + fn player_move(&mut self, loc: u8) { + loop { + if let Numeric(n) = prompt(Some(true), "WHAT IS YOUR MOVE?") { + if n == 0 { + self.forfeit = true; + break; + } + + let n = n as u8; + + if util::is_move_legal(loc, n) { + self.location = Some(n); + break; + } else { + println!("Y O U C H E A T . . . TRY AGAIN? "); + } + } + } + } + + fn check_location(&self) -> bool { + if self.location == Some(158) { + util::print_gameover(self.player_move, self.forfeit); + return false; + } + + true + } + + fn draw(&self, loc: u8) { + let draw_h_border = |top: Option| { + let corners; + + if let Some(top) = top { + if top { + corners = ("┌", "┐", "┬"); + } else { + corners = ("└", "┘", "┴"); + } + } else { + corners = ("├", "┤", "┼"); + } + + print!("{}", corners.0); + + for i in 0..8 { + let corner = if i == 7 { corners.1 } else { corners.2 }; + + print!("───{}", corner); + } + println!(); + }; + + draw_h_border(Some(true)); + + let mut column = 0; + let mut row = 0; + + for block in self.blocks.iter() { + let block = *block as u8; + + let n = if block == loc { + format!("│{}", "*Q*".to_string()) + } else { + let b = block.to_string(); + + if block > 99 { + format!("│{}", b) + } else { + format!("│{} ", b) + } + }; + + print!("{}", n); + + column += 1; + + if column != 1 && (column % 8) == 0 { + column = 0; + row += 1; + + print!("│"); + println!(); + + if row == 8 { + draw_h_border(Some(false)); + } else { + draw_h_border(None); + } + } + } + + println!(); + } +} diff --git a/72_Queen/rust/src/main.rs b/72_Queen/rust/src/main.rs index 75c3d4de..57d65e0f 100644 --- a/72_Queen/rust/src/main.rs +++ b/72_Queen/rust/src/main.rs @@ -1,9 +1,29 @@ -use draw::draw_board; +use crate::{ + game::Game, + util::{prompt, PromptResult::*}, +}; -mod draw; +mod game; mod util; +mod ai; fn main() { - draw_board(158); - println!("{}",util::is_move_legal(32,63)); + util::intro(); + + loop { + let mut game = Game::new(); + + loop { + if !game.update() { + break; + } + } + + if let YesNo(y) = prompt(Some(false), "\nANYONE ELSE CARE TO TRY?") { + if !y { + println!("OK --- THANKS AGAIN."); + break; + } + } + } } diff --git a/72_Queen/rust/src/util.rs b/72_Queen/rust/src/util.rs index 291eaa04..3439aabb 100644 --- a/72_Queen/rust/src/util.rs +++ b/72_Queen/rust/src/util.rs @@ -1,5 +1,46 @@ +use std::io; + +pub enum PromptResult { + Normal(String), + YesNo(bool), + Numeric(i32), +} + +pub fn prompt(is_numeric: Option, msg: &str) -> PromptResult { + use PromptResult::*; + + println!("{msg}"); + + loop { + let mut input = String::new(); + + io::stdin() + .read_line(&mut input) + .expect("**Failed to read input**"); + + if let Some(is_numeric) = is_numeric { + let input = input.trim(); + + if is_numeric { + if let Ok(n) = input.parse::() { + return Numeric(n); + } + println!("PLEASE ENTER A VALID NUMBER!"); + } else { + match input.to_uppercase().as_str() { + "YES" | "Y" => return YesNo(true), + "NO" | "N" => return YesNo(false), + _ => println!("PLEASE ENTER (Y)ES OR (N)O."), + } + } + } else { + return Normal(input); + } + } +} + pub fn is_move_legal(loc: u8, mov: u8) -> bool { - let dt: i32 = (mov - loc).into(); + let dt: i32 = mov as i32 - loc as i32; if dt.is_negative() { return false; @@ -32,3 +73,42 @@ pub fn is_legal_start(loc: u8) -> bool { false } } + +pub fn print_gameover(win: bool, forfeit: bool) { + if win { + println!("C O N G R A T U L A T I O N S . . .\nYOU HAVE WON--VERY WELL PLAYED."); + println!( + "IT LOOKS LIKE I HAVE MET MY MATCH.\nTHANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\n", + ); + } else { + if forfeit { + println!("IT LOOKS LIKE I HAVE WON BY FORFEIT.\n"); + } else { + println!("NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\nTHANKS FOR PLAYING."); + } + } +} + +pub fn intro() { + println!("\n\n\t\tQUEEN"); + println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + + if let PromptResult::YesNo(yes) = prompt(Some(false), "DO YOU WANT INSTRUCTIONS?") { + if yes { + println!( + r#"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS +MOVES. OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT, +DOWN, OR DIAGONALLY DOWN AND TO THE LEFT. +THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER +LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE +COMPUTER. THE FIRST ONE TO PLACE THE QUEEN THERE WINS. +YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES +ON THE TOP ROW OR RIGHT HAND COLUMN. +THAT WILL BE YOUR FIRST MOVE. +WE ALTERNATE MOVES. +YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE. +BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE."# + ) + } + } +}