Add existing files to Git
This commit is contained in:
parent
73d24e7748
commit
0c5991fa20
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": []
|
||||||
|
}
|
||||||
206
src/board.rs
206
src/board.rs
@ -11,6 +11,14 @@ pub struct Board {
|
|||||||
impl fmt::Display for Board {
|
impl fmt::Display for Board {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let horiz_sep_line = "-".repeat(BOARD_SIZE * 2 + 1);
|
let horiz_sep_line = "-".repeat(BOARD_SIZE * 2 + 1);
|
||||||
|
|
||||||
|
// Print numbers at top so I can read the board easier
|
||||||
|
write!(f, " ")?;
|
||||||
|
for j in 0..BOARD_SIZE {
|
||||||
|
write!(f, "{} ", j)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
|
||||||
for i in 0..BOARD_SIZE {
|
for i in 0..BOARD_SIZE {
|
||||||
writeln!(f, " {}", horiz_sep_line)?;
|
writeln!(f, " {}", horiz_sep_line)?;
|
||||||
|
|
||||||
@ -24,12 +32,26 @@ impl fmt::Display for Board {
|
|||||||
}
|
}
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put a line at the bottom of the board too
|
// put a line at the bottom of the board too
|
||||||
writeln!(f, "{}", horiz_sep_line)?;
|
writeln!(f, " {}", horiz_sep_line)?;
|
||||||
|
|
||||||
|
// Print the current score
|
||||||
|
let (white_score, black_score) = self.get_score();
|
||||||
|
writeln!(f, "White Score: {}\nBlack Score: {}", white_score, black_score);
|
||||||
|
|
||||||
|
// Print game over screen
|
||||||
|
if self.game_over() == true {
|
||||||
|
match self.get_winner() {
|
||||||
|
Some(Piece::Black) => writeln!(f, "Black Wins"),
|
||||||
|
Some(Piece::White) => writeln!(f, "White Wins"),
|
||||||
|
None => writeln!(f, "Tie"),
|
||||||
|
}?
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
@ -160,6 +182,56 @@ impl Board {
|
|||||||
}
|
}
|
||||||
captured
|
captured
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep score of each color
|
||||||
|
pub fn get_score(&self) -> (usize, usize) {
|
||||||
|
let mut white_score = 0;
|
||||||
|
let mut black_score = 0;
|
||||||
|
|
||||||
|
for row in &self.board {
|
||||||
|
for &cell in row {
|
||||||
|
match cell {
|
||||||
|
Some(Piece::White) => white_score += 1,
|
||||||
|
Some(Piece::Black) => black_score += 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(white_score, black_score)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the winning piece (for game over screen mainly)
|
||||||
|
pub fn get_winner(&self) -> Option<Piece> {
|
||||||
|
let (white_score, black_score) = self.get_score();
|
||||||
|
|
||||||
|
// White wins
|
||||||
|
if white_score > black_score {
|
||||||
|
Some(Piece::White)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Black Wins
|
||||||
|
else if black_score > white_score {
|
||||||
|
Some(Piece::Black)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tie
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn game_over(&self) -> bool {
|
||||||
|
let (white_score, black_score) = self.get_score();
|
||||||
|
let max_score = BOARD_SIZE * BOARD_SIZE;
|
||||||
|
let combined_score = black_score + white_score;
|
||||||
|
|
||||||
|
if max_score == combined_score {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -262,4 +334,132 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(board.place(2, 5, Piece::Black), Ok(()), "{}", board);
|
assert_eq!(board.place(2, 5, Piece::Black), Ok(()), "{}", board);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Test corner capture from top-left corner
|
||||||
|
#[test]
|
||||||
|
fn corner_capture_top_left() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Black pieces at (0, 0) and (1, 0), and (0, 1) to create capture opportunity
|
||||||
|
board.place_unchecked(0, 0, Piece::Black);
|
||||||
|
board.place_unchecked(1, 0, Piece::White);
|
||||||
|
board.place_unchecked(0, 1, Piece::White);
|
||||||
|
|
||||||
|
board.propegate_from(0, 0);
|
||||||
|
|
||||||
|
// Capture white piece at (0, 1) and (1, 0)
|
||||||
|
assert_eq!(board.get(0, 1), &Some(Piece::Black));
|
||||||
|
assert_eq!(board.get(1, 0), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test corner capture from top-right corner
|
||||||
|
#[test]
|
||||||
|
fn corner_capture_top_right() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Black pieces at (0, 7) and (1, 7), and (0, 6) to create capture opportunity
|
||||||
|
board.place_unchecked(0, 7, Piece::Black);
|
||||||
|
board.place_unchecked(1, 7, Piece::White);
|
||||||
|
board.place_unchecked(0, 6, Piece::White);
|
||||||
|
|
||||||
|
board.propegate_from(0, 7);
|
||||||
|
|
||||||
|
// Capture white piece at (0, 6) and (1, 7)
|
||||||
|
assert_eq!(board.get(0, 6), &Some(Piece::Black));
|
||||||
|
assert_eq!(board.get(1, 7), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test corner capture from bottom-left corner
|
||||||
|
#[test]
|
||||||
|
fn corner_capture_bottom_left() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Black pieces at (7, 0) and (6, 0), and (7, 1) to create capture opportunity
|
||||||
|
board.place_unchecked(7, 0, Piece::Black);
|
||||||
|
board.place_unchecked(6, 0, Piece::White);
|
||||||
|
board.place_unchecked(7, 1, Piece::White);
|
||||||
|
|
||||||
|
board.propegate_from(7, 0);
|
||||||
|
|
||||||
|
// Capture white piece at (7, 1) and (6, 0)
|
||||||
|
assert_eq!(board.get(7, 1), &Some(Piece::Black));
|
||||||
|
assert_eq!(board.get(6, 0), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test corner capture from bottom-right corner
|
||||||
|
#[test]
|
||||||
|
fn corner_capture_bottom_right() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Black pieces at (7, 7) and (6, 7), and (7, 6) to create capture opportunity
|
||||||
|
board.place_unchecked(7, 7, Piece::Black);
|
||||||
|
board.place_unchecked(6, 7, Piece::White);
|
||||||
|
board.place_unchecked(7, 6, Piece::White);
|
||||||
|
|
||||||
|
board.propegate_from(7, 7);
|
||||||
|
|
||||||
|
// Capture white piece at (7, 6) and (6, 7)
|
||||||
|
assert_eq!(board.get(7, 6), &Some(Piece::Black));
|
||||||
|
assert_eq!(board.get(6, 7), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test capture from top-left corner (horizontal)
|
||||||
|
#[test]
|
||||||
|
fn capture_top_left_horiz() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Create a scenario where a capture should happen horizontally from (0, 0)
|
||||||
|
board.place_unchecked(0, 0, Piece::Black);
|
||||||
|
board.place_unchecked(0, 1, Piece::White);
|
||||||
|
board.place_unchecked(0, 2, Piece::Black);
|
||||||
|
|
||||||
|
board.propegate_from(0, 2);
|
||||||
|
|
||||||
|
assert_eq!(board.get(0, 1), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test capture from top-right corner (horizontal)
|
||||||
|
#[test]
|
||||||
|
fn capture_top_right_horiz() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Create a scenario where a capture should happen horizontally from (0, 7)
|
||||||
|
board.place_unchecked(0, 7, Piece::Black);
|
||||||
|
board.place_unchecked(0, 6, Piece::White);
|
||||||
|
board.place_unchecked(0, 5, Piece::Black);
|
||||||
|
|
||||||
|
board.propegate_from(0, 5);
|
||||||
|
|
||||||
|
assert_eq!(board.get(0, 6), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test capture from top-left corner (vertical)
|
||||||
|
#[test]
|
||||||
|
fn capture_top_left_vert() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Create a scenario where a capture should happen vertically from (0, 0)
|
||||||
|
board.place_unchecked(0, 0, Piece::Black);
|
||||||
|
board.place_unchecked(1, 0, Piece::White);
|
||||||
|
board.place_unchecked(2, 0, Piece::Black);
|
||||||
|
|
||||||
|
board.propegate_from(2, 0);
|
||||||
|
|
||||||
|
assert_eq!(board.get(1, 0), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test capture from bottom-left corner (vertical)
|
||||||
|
#[test]
|
||||||
|
fn capture_bottom_left_vert() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
// Create a scenario where a capture should happen vertically from (7, 0)
|
||||||
|
board.place_unchecked(7, 0, Piece::Black);
|
||||||
|
board.place_unchecked(6, 0, Piece::White);
|
||||||
|
board.place_unchecked(5, 0, Piece::Black);
|
||||||
|
|
||||||
|
board.propegate_from(5, 0);
|
||||||
|
|
||||||
|
assert_eq!(board.get(6, 0), &Some(Piece::Black));
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/game.rs
49
src/game.rs
@ -1,5 +1,4 @@
|
|||||||
use crate::{agent::Agent, board::Board};
|
use crate::{agent::Agent, board::Board};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
players: [Box<dyn Agent>; 2],
|
players: [Box<dyn Agent>; 2],
|
||||||
@ -29,31 +28,59 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle when a move is made
|
||||||
pub fn step(&mut self, player_i: usize) {
|
pub fn step(&mut self, player_i: usize) {
|
||||||
let player_move = self.players[player_i].next_move(&self.board);
|
let player_color = self.players[player_i].color();
|
||||||
if let Some((i, j)) = player_move {
|
|
||||||
if let Ok(()) = self.board.place(i, j, self.players[player_i].color()) {
|
loop {
|
||||||
|
let player_move = self.players[player_i].next_move(&self.board);
|
||||||
|
|
||||||
|
if let Some((i, j)) = player_move {
|
||||||
|
match self.board.place(i, j, player_color) {
|
||||||
|
// Check if its a valid move
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Player {} placed at ({}, {})", player_i, i, j);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lets the player try again if the move is invalid
|
||||||
|
// Now we dont need to restart the game if we mess up
|
||||||
|
Err(err) => {
|
||||||
|
println!("Invalid move by Player {}: {}. Try again.", player_i, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!("handle invalid player move");
|
println!("Player {} did not make a move!", player_i);
|
||||||
|
return; // No valid move available
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic!("player {} did not make a move", player_i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO! make this loop good
|
// TODO! make this loop good
|
||||||
pub fn game_loop(&mut self) {
|
pub fn game_loop(&mut self) {
|
||||||
let mut i = 0;
|
let mut current_player: usize = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// alternate which player plays
|
// alternate which player plays
|
||||||
i += 1;
|
current_player += 1;
|
||||||
i %= self.players.len();
|
current_player %= self.players.len();
|
||||||
|
|
||||||
println!("{}", self);
|
println!("{}", self);
|
||||||
|
|
||||||
self.step(i);
|
// Check if the game is over
|
||||||
|
if self.board.game_over() == true {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.step(current_player);
|
||||||
|
|
||||||
// std::thread::sleep(Duration::from_millis(200));
|
// std::thread::sleep(Duration::from_millis(200));
|
||||||
}
|
}
|
||||||
|
// Print Game Over Screen
|
||||||
|
println!("{}", self);
|
||||||
|
match self.board.get_winner() {
|
||||||
|
Some(winner) => println!("Game Over! {} Wins!", winner.text()),
|
||||||
|
None => print!("It's a tie!! You either both suck or are both really good..."),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user