Skip to content

Commit

Permalink
chore: lint and comments
Browse files Browse the repository at this point in the history
Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>
  • Loading branch information
thomas-mauran committed May 6, 2024
1 parent e35269d commit 80d861c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 71 deletions.
170 changes: 100 additions & 70 deletions src/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ pub enum DisplayMode {
DEFAULT,
ASCII,
}

/*
The board struct is the main struct of the chess game
It contains all the information about the game state
*/
pub struct Board {
pub board: [[Option<(PieceType, PieceColor)>; 8]; 8],
pub cursor_coordinates: [i8; 2],
Expand Down Expand Up @@ -172,14 +175,15 @@ impl Board {
_ => Vec::new(),
}
}

pub fn switch_player_turn(&mut self) {
match self.player_turn {
PieceColor::White => self.player_turn = PieceColor::Black,
PieceColor::Black => self.player_turn = PieceColor::White,
}
}

// Methods to change the position of the cursor
// Cursor movement methods
pub fn cursor_up(&mut self) {
if !self.is_checkmate && !self.is_draw && !self.is_promotion {
if self.is_cell_selected() {
Expand Down Expand Up @@ -227,17 +231,19 @@ impl Board {
}
}

pub fn did_king_already_move(&self) -> bool {
for i in 0..self.move_history.len() {
if self.move_history[i].piece_type == PieceType::King
&& get_player_turn_in_modulo(self.player_turn) == i % 2
{
return true;
}
// Method to unselect a cell
pub fn unselect_cell(&mut self) {
if self.is_cell_selected() {
self.selected_coordinates[0] = UNDEFINED_POSITION;
self.selected_coordinates[1] = UNDEFINED_POSITION;
self.selected_piece_cursor = 0;
self.cursor_coordinates = self.old_cursor_position
}
false
}

/* Method to move the selected piece cursor
We make sure that the cursor is in the authorized positions
*/
fn move_selected_piece_cursor(&mut self, first_time_moving: bool, direction: i8) {
let piece_color = get_piece_color(self.board, self.selected_coordinates);
let piece_type = get_piece_type(self.board, self.selected_coordinates);
Expand Down Expand Up @@ -309,7 +315,7 @@ impl Board {
// If we play against a bot we will play his move and switch the player turn again
if self.is_game_against_bot {
self.is_promotion = self.is_latest_move_promotion();
if self.is_promotion == false {
if !self.is_promotion {
self.is_checkmate = self.is_checkmate();
self.is_promotion = self.is_latest_move_promotion();
if !self.is_checkmate {
Expand All @@ -326,6 +332,21 @@ impl Board {
self.is_promotion = self.is_latest_move_promotion();
}

// Check if the king has already moved (used for castling)
pub fn did_king_already_move(&self) -> bool {
for i in 0..self.move_history.len() {
if self.move_history[i].piece_type == PieceType::King
&& get_player_turn_in_modulo(self.player_turn) == i % 2
{
return true;
}
}
false
}

/* Method to make a move for the bot
We use the UCI protocol to communicate with the chess engine
*/
pub fn bot_move(&mut self) {
let engine = match &self.engine {
Some(engine) => engine,
Expand All @@ -351,45 +372,46 @@ impl Board {
[to_y as usize, to_x as usize],
);
}

// Convert the history and game status to a FEN string
pub fn fen_position(&self) -> String {
let mut result = String::new();

// We loop through the board and convert it to a FEN string
for i in 0..8i8 {
for j in 0..8i8 {
match (
// We get the piece type and color
let (piece_type, piece_color) = (
get_piece_type(self.board, [i, j]),
get_piece_color(self.board, [i, j]),
) {
(piece_type, piece_color) => {
match PieceType::piece_to_fen_enum(piece_type, piece_color) {
// Pattern match directly on the result of piece_to_fen_enum
"" => {
// Check if the string is not empty before using chars().last()
if let Some(last_char) = result.chars().last() {
if last_char.is_ascii_digit() {
let incremented_char = char::from_digit(
last_char.to_digit(10).unwrap_or(0) + 1,
10,
)
.unwrap_or_default();
// Remove the old number and add the new incremented one
result.pop();
result.push_str(incremented_char.to_string().as_str());
} else {
result.push('1');
}
} else {
result.push('1');
}
}
letter => {
// If the result is not an empty string, push '1'
result.push_str(letter);
);
let letter = PieceType::piece_to_fen_enum(piece_type, piece_color);
// Pattern match directly on the result of piece_to_fen_enum
match letter {
"" => {
// Check if the string is not empty before using chars().last()
if let Some(last_char) = result.chars().last() {
if last_char.is_ascii_digit() {
let incremented_char = char::from_digit(
last_char.to_digit(10).unwrap_or(0) + 1,
10,
)
.unwrap_or_default();
// Remove the old number and add the new incremented one
result.pop();
result.push_str(incremented_char.to_string().as_str());
} else {
result.push('1');
}
} else {
result.push('1');
}
}
}
letter => {
// If the result is not an empty string, push '1'
result.push_str(letter);
}
};
}
result.push('/')
}
Expand All @@ -410,7 +432,7 @@ impl Board {
}
// queen side black castle availability
if !did_piece_already_move(&self.move_history, (Some(PieceType::Rook), [0, 0])) {
result.push_str("q");
result.push('q');
}
} else {
result.push_str(" -")
Expand All @@ -426,23 +448,24 @@ impl Board {
// FEN starts counting from 1 not 0
converted_move += &format!("{}", 8 - last_move.from_y + 1).to_string();

result.push_str(" ");
result.push(' ');
result.push_str(&converted_move);
}
} else {
result.push_str(" -");
}

result.push_str(" ");
result.push(' ');

result.push_str(&self.consecutive_non_pawn_or_capture.to_string());
result.push_str(" ");
result.push(' ');

result.push_str(&(self.move_history.len() / 2).to_string());

result
}

// Check if the pawn moved two cells (used for en passant)
pub fn did_pawn_move_two_cells(&self) -> bool {
match self.move_history.last() {
Some(last_move) => {
Expand All @@ -451,11 +474,13 @@ impl Board {
if last_move.piece_type == PieceType::Pawn && distance == 2 {
return true;
}
return false;
false
}
_ => false,
}
}

// Method to promote a pawn
pub fn promote_piece(&mut self) {
if let Some(last_move) = self.move_history.last() {
let new_piece = match self.promotion_cursor {
Expand All @@ -477,6 +502,7 @@ impl Board {
self.promotion_cursor = 0;
}

// Move a piece from a cell to another
pub fn move_piece_on_the_board(&mut self, from: [usize; 2], to: [usize; 2]) {
if !is_valid([from[0] as i8, from[1] as i8]) || !is_valid([to[0] as i8, to[1] as i8]) {
return;
Expand Down Expand Up @@ -524,7 +550,7 @@ impl Board {
let distance = from_x - to_x;
let direction_x = if distance > 0 { -1 } else { 1 };

let mut row_index_rook = 0;
let row_index_rook;

let row_index = from_x + direction_x * 2;

Expand All @@ -534,18 +560,21 @@ impl Board {
// We put the rook 3 cells from it's position if it's a big castling else 2 cells
// If it is playing against a bot we will receive 4 -> 6 and 4 -> 2 for to_x instead of 4 -> 7 and 4 -> 0
// big castling
if distance > 0 {
row_index_rook = 3;
if self.is_game_against_bot && self.player_turn == PieceColor::Black {
to_x = 0;
match distance {
distance if distance > 0 => {
row_index_rook = 3;
if self.is_game_against_bot && self.player_turn == PieceColor::Black {
to_x = 0;
}
}
} else if distance < 0 {
row_index_rook = 5;
if self.is_game_against_bot && self.player_turn == PieceColor::Black {
to_x = 7;
distance if distance < 0 => {
row_index_rook = 5;
if self.is_game_against_bot && self.player_turn == PieceColor::Black {
to_x = 7;
}
}
_ => unreachable!("Undefined distance for castling"),
}

self.board[to[0]][row_index_rook as usize] = self.board[to[0]][to_x as usize];

// We remove the latest rook
Expand All @@ -566,15 +595,7 @@ impl Board {
});
}

pub fn unselect_cell(&mut self) {
if self.is_cell_selected() {
self.selected_coordinates[0] = UNDEFINED_POSITION;
self.selected_coordinates[1] = UNDEFINED_POSITION;
self.selected_piece_cursor = 0;
self.cursor_coordinates = self.old_cursor_position
}
}

// Method to get the number of authorized positions for the current player (used for the end condition)
pub fn number_of_authorized_positions(&self) -> usize {
let mut possible_moves: Vec<Vec<i8>> = vec![];

Expand All @@ -594,6 +615,7 @@ impl Board {
possible_moves.len()
}

// Check if the latest move is en passant
fn is_latest_move_en_passant(&self, from: [usize; 2], to: [usize; 2]) -> bool {
let piece_type_from = get_piece_type(self.board, [from[0] as i8, from[1] as i8]);
let piece_type_to = get_piece_type(self.board, [to[0] as i8, to[1] as i8]);
Expand All @@ -611,6 +633,7 @@ impl Board {
}
}

// Check if the latest move is castling
fn is_latest_move_castling(&self, from: [usize; 2], to: [usize; 2]) -> bool {
let piece_type_from = get_piece_type(self.board, [from[0] as i8, from[1] as i8]);
let piece_type_to = get_piece_type(self.board, [to[0] as i8, to[1] as i8]);
Expand All @@ -625,11 +648,14 @@ impl Board {
}
}

// Check if the latest move is a promotion
fn is_latest_move_promotion(&self) -> bool {
if let Some(last_move) = self.move_history.last() {
if let Some(piece_type_to) = get_piece_type(self.board, [last_move.to_y, last_move.to_x])
if let Some(piece_type_to) =
get_piece_type(self.board, [last_move.to_y, last_move.to_x])
{
if let Some(piece_color) = get_piece_color(self.board, [last_move.to_y, last_move.to_x])
if let Some(piece_color) =
get_piece_color(self.board, [last_move.to_y, last_move.to_x])
{
let last_row = if piece_color == PieceColor::White {
0
Expand All @@ -646,6 +672,7 @@ impl Board {
false
}

// Check if the game is checkmate
pub fn is_checkmate(&self) -> bool {
if !is_getting_checked(self.board, self.player_turn, &self.move_history) {
return false;
Expand All @@ -654,23 +681,25 @@ impl Board {
self.number_of_authorized_positions() == 0
}

// Check if the game is a draw
pub fn draw_by_repetition(&self) -> bool {
if self.move_history.len() >= 9 {
let last_ten: Vec<PieceMove> =
self.move_history.iter().rev().take(9).cloned().collect();

if (last_ten[0].clone(), last_ten[1].clone())
== (last_ten[4].clone(), last_ten[5].clone())
&& last_ten[4].clone() == last_ten[8].clone()
&& (last_ten[2].clone(), last_ten[3].clone())
== (last_ten[6].clone(), last_ten[7].clone())
if (last_ten[0], last_ten[1])
== (last_ten[4], last_ten[5])
&& last_ten[4] == last_ten[8]
&& (last_ten[2], last_ten[3])
== (last_ten[6], last_ten[7])
{
return true;
}
}
false
}

// Check if the game is a draw
pub fn is_draw(&self) -> bool {
self.number_of_authorized_positions() == 0
|| self.consecutive_non_pawn_or_capture == 50
Expand Down Expand Up @@ -786,6 +815,7 @@ impl Board {
}
}

// Method to render the right panel history
pub fn history_render(&self, area: Rect, frame: &mut Frame) {
// We write the history board on the side
let history_block = Block::default()
Expand Down
2 changes: 1 addition & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ pub fn get_int_from_char(ch: Option<char>) -> i8 {

pub fn get_latest_move(move_history: &[PieceMove]) -> Option<PieceMove> {
if !move_history.is_empty() {
return Some(move_history[move_history.len() - 1].clone());
return Some(move_history[move_history.len() - 1]);
}
None
}
Expand Down

0 comments on commit 80d861c

Please sign in to comment.