From e599722e45b3d36fb935a4748066985f6fae736c Mon Sep 17 00:00:00 2001 From: htom Date: Sat, 15 Nov 2025 14:44:44 +0100 Subject: [PATCH 01/20] added client for testing connection and events --- server/Cargo.toml | 4 + server/src/bin/client.rs | 208 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 server/src/bin/client.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index c631dd0..c0086f4 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,3 +14,7 @@ url = "2.5.7" uuid = {version = "1.18.1", features = ["v4", "serde"] } anyhow = "1.0.100" rand = "0.9.2" + +[[bin]] +name = "client" +path = "src/bin/client.rs" diff --git a/server/src/bin/client.rs b/server/src/bin/client.rs new file mode 100644 index 0000000..45e3c56 --- /dev/null +++ b/server/src/bin/client.rs @@ -0,0 +1,208 @@ +use futures_util::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use std::io::{self, Write}; +use tokio_tungstenite::{connect_async, tungstenite::Message}; +use url::Url; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "type")] +enum ClientMessage { + Join { username: String }, + FindMatch, + Move { from: String, to: String }, + Resign, + Chat { text: String }, +} + +#[derive(Serialize, Deserialize, Debug)] +struct ServerMessage { + #[serde(rename = "type")] + message_type: String, + player_id: Option, + match_id: Option, + opponent: Option, + color: Option, + reason: Option, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + println!("Knightly Chess Client"); + println!("========================"); + + // Get server address from user + print!("Enter server address [ws://127.0.0.1:9001]: "); + io::stdout().flush()?; + let mut server_addr = String::new(); + io::stdin().read_line(&mut server_addr)?; + let server_addr = server_addr.trim(); + let server_addr = if server_addr.is_empty() { + "ws://127.0.0.1:9001".to_string() + } else { + server_addr.to_string() + }; + + // Connect to server + println!("Connecting to {}...", server_addr); + let url = Url::parse(&server_addr)?; + let (ws_stream, _) = connect_async(url).await?; + println!("Connected to server!"); + + let (mut write, mut read) = ws_stream.split(); + + // Spawn a task to handle incoming messages + let read_handle = tokio::spawn(async move { + while let Some(message) = read.next().await { + match message { + Ok(msg) => { + if msg.is_text() { + let text = msg.to_text().unwrap(); + println!("\nServer: {}", text); + + // Try to parse as structured message + if let Ok(parsed) = serde_json::from_str::(text) { + match parsed.message_type.as_str() { + "welcome" => { + if let Some(player_id) = parsed.player_id { + println!("Welcome! Your player ID: {}", player_id); + } + } + "match_found" => { + if let (Some(opponent), Some(color), Some(match_id)) = + (parsed.opponent, parsed.color, parsed.match_id) + { + println!( + "Match found! Opponent: {}, Color: {}, Match ID: {}", + opponent, color, match_id + ); + } + } + "error" => { + if let Some(reason) = parsed.reason { + println!("Error: {}", reason); + } + } + _ => {} + } + } + } + } + Err(e) => { + eprintln!("Error receiving message: {}", e); + break; + } + } + } + }); + + // Main loop for sending messages + println!("\nAvailable commands:"); + println!(" join - Join the server"); + println!(" findmatch - Find a match"); + println!(" move - Make a move (e.g., move e2 e4)"); + println!(" chat - Send chat message"); + println!(" resign - Resign from current game"); + println!(" quit - Exit client"); + println!(); + + loop { + print!("āž”ļø Enter command: "); + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + let input = input.trim(); + + if input.is_empty() { + continue; + } + + let parts: Vec<&str> = input.split_whitespace().collect(); + let command = parts[0].to_lowercase(); + + match command.as_str() { + "quit" | "exit" => { + println!("šŸ‘‹ Goodbye!"); + break; + } + "join" => { + if parts.len() >= 2 { + let username = parts[1..].join(" "); + let message = ClientMessage::Join { username }; + send_message(&mut write, &message).await?; + } else { + println!("Usage: join "); + } + } + "findmatch" | "find" => { + let message = ClientMessage::FindMatch; + send_message(&mut write, &message).await?; + println!("šŸ” Searching for a match..."); + } + "move" => { + if parts.len() >= 3 { + let from = parts[1].to_string(); + let to = parts[2].to_string(); + let message = ClientMessage::Move { from, to }; + send_message(&mut write, &message).await?; + println!("ā™Ÿļø Sent move: {} -> {}", parts[1], parts[2]); + } else { + println!("Usage: move (e.g., move e2 e4)"); + } + } + "chat" => { + if parts.len() >= 2 { + let text = parts[1..].join(" "); + let message = ClientMessage::Chat { text }; + send_message(&mut write, &message).await?; + } else { + println!("Usage: chat "); + } + } + "resign" => { + let message = ClientMessage::Resign; + send_message(&mut write, &message).await?; + println!("Resigned from current game"); + } + "help" => { + print_help(); + } + _ => { + println!( + "Unknown command: {}. Type 'help' for available commands.", + command + ); + } + } + } + + // Cleanup + read_handle.abort(); + Ok(()) +} + +async fn send_message( + write: &mut futures_util::stream::SplitSink< + tokio_tungstenite::WebSocketStream< + tokio_tungstenite::MaybeTlsStream, + >, + Message, + >, + message: &ClientMessage, +) -> Result<(), Box> { + let json = serde_json::to_string(message)?; + write.send(Message::Text(json)).await?; + Ok(()) +} + +fn print_help() { + println!("\nšŸ“– Available Commands:"); + println!(" join - Register with a username"); + println!(" findmatch - Enter matchmaking queue"); + println!(" move - Make a chess move"); + println!(" chat - Send chat to opponent"); + println!(" resign - Resign from current game"); + println!(" help - Show this help"); + println!(" quit - Exit the client"); + println!(); +} -- 2.49.1 From a098c8051a0f76a4d300ee880e1c3766a2be91b4 Mon Sep 17 00:00:00 2001 From: htom Date: Sat, 15 Nov 2025 16:41:11 +0100 Subject: [PATCH 02/20] planning done on how the event system works --- server/src/events.rs | 23 +++++++++-------------- server/src/main.rs | 1 + 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/server/src/events.rs b/server/src/events.rs index 8cc43a4..810a5ac 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -21,20 +21,14 @@ pub enum ClientEvent { RequestLegalMoves { fen: String }, } -#[derive(Debug)] -pub enum ServerEvent { - PlayerJoined(Uuid, String), - PlayerLeft(Uuid), - PlayerJoinedQueue(Uuid), - PlayerJoinedMatch(Uuid, Uuid), // player_id, match_id - PlayerMove(Uuid, Step), - PlayerResigned(Uuid), - MatchCreated(Uuid, Uuid, Uuid), // match_id, white_id, black_id +#[derive(Serialize, Deserialize, Debug)] +pub struct EventResponse { + response: Result, } pub struct EventSystem { - sender: mpsc::UnboundedSender<(Uuid, ClientEvent)>, - receiver: Arc>>, + sender: mpsc::UnboundedSender<(Uuid, EventResponse)>, + receiver: Arc>>, } impl Clone for EventSystem { @@ -58,13 +52,13 @@ impl EventSystem { pub async fn send_event( &self, player_id: Uuid, - event: ClientEvent, + event: EventResponse, ) -> Result<(), Box> { self.sender.send((player_id, event))?; Ok(()) } - pub async fn next_event(&self) -> Option<(Uuid, ClientEvent)> { + pub async fn next_event(&self) -> Option<(Uuid, EventResponse)> { let mut receiver = self.receiver.lock().await; receiver.recv().await } @@ -76,6 +70,7 @@ impl Default for EventSystem { } } +/* #[cfg(test)] mod tests { use super::*; @@ -123,4 +118,4 @@ mod tests { "Cloned event system should receive events" ); } -} +}*/ diff --git a/server/src/main.rs b/server/src/main.rs index 0d35baf..ec0ce08 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,6 +1,7 @@ mod connection; mod events; mod matchmaking; +mod messages; use tokio::net::TcpListener; #[tokio::main] -- 2.49.1 From cca852d466080c22a371e65960131b6537960589 Mon Sep 17 00:00:00 2001 From: htom Date: Sat, 15 Nov 2025 18:32:43 +0100 Subject: [PATCH 03/20] Working on event system, join implemented --- server/src/bin/client.rs | 17 ++--------------- server/src/connection.rs | 33 +++++++++++++++++++++++++++++++-- server/src/events.rs | 17 ++++++++++++++--- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/server/src/bin/client.rs b/server/src/bin/client.rs index 45e3c56..1b9edbf 100644 --- a/server/src/bin/client.rs +++ b/server/src/bin/client.rs @@ -67,22 +67,9 @@ async fn main() -> Result<(), Box> { println!("Welcome! Your player ID: {}", player_id); } } - "match_found" => { - if let (Some(opponent), Some(color), Some(match_id)) = - (parsed.opponent, parsed.color, parsed.match_id) - { - println!( - "Match found! Opponent: {}, Color: {}, Match ID: {}", - opponent, color, match_id - ); - } + _ => { + println!("cucc: {:?}", parsed); } - "error" => { - if let Some(reason) = parsed.reason { - println!("Error: {}", reason); - } - } - _ => {} } } } diff --git a/server/src/connection.rs b/server/src/connection.rs index 715ae88..1ec5d42 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -1,3 +1,5 @@ +use crate::events::ClientEvent::*; +use crate::events::{ClientEvent, EventResponse}; use futures_util::{SinkExt, StreamExt}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; @@ -141,8 +143,35 @@ pub async fn handle_connection( let text = message.to_text()?; println!("Received from {}: {}", player_id, text); - // TODO: Parse and handle message with event system - // This will be implemented when we integrate the event system + let client_data: ClientEvent = serde_json::from_str(text) + .expect("Failed to convert data into json at handle_connection"); + + println!("client: {:?}", client_data); + + match client_data { + Join { username } => { + { + let mut conn_map = connections.lock().await; + let mut player = conn_map.get_mut(&player_id).unwrap(); + player.username = Some(username); + } + + //respone to client + let response: EventResponse = EventResponse { + response: core::result::Result::Ok(true), + }; + + println!("response: {:?}", response); + + send_message_to_player( + &connections, + player_id, + &serde_json::to_string(&response).unwrap(), + ) + .await; + } + _ => {} + } } } diff --git a/server/src/events.rs b/server/src/events.rs index 810a5ac..817965a 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -1,9 +1,12 @@ use serde::{Deserialize, Serialize}; +use serde_json::json; use std::sync::Arc; use tokio::sync::Mutex; use tokio::sync::mpsc; use uuid::Uuid; +use crate::connection::ConnectionMap; + #[derive(Serialize, Deserialize, Debug)] pub struct Step { pub from: String, @@ -23,7 +26,7 @@ pub enum ClientEvent { #[derive(Serialize, Deserialize, Debug)] pub struct EventResponse { - response: Result, + pub response: Result, } pub struct EventSystem { @@ -52,9 +55,17 @@ impl EventSystem { pub async fn send_event( &self, player_id: Uuid, - event: EventResponse, + event: &EventResponse, + connections: &ConnectionMap, ) -> Result<(), Box> { - self.sender.send((player_id, event))?; + //self.sender.send((player_id, event))?; + + crate::connection::send_message_to_player( + &connections, + player_id, + &serde_json::to_string(&event).unwrap(), + ); + Ok(()) } -- 2.49.1 From 1c92918692ba0f53824018f7409d37816ba5136f Mon Sep 17 00:00:00 2001 From: htom Date: Sat, 15 Nov 2025 19:33:40 +0100 Subject: [PATCH 04/20] finished join event --- server/src/connection.rs | 9 +++++---- server/src/events.rs | 10 +++++----- server/src/main.rs | 8 ++++---- server/src/matchmaking.rs | 18 +++++++++--------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/server/src/connection.rs b/server/src/connection.rs index 1ec5d42..47b72e8 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -104,7 +104,7 @@ pub async fn handle_connection( connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue, - event_system: crate::events::EventSystem, + //event_system: crate::events::EventSystem, ) -> anyhow::Result<()> { use tokio_tungstenite::accept_async; @@ -152,18 +152,19 @@ pub async fn handle_connection( Join { username } => { { let mut conn_map = connections.lock().await; - let mut player = conn_map.get_mut(&player_id).unwrap(); + let player = conn_map.get_mut(&player_id).unwrap(); player.username = Some(username); } //respone to client let response: EventResponse = EventResponse { - response: core::result::Result::Ok(true), + response: core::result::Result::Ok(()), }; println!("response: {:?}", response); - send_message_to_player( + //event_system.send_event(player_id, &response, &connections); + let _ = send_message_to_player( &connections, player_id, &serde_json::to_string(&response).unwrap(), diff --git a/server/src/events.rs b/server/src/events.rs index 817965a..94b14ea 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -26,10 +26,10 @@ pub enum ClientEvent { #[derive(Serialize, Deserialize, Debug)] pub struct EventResponse { - pub response: Result, + pub response: Result<(), String>, } -pub struct EventSystem { +/*pub struct EventSystem { sender: mpsc::UnboundedSender<(Uuid, EventResponse)>, receiver: Arc>>, } @@ -59,12 +59,13 @@ impl EventSystem { connections: &ConnectionMap, ) -> Result<(), Box> { //self.sender.send((player_id, event))?; - + println!("Hellodsjaoidsaid"); crate::connection::send_message_to_player( &connections, player_id, &serde_json::to_string(&event).unwrap(), - ); + ) + .await; Ok(()) } @@ -81,7 +82,6 @@ impl Default for EventSystem { } } -/* #[cfg(test)] mod tests { use super::*; diff --git a/server/src/main.rs b/server/src/main.rs index ec0ce08..cd50264 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -16,14 +16,14 @@ async fn main() -> anyhow::Result<()> { let waiting_queue = connection::new_waiting_queue(); // Event system for communication between components - let event_system = events::EventSystem::new(); + //let event_system = events::EventSystem::new(); // Start matchmaking background task let matchmaker = matchmaking::MatchmakingSystem::new( connections.clone(), matches.clone(), waiting_queue.clone(), - event_system.clone(), + //event_system.clone(), ); tokio::spawn(async move { matchmaker.run().await; @@ -34,7 +34,7 @@ async fn main() -> anyhow::Result<()> { let connections = connections.clone(); let matches = matches.clone(); let waiting_queue = waiting_queue.clone(); - let event_system = event_system.clone(); + //let event_system = event_system.clone(); tokio::spawn(async move { if let Err(e) = connection::handle_connection( @@ -42,7 +42,7 @@ async fn main() -> anyhow::Result<()> { connections, matches, waiting_queue, - event_system, + //event_system, ) .await { diff --git a/server/src/matchmaking.rs b/server/src/matchmaking.rs index 4f4cc27..1aae4ea 100644 --- a/server/src/matchmaking.rs +++ b/server/src/matchmaking.rs @@ -1,5 +1,5 @@ use crate::connection::{ConnectionMap, GameMatch, MatchMap, WaitingQueue}; -use crate::events::EventSystem; +//use crate::events::EventSystem; use rand::random; use uuid::Uuid; @@ -7,7 +7,7 @@ pub struct MatchmakingSystem { connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue, - event_system: EventSystem, + //event_system: EventSystem, } impl MatchmakingSystem { @@ -15,13 +15,13 @@ impl MatchmakingSystem { connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue, - event_system: EventSystem, + //event_system: EventSystem, ) -> Self { Self { connections, matches, waiting_queue, - event_system, + //event_system, } } @@ -114,7 +114,7 @@ impl MatchmakingSystem { #[cfg(test)] mod tests { use super::*; - use crate::events::EventSystem; + //use crate::events::EventSystem; use uuid::Uuid; use crate::connection::new_connection_map; @@ -126,13 +126,13 @@ mod tests { let connections = new_connection_map(); let matches = new_match_map(); let waiting_queue = new_waiting_queue(); - let event_system = EventSystem::new(); + //let event_system = EventSystem::new(); let matchmaking = MatchmakingSystem::new( connections.clone(), matches.clone(), waiting_queue.clone(), - event_system.clone(), + //event_system.clone(), ); let player1 = Uuid::new_v4(); @@ -172,13 +172,13 @@ mod tests { let connections = new_connection_map(); let matches = new_match_map(); let waiting_queue = new_waiting_queue(); - let event_system = EventSystem::new(); + //let event_system = EventSystem::new(); let matchmaking = MatchmakingSystem::new( connections.clone(), matches.clone(), waiting_queue.clone(), - event_system.clone(), + //event_system.clone(), ); let player1 = Uuid::new_v4(); -- 2.49.1 From c77e534ed8c8e6fcfdcb6c049d9e333d577952b8 Mon Sep 17 00:00:00 2001 From: htom Date: Sat, 15 Nov 2025 19:41:48 +0100 Subject: [PATCH 05/20] removed event system file as it was unused and we do not neet it anymore --- server/src/connection.rs | 33 +++++++--- server/src/events.rs | 132 -------------------------------------- server/src/main.rs | 16 +---- server/src/matchmaking.rs | 29 ++------- 4 files changed, 30 insertions(+), 180 deletions(-) delete mode 100644 server/src/events.rs diff --git a/server/src/connection.rs b/server/src/connection.rs index 47b72e8..19b91dc 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -1,5 +1,4 @@ -use crate::events::ClientEvent::*; -use crate::events::{ClientEvent, EventResponse}; +use crate::connection::ClientEvent::*; use futures_util::{SinkExt, StreamExt}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; @@ -28,6 +27,28 @@ pub fn new_waiting_queue() -> WaitingQueue { Arc::new(Mutex::new(VecDeque::new())) } +#[derive(Serialize, Deserialize, Debug)] +pub struct Step { + pub from: String, + pub to: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "type")] +enum ClientEvent { + Join { username: String }, + FindMatch, + Move { from: String, to: String }, + Resign, + Chat { text: String }, + RequestLegalMoves { fen: String }, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct EventResponse { + pub response: Result<(), String>, +} + #[derive(Debug)] pub struct PlayerConnection { pub id: Uuid, @@ -45,12 +66,6 @@ pub struct GameMatch { pub move_history: Vec, } -#[derive(Serialize, Deserialize, Debug)] -pub struct Step { - pub from: String, - pub to: String, -} - // Message sending utilities pub async fn send_message_to_player( connections: &ConnectionMap, @@ -104,7 +119,6 @@ pub async fn handle_connection( connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue, - //event_system: crate::events::EventSystem, ) -> anyhow::Result<()> { use tokio_tungstenite::accept_async; @@ -163,7 +177,6 @@ pub async fn handle_connection( println!("response: {:?}", response); - //event_system.send_event(player_id, &response, &connections); let _ = send_message_to_player( &connections, player_id, diff --git a/server/src/events.rs b/server/src/events.rs deleted file mode 100644 index 94b14ea..0000000 --- a/server/src/events.rs +++ /dev/null @@ -1,132 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::json; -use std::sync::Arc; -use tokio::sync::Mutex; -use tokio::sync::mpsc; -use uuid::Uuid; - -use crate::connection::ConnectionMap; - -#[derive(Serialize, Deserialize, Debug)] -pub struct Step { - pub from: String, - pub to: String, -} - -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "type")] -pub enum ClientEvent { - Join { username: String }, - FindMatch, - Move { from: String, to: String }, - Resign, - Chat { text: String }, - RequestLegalMoves { fen: String }, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct EventResponse { - pub response: Result<(), String>, -} - -/*pub struct EventSystem { - sender: mpsc::UnboundedSender<(Uuid, EventResponse)>, - receiver: Arc>>, -} - -impl Clone for EventSystem { - fn clone(&self) -> Self { - Self { - sender: self.sender.clone(), - receiver: Arc::clone(&self.receiver), - } - } -} - -impl EventSystem { - pub fn new() -> Self { - let (sender, receiver) = mpsc::unbounded_channel(); - Self { - sender, - receiver: Arc::new(Mutex::new(receiver)), - } - } - - pub async fn send_event( - &self, - player_id: Uuid, - event: &EventResponse, - connections: &ConnectionMap, - ) -> Result<(), Box> { - //self.sender.send((player_id, event))?; - println!("Hellodsjaoidsaid"); - crate::connection::send_message_to_player( - &connections, - player_id, - &serde_json::to_string(&event).unwrap(), - ) - .await; - - Ok(()) - } - - pub async fn next_event(&self) -> Option<(Uuid, EventResponse)> { - let mut receiver = self.receiver.lock().await; - receiver.recv().await - } -} - -impl Default for EventSystem { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use uuid::Uuid; - - #[tokio::test] - async fn test_event_system_send_and_receive() { - let event_system = EventSystem::new(); - let player_id = Uuid::new_v4(); - - let join_event = ClientEvent::Join { - username: "test_user".to_string(), - }; - - let send_result = event_system.send_event(player_id, join_event).await; - assert!(send_result.is_ok(), "Should send event successfully"); - - let received = event_system.next_event().await; - assert!(received.is_some(), "Should receive sent event"); - - let (received_id, received_event) = received.unwrap(); - assert_eq!(received_id, player_id, "Should receive correct player ID"); - - match received_event { - ClientEvent::Join { username } => { - assert_eq!(username, "test_user", "Should receive correct username"); - } - _ => panic!("Should receive Join event"), - } - } - - #[tokio::test] - async fn test_event_system_clone() { - let event_system1 = EventSystem::new(); - let event_system2 = event_system1.clone(); - - let player_id = Uuid::new_v4(); - let event = ClientEvent::FindMatch; - - event_system1.send_event(player_id, event).await.unwrap(); - - let received = event_system2.next_event().await; - assert!( - received.is_some(), - "Cloned event system should receive events" - ); - } -}*/ diff --git a/server/src/main.rs b/server/src/main.rs index cd50264..ad6ee97 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,5 +1,4 @@ mod connection; -mod events; mod matchmaking; mod messages; use tokio::net::TcpListener; @@ -15,15 +14,11 @@ async fn main() -> anyhow::Result<()> { let matches = connection::new_match_map(); let waiting_queue = connection::new_waiting_queue(); - // Event system for communication between components - //let event_system = events::EventSystem::new(); - // Start matchmaking background task let matchmaker = matchmaking::MatchmakingSystem::new( connections.clone(), matches.clone(), waiting_queue.clone(), - //event_system.clone(), ); tokio::spawn(async move { matchmaker.run().await; @@ -34,17 +29,10 @@ async fn main() -> anyhow::Result<()> { let connections = connections.clone(); let matches = matches.clone(); let waiting_queue = waiting_queue.clone(); - //let event_system = event_system.clone(); tokio::spawn(async move { - if let Err(e) = connection::handle_connection( - stream, - connections, - matches, - waiting_queue, - //event_system, - ) - .await + if let Err(e) = + connection::handle_connection(stream, connections, matches, waiting_queue).await { eprintln!("Connection error: {}", e); } diff --git a/server/src/matchmaking.rs b/server/src/matchmaking.rs index 1aae4ea..de7eca0 100644 --- a/server/src/matchmaking.rs +++ b/server/src/matchmaking.rs @@ -1,5 +1,4 @@ use crate::connection::{ConnectionMap, GameMatch, MatchMap, WaitingQueue}; -//use crate::events::EventSystem; use rand::random; use uuid::Uuid; @@ -7,21 +6,14 @@ pub struct MatchmakingSystem { connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue, - //event_system: EventSystem, } impl MatchmakingSystem { - pub fn new( - connections: ConnectionMap, - matches: MatchMap, - waiting_queue: WaitingQueue, - //event_system: EventSystem, - ) -> Self { + pub fn new(connections: ConnectionMap, matches: MatchMap, waiting_queue: WaitingQueue) -> Self { Self { connections, matches, waiting_queue, - //event_system, } } @@ -114,7 +106,6 @@ impl MatchmakingSystem { #[cfg(test)] mod tests { use super::*; - //use crate::events::EventSystem; use uuid::Uuid; use crate::connection::new_connection_map; @@ -126,14 +117,9 @@ mod tests { let connections = new_connection_map(); let matches = new_match_map(); let waiting_queue = new_waiting_queue(); - //let event_system = EventSystem::new(); - let matchmaking = MatchmakingSystem::new( - connections.clone(), - matches.clone(), - waiting_queue.clone(), - //event_system.clone(), - ); + let matchmaking = + MatchmakingSystem::new(connections.clone(), matches.clone(), waiting_queue.clone()); let player1 = Uuid::new_v4(); let player2 = Uuid::new_v4(); @@ -172,14 +158,9 @@ mod tests { let connections = new_connection_map(); let matches = new_match_map(); let waiting_queue = new_waiting_queue(); - //let event_system = EventSystem::new(); - let matchmaking = MatchmakingSystem::new( - connections.clone(), - matches.clone(), - waiting_queue.clone(), - //event_system.clone(), - ); + let matchmaking = + MatchmakingSystem::new(connections.clone(), matches.clone(), waiting_queue.clone()); let player1 = Uuid::new_v4(); { -- 2.49.1 From 4bb485e83352cf0fc6662eef18a2dc19c09cf4d1 Mon Sep 17 00:00:00 2001 From: htom Date: Tue, 18 Nov 2025 09:28:07 +0100 Subject: [PATCH 06/20] added findmatch event --- server/src/connection.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/src/connection.rs b/server/src/connection.rs index 19b91dc..1fe78e8 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -184,6 +184,12 @@ pub async fn handle_connection( ) .await; } + FindMatch => { + let mut wait_queue = waiting_queue.lock().await; + wait_queue.push_back(player_id.clone()); + println!("Appended {} to the waiting queue", player_id); + println!("queue {:?}", wait_queue); + } _ => {} } } -- 2.49.1 From 9209f1c4e010b4c052738bed7c613de73dfda245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 12:14:22 +0100 Subject: [PATCH 07/20] implemented method check_test in bitboard::checktest.rs --- engine/src/bitboard/legality.rs | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/engine/src/bitboard/legality.rs b/engine/src/bitboard/legality.rs index 7d12e57..64c8601 100644 --- a/engine/src/bitboard/legality.rs +++ b/engine/src/bitboard/legality.rs @@ -1,8 +1,56 @@ use super::board::Board; use super::attackmaps::RAY_TABLE; +use super::checkinfo::CheckInfo; +use super::attacks::get_raycast_from_square_in_direction; impl Board { + pub fn check_test(&self) -> CheckInfo { + let mut check_info: CheckInfo = CheckInfo::new(); + let offset: usize = 6 * self.side_to_move as usize; + let king: u64 = self.bitboards[5 + offset]; + let king_sq = king.trailing_zeros() as usize; + let occupancy = self.occupancy[2]; + + // queen-rook checks (+) + let attacker_mask = self.bitboards[10 - offset] | self.bitboards[9 - offset]; + + for dir in [0, 2, 4, 6] { + let threat_mask: u64 = get_raycast_from_square_in_direction(occupancy, king_sq, dir); + if threat_mask & attacker_mask != 0 { + check_info.add_checker(threat_mask); + } + } + + // queen-bishop checks (x) + let attacker_mask = self.bitboards[10 - offset] | self.bitboards[8 - offset]; + + for dir in [1, 3, 5, 7] { + let threat_mask = get_raycast_from_square_in_direction(occupancy, king_sq, dir); + if threat_mask & attacker_mask != 0 { + check_info.add_checker(threat_mask); + } + } + + // knight checks (L) + let attacker_mask = self.bitboards[7 - offset]; + let threat_mask = self.get_pseudo_knight_moves(king_sq as u32); + let checker = threat_mask & attacker_mask; + if checker != 0 { + check_info.add_checker(checker); + } + + // pawn checks (v) + let attacker_mask = self.bitboards[6 - offset]; + let threat_mask = self.get_pseudo_pawn_captures(king_sq as u32); + let checker = threat_mask & attacker_mask; + if checker != 0 { + check_info.add_checker(checker); + } + + return check_info; + } + pub(in super) fn calc_pinned_squares(&mut self) { self.pinned_squares = [4; 64]; self.pin_mask = 0u64; -- 2.49.1 From 1a9d7ad46022e7a84c9dad11f8939b78f18c827f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 16:15:28 +0100 Subject: [PATCH 08/20] added tests for method bitboard::legality::check_test --- engine/src/bitboard/legality.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/engine/src/bitboard/legality.rs b/engine/src/bitboard/legality.rs index 64c8601..2243bd3 100644 --- a/engine/src/bitboard/legality.rs +++ b/engine/src/bitboard/legality.rs @@ -93,4 +93,35 @@ impl Board { } } +} + +// <----- TESTS -----> + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_test_test() { + + let fens = [ + "rnb1k1nr/pppppppp/4q3/8/1b6/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", // no check + "rnb1k1nr/pppppppp/4q3/8/1b1P4/8/PPP1PPPP/RNBQKBNR b KQkq d3 0 1", // single check + "rnb1k1nr/ppp1p2p/3pq1p1/8/1b1P1P2/8/PPP2PPP/RNBQKBNR w KQkq - 0 1" // double check + ]; + let expected_results = [ + CheckInfo { check_count: 0, move_mask: 0xFFFF_FFFF_FFFF_FFFF }, + CheckInfo { check_count: 1, move_mask: 0x0000_0000_0204_0800 }, + CheckInfo { check_count: 2, move_mask: 0x0000_0000_0000_0000 } + ]; + + for test_nr in 0..3 { + let fen = fens[test_nr]; + let board = Board::build(fen); + let check_test_actual = board.check_test(); + assert_eq!(check_test_actual.check_count, expected_results[test_nr].check_count); + assert_eq!(check_test_actual.move_mask, expected_results[test_nr].move_mask); + } + + } } \ No newline at end of file -- 2.49.1 From 6e0efc76f3b4fc1170e12dcdd63da016e074d0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 16:18:19 +0100 Subject: [PATCH 09/20] added missing method place_piece to struct bitboard::Board --- engine/src/bitboard/board.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/engine/src/bitboard/board.rs b/engine/src/bitboard/board.rs index 11a85ce..483f1c4 100644 --- a/engine/src/bitboard/board.rs +++ b/engine/src/bitboard/board.rs @@ -64,7 +64,7 @@ impl Board { for (i, c) in coming_up.chars().enumerate() { if pieces.contains(&c) { - // board.place_piece(row*8 + col, c); + board.place_piece(row*8 + col, c); col += 1; } else if ('1'..='8').contains(&c) { @@ -179,4 +179,21 @@ impl Board { } } + pub fn place_piece(&mut self, sq: i32, piece: char) { + match piece { + 'p' => {self.bitboards[6] |= 1 << sq} + 'n' => {self.bitboards[7] |= 1 << sq} + 'b' => {self.bitboards[8] |= 1 << sq} + 'r' => {self.bitboards[9] |= 1 << sq} + 'q' => {self.bitboards[10] |= 1 << sq} + 'k' => {self.bitboards[11] |= 1 << sq} + 'P' => {self.bitboards[0] |= 1 << sq} + 'N' => {self.bitboards[1] |= 1 << sq} + 'B' => {self.bitboards[2] |= 1 << sq} + 'R' => {self.bitboards[3] |= 1 << sq} + 'Q' => {self.bitboards[4] |= 1 << sq} + 'K' => {self.bitboards[5] |= 1 << sq} + _ => () + } + } } \ No newline at end of file -- 2.49.1 From 7e64a7ca16dd0e962430782802aaeb76fabf1f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 16:20:42 +0100 Subject: [PATCH 10/20] fixed incorrect test parameter in bitboard::legality::tests::check_test_test --- engine/src/bitboard/legality.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/bitboard/legality.rs b/engine/src/bitboard/legality.rs index 2243bd3..f42fdc1 100644 --- a/engine/src/bitboard/legality.rs +++ b/engine/src/bitboard/legality.rs @@ -106,7 +106,7 @@ mod tests { let fens = [ "rnb1k1nr/pppppppp/4q3/8/1b6/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", // no check - "rnb1k1nr/pppppppp/4q3/8/1b1P4/8/PPP1PPPP/RNBQKBNR b KQkq d3 0 1", // single check + "rnb1k1nr/pppppppp/4q3/8/1b1P4/8/PPP1PPPP/RNBQKBNR w KQkq d3 0 1", // single check "rnb1k1nr/ppp1p2p/3pq1p1/8/1b1P1P2/8/PPP2PPP/RNBQKBNR w KQkq - 0 1" // double check ]; let expected_results = [ -- 2.49.1 From 48f66aac7557e0a4104443580677c2f9dad1e077 Mon Sep 17 00:00:00 2001 From: htom Date: Tue, 18 Nov 2025 16:43:14 +0100 Subject: [PATCH 11/20] added engine as a crate into server project, implemented request moves event --- engine/Cargo.toml | 4 +- engine/src/boardsquare.rs | 51 +++++++++-------- engine/src/chessmove.rs | 114 +++++++++++++++++++------------------- engine/src/movetype.rs | 14 +++-- engine/src/piecetype.rs | 29 +++++----- server/Cargo.toml | 2 + server/src/connection.rs | 12 ++++ 7 files changed, 124 insertions(+), 102 deletions(-) diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 15addf3..0ffa59b 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -4,4 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -once_cell = "1.19" \ No newline at end of file +once_cell = "1.19" +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/engine/src/boardsquare.rs b/engine/src/boardsquare.rs index b4613fe..2587406 100644 --- a/engine/src/boardsquare.rs +++ b/engine/src/boardsquare.rs @@ -1,32 +1,31 @@ +use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize)] pub struct BoardSquare { - pub x: usize, - pub y: usize + pub x: usize, + pub y: usize, } impl BoardSquare { - - pub fn new() -> Self { - return Self{ - x: 0, - y: 0 - }; - } - - pub fn from_coord(x: usize, y: usize) -> Self { - - #[cfg(debug_assertions)] - { - if x > 7 { - println!("Warning: x coordinate of square is bigger than 7, it might not be on the board!"); - } - if y > 7 { - println!("Warning: y coordinate of square is bigger than 7, it might not be on the board!"); - } + pub fn new() -> Self { + return Self { x: 0, y: 0 }; } - return Self { - x: x, - y: y - }; - } -} \ No newline at end of file + + pub fn from_coord(x: usize, y: usize) -> Self { + #[cfg(debug_assertions)] + { + if x > 7 { + println!( + "Warning: x coordinate of square is bigger than 7, it might not be on the board!" + ); + } + if y > 7 { + println!( + "Warning: y coordinate of square is bigger than 7, it might not be on the board!" + ); + } + } + return Self { x: x, y: y }; + } +} + diff --git a/engine/src/chessmove.rs b/engine/src/chessmove.rs index cf92de1..ae46a6a 100644 --- a/engine/src/chessmove.rs +++ b/engine/src/chessmove.rs @@ -1,71 +1,71 @@ use crate::piecetype; use super::boardsquare::BoardSquare; -use super::piecetype::PieceType; use super::movetype::MoveType; +use super::piecetype::PieceType; +use serde::{Deserialize, Serialize}; - +#[derive(Serialize, Deserialize)] pub struct ChessMove { - pub move_type: MoveType, - pub piece_type: PieceType, - pub from_square: BoardSquare, - pub to_square: BoardSquare, - pub rook_from: BoardSquare, - pub rook_to: BoardSquare, - pub promotion_piece: Option + pub move_type: MoveType, + pub piece_type: PieceType, + pub from_square: BoardSquare, + pub to_square: BoardSquare, + pub rook_from: BoardSquare, + pub rook_to: BoardSquare, + pub promotion_piece: Option, } impl ChessMove { - - pub fn quiet( - piece_type: PieceType, - from_square: BoardSquare, - to_square: BoardSquare, - promotion_piece: Option - ) -> Self { - return Self { - move_type: MoveType::Quiet, - piece_type: piece_type, - from_square: from_square, - to_square: to_square, - rook_from: BoardSquare::new(), - rook_to: BoardSquare::new(), - promotion_piece: promotion_piece + pub fn quiet( + piece_type: PieceType, + from_square: BoardSquare, + to_square: BoardSquare, + promotion_piece: Option, + ) -> Self { + return Self { + move_type: MoveType::Quiet, + piece_type: piece_type, + from_square: from_square, + to_square: to_square, + rook_from: BoardSquare::new(), + rook_to: BoardSquare::new(), + promotion_piece: promotion_piece, + }; } - } - pub fn capture( - piece_type: PieceType, - from_square: BoardSquare, - to_square: BoardSquare, - promotion_piece: Option - ) -> Self { - return Self { - move_type: MoveType::Capture, - piece_type: piece_type, - from_square: from_square, - to_square: to_square, - rook_from: BoardSquare::new(), - rook_to: BoardSquare::new(), - promotion_piece: promotion_piece + pub fn capture( + piece_type: PieceType, + from_square: BoardSquare, + to_square: BoardSquare, + promotion_piece: Option, + ) -> Self { + return Self { + move_type: MoveType::Capture, + piece_type: piece_type, + from_square: from_square, + to_square: to_square, + rook_from: BoardSquare::new(), + rook_to: BoardSquare::new(), + promotion_piece: promotion_piece, + }; } - } - pub fn castle( - piece_type: PieceType, - from_square: BoardSquare, - to_square: BoardSquare, - rook_from: BoardSquare, - rook_to: BoardSquare - ) -> Self { - return Self { - move_type: MoveType::Quiet, - piece_type: piece_type, - from_square: from_square, - to_square: to_square, - rook_from: rook_from, - rook_to: rook_to, - promotion_piece: None + pub fn castle( + piece_type: PieceType, + from_square: BoardSquare, + to_square: BoardSquare, + rook_from: BoardSquare, + rook_to: BoardSquare, + ) -> Self { + return Self { + move_type: MoveType::Quiet, + piece_type: piece_type, + from_square: from_square, + to_square: to_square, + rook_from: rook_from, + rook_to: rook_to, + promotion_piece: None, + }; } - } -} \ No newline at end of file +} diff --git a/engine/src/movetype.rs b/engine/src/movetype.rs index ec045a5..3c531dd 100644 --- a/engine/src/movetype.rs +++ b/engine/src/movetype.rs @@ -1,7 +1,11 @@ +use serde::Deserialize; +use serde::Serialize; +#[derive(Serialize, Deserialize)] pub enum MoveType { - Quiet, - Capture, - Castle, - EnPassant -} \ No newline at end of file + Quiet, + Capture, + Castle, + EnPassant, +} + diff --git a/engine/src/piecetype.rs b/engine/src/piecetype.rs index 3eb23f1..b79d341 100644 --- a/engine/src/piecetype.rs +++ b/engine/src/piecetype.rs @@ -1,15 +1,18 @@ +use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize)] pub enum PieceType { - WhitePawn, - WhiteKnight, - WhiteBishop, - WhiteRook, - WhiteQueen, - WhiteKing, - BlackPawn, - BlackKnight, - BlackBishop, - BlackRook, - BlackQueen, - BlackKing -} \ No newline at end of file + WhitePawn, + WhiteKnight, + WhiteBishop, + WhiteRook, + WhiteQueen, + WhiteKing, + BlackPawn, + BlackKnight, + BlackBishop, + BlackRook, + BlackQueen, + BlackKing, +} + diff --git a/server/Cargo.toml b/server/Cargo.toml index c0086f4..ab5f7bf 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,6 +14,8 @@ url = "2.5.7" uuid = {version = "1.18.1", features = ["v4", "serde"] } anyhow = "1.0.100" rand = "0.9.2" +engine = {path = "../engine/"} + [[bin]] name = "client" diff --git a/server/src/connection.rs b/server/src/connection.rs index 1fe78e8..0b9a534 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -1,4 +1,5 @@ use crate::connection::ClientEvent::*; +use engine::get_available_moves; use futures_util::{SinkExt, StreamExt}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; @@ -190,6 +191,17 @@ pub async fn handle_connection( println!("Appended {} to the waiting queue", player_id); println!("queue {:?}", wait_queue); } + Move { from, to } => {} + RequestLegalMoves { fen } => { + let moves = get_available_moves(&fen); + let _ = send_message_to_player( + &connections, + player_id, + &serde_json::to_string(&moves).unwrap(), + ) + .await; + println!("Sent moves to player: {}", player_id); + } _ => {} } } -- 2.49.1 From 887b9abed899f141c3ec891e21de67130700101b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:02:07 +0100 Subject: [PATCH 12/20] adde file and module structure for bitboard::bitmove.rs --- engine/src/bitboard.rs | 1 + engine/src/bitboard/bitmove.rs | 0 2 files changed, 1 insertion(+) create mode 100644 engine/src/bitboard/bitmove.rs diff --git a/engine/src/bitboard.rs b/engine/src/bitboard.rs index 504ae04..405141f 100644 --- a/engine/src/bitboard.rs +++ b/engine/src/bitboard.rs @@ -3,5 +3,6 @@ mod utils; mod legality; mod checkinfo; mod attacks; +mod bitmove; pub mod board; \ No newline at end of file diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs new file mode 100644 index 0000000..e69de29 -- 2.49.1 From 57af3aaae346bd0893b0866247e3fa09297a7803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:09:39 +0100 Subject: [PATCH 13/20] defined shape of struct bitboard::bitmove::BitMove --- engine/src/bitboard/bitmove.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index e69de29..4b0bb17 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -0,0 +1,8 @@ + +pub struct BitMove { + + pub move_type: u8, + pub from_square: u8, + pub to_square: u8, + pub promotion_piece: Option +} \ No newline at end of file -- 2.49.1 From c420d8b3dd54bf98b64076abc9d201da40d7cef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:17:11 +0100 Subject: [PATCH 14/20] added constructor for quiet moves in bitboard::bitmove.rs --- engine/src/bitboard/bitmove.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 4b0bb17..11510f9 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -5,4 +5,17 @@ pub struct BitMove { pub from_square: u8, pub to_square: u8, pub promotion_piece: Option +} + +impl BitMove { + + #[inline] + pub fn quiet(from: u8, to: u8, promotion_piece: Option) -> Self { + return Self { + move_type: 0, + from_square: from, + to_square: to, + promotion_piece: promotion_piece + }; + } } \ No newline at end of file -- 2.49.1 From d8da8085804b175cdfbe7bdfe3b6f454ef193bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:19:31 +0100 Subject: [PATCH 15/20] added enum BitMoveType to bitboard::bitmove.rs for readability --- engine/src/bitboard/bitmove.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 11510f9..59f9dce 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -1,7 +1,7 @@ pub struct BitMove { - pub move_type: u8, + pub move_type: BitMoveType, pub from_square: u8, pub to_square: u8, pub promotion_piece: Option @@ -12,10 +12,17 @@ impl BitMove { #[inline] pub fn quiet(from: u8, to: u8, promotion_piece: Option) -> Self { return Self { - move_type: 0, + move_type: BitMoveType::Quiet, from_square: from, to_square: to, promotion_piece: promotion_piece }; } +} + +pub enum BitMoveType { + Quiet, + Capture, + Castle, + En_Passant } \ No newline at end of file -- 2.49.1 From 05294a77364ad3dc9b7853a11d8953e7e5b17976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:20:40 +0100 Subject: [PATCH 16/20] changed name of value of enum BitMoveType to align with Rust naming conventions --- engine/src/bitboard/bitmove.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 59f9dce..4ba2555 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -24,5 +24,5 @@ pub enum BitMoveType { Quiet, Capture, Castle, - En_Passant + EnPassant } \ No newline at end of file -- 2.49.1 From 7b9c1edbabc499e817c11b8c7a9fd3023f643e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:23:07 +0100 Subject: [PATCH 17/20] added constructor for capture moves in bitboard::bitmove.rs --- engine/src/bitboard/bitmove.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 4ba2555..7afee71 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -18,6 +18,15 @@ impl BitMove { promotion_piece: promotion_piece }; } + #[inline] + pub fn capture(from: u8, to: u8, promotion_piece: Option) -> Self { + return Self { + move_type: BitMoveType::Capture, + from_square: from, + to_square: to, + promotion_piece: promotion_piece + }; + } } pub enum BitMoveType { -- 2.49.1 From e1f4ae717e841c45a451c34c204397ad3c629727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:24:11 +0100 Subject: [PATCH 18/20] added constructor for castling moves in bitboard::bitmove.rs --- engine/src/bitboard/bitmove.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 7afee71..4eff425 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -27,6 +27,15 @@ impl BitMove { promotion_piece: promotion_piece }; } + #[inline] + pub fn castle(from: u8, to: u8) -> Self { + return Self { + move_type: BitMoveType::Castle, + from_square: from, + to_square: to, + promotion_piece: None + }; + } } pub enum BitMoveType { -- 2.49.1 From fd0d26486b5830e8609650e2e6fbe94e84e20874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:30:04 +0100 Subject: [PATCH 19/20] switched from public fields to getters for struct BitMove --- engine/src/bitboard/bitmove.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 4eff425..0ec351b 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -1,10 +1,11 @@ +#[derive(Copy, Clone, PartialEq, Eq)] pub struct BitMove { - pub move_type: BitMoveType, - pub from_square: u8, - pub to_square: u8, - pub promotion_piece: Option + move_type: BitMoveType, + from_square: u8, + to_square: u8, + promotion_piece: Option } impl BitMove { @@ -36,8 +37,26 @@ impl BitMove { promotion_piece: None }; } + + #[inline(always)] + pub fn move_type(&self) -> BitMoveType { + return self.move_type; + } + #[inline(always)] + pub fn from_square(&self) -> u8 { + return self.from_square; + } + #[inline(always)] + pub fn to_square(&self) -> u8 { + return self.to_square; + } + #[inline(always)] + pub fn promotion_piece(&self) -> Option { + return self.promotion_piece; + } } +#[derive(Copy, Clone, PartialEq, Eq)] pub enum BitMoveType { Quiet, Capture, -- 2.49.1 From db333a693f2905dd41b614f0a65fc91379b4a6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Tue, 18 Nov 2025 17:38:48 +0100 Subject: [PATCH 20/20] added method uci_notation to struct BitMove --- engine/src/bitboard/bitmove.rs | 12 ++++++++++++ engine/src/bitboard/utils.rs | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/engine/src/bitboard/bitmove.rs b/engine/src/bitboard/bitmove.rs index 0ec351b..86c5b44 100644 --- a/engine/src/bitboard/bitmove.rs +++ b/engine/src/bitboard/bitmove.rs @@ -1,3 +1,4 @@ +use super::utils::*; #[derive(Copy, Clone, PartialEq, Eq)] pub struct BitMove { @@ -54,6 +55,17 @@ impl BitMove { pub fn promotion_piece(&self) -> Option { return self.promotion_piece; } + + pub fn uci_notation(&self) -> String { + let mut notation = notation_from_square_number(self.from_square()); + notation.push_str(¬ation_from_square_number(self.to_square())); + + if let Some(promotion_piece) = self.promotion_piece { + notation.push(get_character_by_piece_id(promotion_piece).to_ascii_lowercase()); + } + + return notation; + } } #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/engine/src/bitboard/utils.rs b/engine/src/bitboard/utils.rs index 25d7ba8..f7f83fe 100644 --- a/engine/src/bitboard/utils.rs +++ b/engine/src/bitboard/utils.rs @@ -48,6 +48,11 @@ pub fn try_get_square_number_from_notation(notation: &str) -> Result { } } +const PIECE_CHARACTERS: [char; 12] = ['P', 'N', 'B', 'R', 'Q', 'K', 'p', 'n', 'b', 'r', 'q', 'k']; +pub fn get_character_by_piece_id(id: u8) -> char { + return PIECE_CHARACTERS[id as usize]; +} + // <----- TESTS -----> -- 2.49.1