forked from coding-horror/basic-computer-games
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request coding-horror#742 from ugurkupeli/72_Queen/rust
72 queen/rust
- Loading branch information
Showing
5 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
use crate::{ | ||
ai, | ||
util::{self, prompt, PromptResult::*}, | ||
}; | ||
|
||
pub struct Game { | ||
blocks: [u8; 64], | ||
location: Option<u8>, | ||
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<bool>| { | ||
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!(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use crate::{ | ||
game::Game, | ||
util::{prompt, PromptResult::*}, | ||
}; | ||
|
||
mod game; | ||
mod util; | ||
mod ai; | ||
|
||
fn main() { | ||
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; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
use std::io; | ||
|
||
pub enum PromptResult { | ||
Normal(String), | ||
YesNo(bool), | ||
Numeric(i32), | ||
} | ||
|
||
pub fn prompt(is_numeric: Option<bool>, 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::<i32>() { | ||
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 as i32 - loc as i32; | ||
|
||
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 | ||
} | ||
} | ||
|
||
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."# | ||
) | ||
} | ||
} | ||
} |