diff --git a/engine/src/boardsquare.rs b/engine/src/boardsquare.rs index 3682c51..815875c 100644 --- a/engine/src/boardsquare.rs +++ b/engine/src/boardsquare.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct BoardSquare { pub x: usize, pub y: usize, @@ -28,10 +28,10 @@ impl BoardSquare { return Self { x: x, y: y }; } - pub(in super) fn from_index(idx: u8) -> Self { + pub(super) fn from_index(idx: u8) -> Self { let file = idx % 8; let rank = idx / 8; - + #[cfg(debug_assertions)] { if !(0..8).contains(&rank) { @@ -39,10 +39,12 @@ impl BoardSquare { } } - return Self {x: file as usize, y: rank as usize}; + return Self { + x: file as usize, + y: rank as usize, + }; } - pub(in super) fn to_index(&self) -> u8 { + pub(super) fn to_index(&self) -> u8 { return (8 * self.y + self.x) as u8; } } - diff --git a/engine/src/chessmove.rs b/engine/src/chessmove.rs index ec14ef2..d20c0cf 100644 --- a/engine/src/chessmove.rs +++ b/engine/src/chessmove.rs @@ -1,10 +1,13 @@ -use crate::{bitboard::{bitmove::{BitMove, BitMoveType}, board::Board}}; +use crate::bitboard::{ + bitmove::{BitMove, BitMoveType}, + board::Board, +}; use super::boardsquare::BoardSquare; use super::piecetype::PieceType; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] /*pub struct ChessMove { pub move_type: MoveType, pub piece_type: PieceType, @@ -19,14 +22,14 @@ pub enum ChessMove { piece_type: PieceType, from_square: BoardSquare, to_square: BoardSquare, - promotion_piece: Option + promotion_piece: Option, }, Capture { piece_type: PieceType, from_square: BoardSquare, to_square: BoardSquare, captured_piece: PieceType, - promotion_piece: Option + promotion_piece: Option, }, Castle { king_type: PieceType, @@ -34,15 +37,15 @@ pub enum ChessMove { king_to: BoardSquare, rook_type: PieceType, rook_from: BoardSquare, - rook_to: BoardSquare + rook_to: BoardSquare, }, EnPassant { pawn_type: PieceType, from_square: BoardSquare, to_square: BoardSquare, captured_piece: PieceType, - captured_from: BoardSquare - } + captured_from: BoardSquare, + }, } impl ChessMove { @@ -56,7 +59,7 @@ impl ChessMove { piece_type, from_square, to_square, - promotion_piece + promotion_piece, }; } @@ -72,7 +75,7 @@ impl ChessMove { from_square, to_square, captured_piece, - promotion_piece + promotion_piece, }; } @@ -90,11 +93,11 @@ impl ChessMove { king_to, rook_type, rook_from, - rook_to + rook_to, }; } - pub(in super) fn from_bitmove(bitmove: &BitMove, board: &Board) -> Self { + pub(super) fn from_bitmove(bitmove: &BitMove, board: &Board) -> Self { match bitmove.move_type() { BitMoveType::Quiet => { let from_square_index = bitmove.from_square(); @@ -103,11 +106,16 @@ impl ChessMove { let to_square = BoardSquare::from_index(bitmove.to_square()); let promotion_piece = match bitmove.promotion_piece() { Some(piece) => Some(PieceType::from_index(piece)), - None => None + None => None, }; - return ChessMove::Quiet { piece_type, from_square, to_square, promotion_piece } - }, + return ChessMove::Quiet { + piece_type, + from_square, + to_square, + promotion_piece, + }; + } BitMoveType::Capture => { let from_square_index = bitmove.from_square(); let to_square_index = bitmove.to_square(); @@ -117,18 +125,28 @@ impl ChessMove { let captured_piece = PieceType::from_index(board.piece_board(to_square_index)); let promotion_piece = match bitmove.promotion_piece() { Some(piece) => Some(PieceType::from_index(piece)), - None => None + None => None, }; - return ChessMove::Capture { piece_type, from_square, to_square, captured_piece, promotion_piece } - }, + return ChessMove::Capture { + piece_type, + from_square, + to_square, + captured_piece, + promotion_piece, + }; + } BitMoveType::Castle => { let from_square_index = bitmove.from_square(); let to_square_index = bitmove.to_square(); let king_type = PieceType::from_index(board.piece_board(from_square_index)); let king_from = BoardSquare::from_index(from_square_index); let king_to = BoardSquare::from_index(to_square_index); - let rook_type = if bitmove.from_square() < 32 { PieceType::WhiteRook } else { PieceType::BlackRook }; + let rook_type = if bitmove.from_square() < 32 { + PieceType::WhiteRook + } else { + PieceType::BlackRook + }; let rook_from_index = if bitmove.to_square() > bitmove.from_square() { bitmove.from_square() + 3 } else { @@ -142,44 +160,72 @@ impl ChessMove { }; let rook_to = BoardSquare::from_index(rook_to_index); - return ChessMove::Castle { king_type, king_from, king_to, rook_type, rook_from, rook_to } - }, + return ChessMove::Castle { + king_type, + king_from, + king_to, + rook_type, + rook_from, + rook_to, + }; + } BitMoveType::EnPassant => { panic!("ChessMove::from_bitmove was left unimplemented"); } } } - pub(in super) fn to_bitmove(&self) -> BitMove { + pub(super) fn to_bitmove(&self) -> BitMove { let bitmove = match self { - ChessMove::Quiet { piece_type, from_square, to_square, promotion_piece } => { + ChessMove::Quiet { + piece_type, + from_square, + to_square, + promotion_piece, + } => { let promotion_piece = match promotion_piece { Some(piece) => Some(piece.to_index()), - None => None + None => None, }; return BitMove::quiet( from_square.to_index(), to_square.to_index(), - promotion_piece + promotion_piece, ); - }, - ChessMove::Capture { piece_type, from_square, to_square, captured_piece, promotion_piece } => { + } + ChessMove::Capture { + piece_type, + from_square, + to_square, + captured_piece, + promotion_piece, + } => { let promotion_piece = match promotion_piece { Some(piece) => Some(piece.to_index()), - None => None + None => None, }; return BitMove::capture( from_square.to_index(), to_square.to_index(), - promotion_piece + promotion_piece, ); - }, - ChessMove::Castle { king_type, king_from, king_to, rook_type, rook_from, rook_to } => { - return BitMove::castle( - king_from.to_index(), - king_to.to_index() - ); - }, - ChessMove::EnPassant { pawn_type, from_square, to_square, captured_piece, captured_from } => { + } + ChessMove::Castle { + king_type, + king_from, + king_to, + rook_type, + rook_from, + rook_to, + } => { + return BitMove::castle(king_from.to_index(), king_to.to_index()); + } + ChessMove::EnPassant { + pawn_type, + from_square, + to_square, + captured_piece, + captured_from, + } => { panic!("ChessMove::to_bitmove was left unimplemented"); } }; diff --git a/engine/src/piecetype.rs b/engine/src/piecetype.rs index 7a6fc5f..e366950 100644 --- a/engine/src/piecetype.rs +++ b/engine/src/piecetype.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug)] pub enum PieceType { WhitePawn, WhiteKnight, @@ -17,8 +17,7 @@ pub enum PieceType { } impl PieceType { - - pub(in super) fn from_index(idx: u8) -> Self { + pub(super) fn from_index(idx: u8) -> Self { return match idx { 0 => PieceType::WhitePawn, 1 => PieceType::WhiteKnight, @@ -32,10 +31,10 @@ impl PieceType { 9 => PieceType::BlackRook, 10 => PieceType::BlackQueen, 11 => PieceType::BlackKing, - _ => panic!("invalid piece index! should NEVER appear") - } + _ => panic!("invalid piece index! should NEVER appear"), + }; } - pub(in super) fn to_index(&self) -> u8 { + pub(super) fn to_index(&self) -> u8 { return match self { &PieceType::WhitePawn => 0, &PieceType::WhiteKnight => 1, @@ -48,7 +47,8 @@ impl PieceType { &PieceType::BlackBishop => 8, &PieceType::BlackRook => 9, &PieceType::BlackQueen => 10, - &PieceType::BlackKing => 11 - } + &PieceType::BlackKing => 11, + }; } -} \ No newline at end of file +} + diff --git a/ui/src/main.rs b/ui/src/main.rs index 0a12141..e323f6a 100644 --- a/ui/src/main.rs +++ b/ui/src/main.rs @@ -4,6 +4,9 @@ use env_logger::Env; use futures_util::{SinkExt, StreamExt}; use log::{error, info, warn}; use serde::{Deserialize, Serialize}; +use std::os::unix::process::CommandExt; +use std::path::Path; +use std::process::Command; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; use tokio_tungstenite::{connect_async, tungstenite::Message}; @@ -82,6 +85,7 @@ struct GameState { opponent_name: Option, match_id: Option, game_over: Option, + available_moves: Option>, } impl Default for GameState { @@ -92,6 +96,7 @@ impl Default for GameState { opponent_name: None, match_id: None, game_over: None, + available_moves: None, } } } @@ -99,6 +104,7 @@ impl Default for GameState { // UI state enum AppState { MainMenu, + PrivatePlayConnect, Connecting, FindingMatch, InGame, @@ -110,7 +116,8 @@ struct ChessApp { game_state: Arc>, server_port: String, username: String, - + server_ip: String, + start_local_server_instance: bool, // Channels for communication with network tasks tx_to_network: Option>, rx_from_network: Option>, @@ -129,6 +136,9 @@ impl Default for ChessApp { tx_to_network: None, rx_from_network: None, selected_square: None, + server_ip: "127.0.0.1".to_string(), // TODO: change to dns when we figure out hosting + // for the online server (reverse proxy?) + start_local_server_instance: false, } } } @@ -138,6 +148,7 @@ impl ChessApp { let server_port = self.server_port.clone(); let username = self.username.clone(); let game_state = self.game_state.clone(); + let server_address = self.server_ip.clone(); // Create channels for communication let (tx_to_network, rx_from_ui) = mpsc::unbounded_channel(); @@ -150,8 +161,15 @@ impl ChessApp { // Spawn network connection task tokio::spawn(async move { - if let Err(e) = - Self::network_handler(server_port, username, rx_from_ui, tx_to_ui, game_state).await + if let Err(e) = Self::network_handler( + server_port, + server_address, + username, + rx_from_ui, + tx_to_ui, + game_state, + ) + .await { error!("Network handler error: {}", e); } @@ -160,13 +178,14 @@ impl ChessApp { async fn network_handler( server_port: String, + server_ip: String, username: String, mut rx_from_ui: mpsc::UnboundedReceiver, tx_to_ui: mpsc::UnboundedSender, game_state: Arc>, ) -> anyhow::Result<()> { // Build WebSocket URL - let server_address = format!("ws://127.0.0.1:{}", server_port); + let server_address = format!("ws://{}:{}", server_ip, server_port); let url = Url::parse(&server_address)?; info!("Connecting to: {}", server_address); @@ -366,17 +385,17 @@ impl eframe::App for ChessApp { ui.text_edit_singleline(&mut self.username); }); - ui.horizontal(|ui| { - ui.label("Server Port:"); - ui.text_edit_singleline(&mut self.server_port); - }); - ui.add_space(20.0); - if ui.button("Connect & Play").clicked() { + if ui.button("Online Play").clicked() { + self.server_ip = "random.dns.com".to_string(); self.connect_to_server(); } + if ui.button("Private Play").clicked() { + self.state = AppState::PrivatePlayConnect; + } + if ui.button("Quit").clicked() { std::process::exit(0); } @@ -384,6 +403,47 @@ impl eframe::App for ChessApp { }); } + AppState::PrivatePlayConnect => { + egui::CentralPanel::default().show(ctx, |ui| { + ui.vertical_centered(|ui| { + ui.horizontal(|ui| { + ui.label("Server ip address"); + ui.text_edit_singleline(&mut self.server_ip); + }); + + ui.horizontal(|ui| { + ui.label("Server Port:"); + ui.text_edit_singleline(&mut self.server_port); + }); + + ui.horizontal(|ui| { + ui.checkbox(&mut self.start_local_server_instance, "Host Server"); + }); + + ui.add_space(20.0); + + if ui.button("Play").clicked() { + if self.start_local_server_instance == true { + // TODO: Spawn server instance here + let path = if cfg!(windows) { + "./server.exe" + } else { + "./server" + }; + + if !Path::new(path).exists() { + error!("Server binary does not exist, cfg: {}", path); + } else { + let _ = Command::new(path).spawn(); + std::thread::sleep(std::time::Duration::from_secs(1)); + } + } + self.connect_to_server(); + } + }) + }); + } + AppState::Connecting => { egui::CentralPanel::default().show(ctx, |ui| { // TODO: go back to menu btn @@ -399,6 +459,7 @@ impl eframe::App for ChessApp { egui::CentralPanel::default().show(ctx, |ui| { // TODO: go back to menu btn // TODO: how do we delete the player from the waiting queue + // FIX: disconnect the player from the server which will clean up connection ui.vertical_centered(|ui| { ui.heading("Finding Match..."); ui.add_space(20.0);