mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-13 21:46:58 -08:00
rust port
final
This commit is contained in:
30
72_Queen/rust/src/ai.rs
Normal file
30
72_Queen/rust/src/ai.rs
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<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 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!();
|
|
||||||
}
|
|
||||||
180
72_Queen/rust/src/game.rs
Normal file
180
72_Queen/rust/src/game.rs
Normal file
@@ -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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,29 @@
|
|||||||
use draw::draw_board;
|
use crate::{
|
||||||
|
game::Game,
|
||||||
|
util::{prompt, PromptResult::*},
|
||||||
|
};
|
||||||
|
|
||||||
mod draw;
|
mod game;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod ai;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
draw_board(158);
|
util::intro();
|
||||||
println!("{}",util::is_move_legal(32,63));
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,46 @@
|
|||||||
|
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 {
|
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() {
|
if dt.is_negative() {
|
||||||
return false;
|
return false;
|
||||||
@@ -32,3 +73,42 @@ pub fn is_legal_start(loc: u8) -> bool {
|
|||||||
false
|
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."#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user