From 2b7faf80ab5bc870e7dfbdb4a9452ffcb7f2ad79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 20:36:22 +0200 Subject: [PATCH 1/7] removed unused variable from conversion method from_bitmove from chessmove.rs --- engine/src/chessmove.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/engine/src/chessmove.rs b/engine/src/chessmove.rs index 4fa1319..7ea0e1c 100644 --- a/engine/src/chessmove.rs +++ b/engine/src/chessmove.rs @@ -128,10 +128,6 @@ impl ChessMove { 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 promotion_piece = match bitmove.promotion_piece() { - Some(piece) => Some(PieceType::from_index(piece)), - None => None - }; 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 -- 2.49.1 From a63954fbfe6e28f145e46d97350ac74b70be26b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 21:52:46 +0200 Subject: [PATCH 2/7] implemented traits needed for testing in lib.rs --- engine/src/lib.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/engine/src/lib.rs b/engine/src/lib.rs index b7bc67b..4e18990 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -21,4 +21,45 @@ pub fn is_game_over(fen: &str) -> Option { pub fn get_board_after_move(fen: &str, chess_move: &ChessMove) -> String { println!("get_board_after_move answered"); return String::from("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); +} + +#[cfg(test)] +mod tests { + use super::*; + + impl PartialEq for ChessMove { + fn eq(&self, other: &Self) -> bool { + canonical(self) == canonical(other) + } + } + impl Eq for ChessMove { + + } + impl Ord for ChessMove { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let lhs = canonical(self); + let rhs = canonical(other); + lhs.cmp(&rhs) + } + } + impl PartialOrd for ChessMove { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + fn canonical(m: &ChessMove) -> (u8, u8, u8) { + match m { + ChessMove::Quiet { piece_type, from_square, to_square, promotion_piece } => + (0, from_square.to_index(), to_square.to_index()), + ChessMove::Capture { piece_type, from_square, to_square, captured_piece, promotion_piece } => + (1, from_square.to_index(), to_square.to_index()), + ChessMove::Castle { king_type, king_from, king_to, rook_type, rook_from, rook_to } => + (2, king_from.to_index(), king_to.to_index()), + ChessMove::EnPassant { pawn_type, from_square, to_square, captured_piece, captured_from } => + (3, from_square.to_index(), to_square.to_index()), + } + } + + } \ No newline at end of file -- 2.49.1 From 068f5248cd4e8d01741b86b7dade6dd47559405d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 22:56:02 +0200 Subject: [PATCH 3/7] implemented api function get_available_moves --- engine/src/bitboard.rs | 4 +- engine/src/boardsquare.rs | 2 +- engine/src/chessmove.rs | 4 +- engine/src/lib.rs | 105 ++++++++++++++++++++++++++++++++++++-- engine/src/piecetype.rs | 2 +- 5 files changed, 108 insertions(+), 9 deletions(-) diff --git a/engine/src/bitboard.rs b/engine/src/bitboard.rs index 9779d93..7da5b04 100644 --- a/engine/src/bitboard.rs +++ b/engine/src/bitboard.rs @@ -3,8 +3,8 @@ mod utils; mod legality; mod checkinfo; mod attacks; -mod movebuffer; mod movegen; pub mod board; -pub(in super) mod bitmove; \ No newline at end of file +pub(in super) mod bitmove; +pub(in super) mod movebuffer; \ No newline at end of file diff --git a/engine/src/boardsquare.rs b/engine/src/boardsquare.rs index 2e0b57f..3682c51 100644 --- a/engine/src/boardsquare.rs +++ b/engine/src/boardsquare.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct BoardSquare { pub x: usize, pub y: usize, diff --git a/engine/src/chessmove.rs b/engine/src/chessmove.rs index 7ea0e1c..ec14ef2 100644 --- a/engine/src/chessmove.rs +++ b/engine/src/chessmove.rs @@ -4,7 +4,7 @@ use super::boardsquare::BoardSquare; use super::piecetype::PieceType; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] /*pub struct ChessMove { pub move_type: MoveType, pub piece_type: PieceType, @@ -94,7 +94,7 @@ impl ChessMove { }; } - pub(in super) fn from_bitmove(bitmove: &BitMove, board: Board) -> Self { + pub(in super) fn from_bitmove(bitmove: &BitMove, board: &Board) -> Self { match bitmove.move_type() { BitMoveType::Quiet => { let from_square_index = bitmove.from_square(); diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 4e18990..dab9ee1 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -7,10 +7,23 @@ pub mod gameend; use chessmove::ChessMove; use gameend::GameEnd; +use bitboard::board::Board; +use bitboard::movebuffer::MoveBuffer; pub fn get_available_moves(fen: &str) -> Vec { - println!("get_available_moves answered"); - return vec![]; + let mut board = Board::build(fen); + let mut buffer = MoveBuffer::new(); + let mut temp_buffer = MoveBuffer::new(); + let mut generated_moves: Vec = vec![]; + + board.collect_moves(&mut buffer, &mut temp_buffer); + + for idx in 0..buffer.count() { + generated_moves.push(ChessMove::from_bitmove(buffer.get(idx), &board)); + } + + println!("get_available_moves resulted in {} moves", generated_moves.len()); + return generated_moves; } pub fn is_game_over(fen: &str) -> Option { @@ -25,6 +38,9 @@ pub fn get_board_after_move(fen: &str, chess_move: &ChessMove) -> String { #[cfg(test)] mod tests { + use crate::boardsquare::BoardSquare; + use crate::piecetype::PieceType::*; + use super::*; impl PartialEq for ChessMove { @@ -61,5 +77,88 @@ mod tests { } } - + #[test] + fn get_available_moves_test() { + let boards: [&str; 2] = [ + "rnbqkbnr/pppppppp/8/1B6/4P3/5P1N/PPPP2PP/RNBQK2R w KQkq e6 0 1", + "6Bn/B2Pk3/8/p1r3NK/3p4/b6P/3p2n1/2R5 w - - 0 1" + ]; + let mut expected_moves: Vec> = vec![ + vec![ + ChessMove::capture(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(3, 6), BlackPawn, None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(0, 1), BoardSquare::from_coord(0, 2), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(0, 1), BoardSquare::from_coord(0, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(1, 1), BoardSquare::from_coord(1, 2), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(1, 1), BoardSquare::from_coord(1, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(2, 1), BoardSquare::from_coord(2, 2), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(2, 1), BoardSquare::from_coord(2, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 1), BoardSquare::from_coord(3, 2), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 1), BoardSquare::from_coord(3, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(4, 3), BoardSquare::from_coord(4, 4), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(5, 2), BoardSquare::from_coord(5, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(6, 1), BoardSquare::from_coord(6, 2), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(6, 1), BoardSquare::from_coord(6, 3), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(1, 0), BoardSquare::from_coord(0, 2), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(1, 0), BoardSquare::from_coord(2, 2), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(7, 2), BoardSquare::from_coord(6, 0), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(7, 2), BoardSquare::from_coord(5, 1), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(7, 2), BoardSquare::from_coord(5, 3), None), + ChessMove::quiet(WhiteKnight, BoardSquare::from_coord(7, 2), BoardSquare::from_coord(6, 4), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(5, 0), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(4, 1), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(3, 2), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(2, 3), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(0, 3), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(0, 5), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(1, 4), BoardSquare::from_coord(2, 5), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(7, 0), BoardSquare::from_coord(6, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(7, 0), BoardSquare::from_coord(5, 0), None), + ChessMove::quiet(WhiteQueen, BoardSquare::from_coord(3, 0), BoardSquare::from_coord(4, 1), None), + ChessMove::quiet(WhiteKing, BoardSquare::from_coord(4, 0), BoardSquare::from_coord(4, 1), None), + ChessMove::quiet(WhiteKing, BoardSquare::from_coord(4, 0), BoardSquare::from_coord(5, 1), None), + ChessMove::quiet(WhiteKing, BoardSquare::from_coord(4, 0), BoardSquare::from_coord(5, 0), None), + ChessMove::castle(WhiteKing, BoardSquare::from_coord(4, 0), BoardSquare::from_coord(6, 0), WhiteRook, BoardSquare::from_coord(7, 0), BoardSquare::from_coord(5, 0)) + ], + vec![ + ChessMove::capture(WhiteBishop, BoardSquare::from_coord(0, 6), BoardSquare::from_coord(2, 4), BlackRook, None), + ChessMove::capture(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(2, 4), BlackRook, None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(7, 2), BoardSquare::from_coord(7, 3), None), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 6), BoardSquare::from_coord(3, 7), Some(WhiteQueen)), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 6), BoardSquare::from_coord(3, 7), Some(WhiteRook)), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 6), BoardSquare::from_coord(3, 7), Some(WhiteBishop)), + ChessMove::quiet(WhitePawn, BoardSquare::from_coord(3, 6), BoardSquare::from_coord(3, 7), Some(WhiteKnight)), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(0, 6), BoardSquare::from_coord(1, 5), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(0, 6), BoardSquare::from_coord(1, 7), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(7, 6), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(5, 6), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(4, 5), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(3, 4), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(2, 3), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(1, 2), None), + ChessMove::quiet(WhiteBishop, BoardSquare::from_coord(6, 7), BoardSquare::from_coord(0, 1), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(0, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(1, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(3, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(4, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(5, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(6, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(7, 0), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(2, 1), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(2, 2), None), + ChessMove::quiet(WhiteRook, BoardSquare::from_coord(2, 0), BoardSquare::from_coord(2, 3), None), + ChessMove::quiet(WhiteKing, BoardSquare::from_coord(7, 4), BoardSquare::from_coord(6, 3), None), + ChessMove::quiet(WhiteKing, BoardSquare::from_coord(7, 4), BoardSquare::from_coord(7, 5), None) + ] + ]; + + for case in 0..2 { + + let mut generated_moves = get_available_moves(boards[case]); + + generated_moves.sort(); + expected_moves[case].sort(); + assert_eq!(generated_moves.len(), expected_moves[case].len()); + assert_eq!(generated_moves, expected_moves[case]); + } + } } \ No newline at end of file diff --git a/engine/src/piecetype.rs b/engine/src/piecetype.rs index 92a7e7b..7a6fc5f 100644 --- a/engine/src/piecetype.rs +++ b/engine/src/piecetype.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub enum PieceType { WhitePawn, WhiteKnight, -- 2.49.1 From f05b1c80dadf9ffb904c0cf3fb28ceddc7b9730b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 23:26:15 +0200 Subject: [PATCH 4/7] added test for api function is_game_over --- engine/src/gameend.rs | 1 + engine/src/lib.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/engine/src/gameend.rs b/engine/src/gameend.rs index 43dd158..c67efe2 100644 --- a/engine/src/gameend.rs +++ b/engine/src/gameend.rs @@ -1,4 +1,5 @@ +#[derive(Debug)] pub enum GameEnd { WhiteWon(String), BlackWon(String), diff --git a/engine/src/lib.rs b/engine/src/lib.rs index dab9ee1..26976d3 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -40,6 +40,7 @@ pub fn get_board_after_move(fen: &str, chess_move: &ChessMove) -> String { mod tests { use crate::boardsquare::BoardSquare; use crate::piecetype::PieceType::*; + use crate::gameend::GameEnd; use super::*; @@ -64,6 +65,17 @@ mod tests { } } + impl PartialEq for GameEnd { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (GameEnd::WhiteWon(a), GameEnd::WhiteWon(b)) => a == b, + (GameEnd::BlackWon(a), GameEnd::BlackWon(b)) => a == b, + (GameEnd::Draw(a), GameEnd::Draw(b)) => a == b, + _ => false, + } + } +} + fn canonical(m: &ChessMove) -> (u8, u8, u8) { match m { ChessMove::Quiet { piece_type, from_square, to_square, promotion_piece } => @@ -161,4 +173,27 @@ mod tests { assert_eq!(generated_moves, expected_moves[case]); } } + + #[test] + fn is_game_over_test() { + + let boards: [&str; 4] = [ + "2k5/3pn3/2pP4/1R1P3B/1Np5/3RPp2/1B6/6Kb w - - 0 1", + "2K3B1/4P3/8/7p/4pPn1/1N1P1p1p/4bp2/2Rk4 b - - 0 1", + "6N1/B2PP3/pR1b4/3P2nb/6P1/3P1k2/2p5/4r1K1 w - - 0 1", + "3n1K2/p4p2/3k1P2/b1p2P2/P7/8/3p2r1/8 w - - 0 1" + ]; + let expected_results: [Option; 4] = [ + None, + Some(GameEnd::WhiteWon("".to_string())), + Some(GameEnd::BlackWon("".to_string())), + Some(GameEnd::Draw("".to_string())) + ]; + + for case in 0..4 { + let fen = boards[case]; + let actual = is_game_over(fen); + assert_eq!(actual, expected_results[case]); + } + } } \ No newline at end of file -- 2.49.1 From eba8076ea9c4cdcc412db3404da3d80ee3b3759e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 23:41:33 +0200 Subject: [PATCH 5/7] implemented api function is_game_over --- engine/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 26976d3..1d618b3 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -27,8 +27,20 @@ pub fn get_available_moves(fen: &str) -> Vec { } pub fn is_game_over(fen: &str) -> Option { + let mut board = Board::build(fen); + let mut buffer = MoveBuffer::new(); + let mut temp_buffer = MoveBuffer::new(); + let in_check = board.collect_moves(&mut buffer, &mut temp_buffer); + + println!("found moves: {}", buffer.count()); println!("is_game_over answered"); - return None; + if buffer.count() > 0 { + return None; + } + if !in_check { + return Some(GameEnd::Draw("".to_string())); + } + return if board.side_to_move() == 0 { Some(GameEnd::BlackWon("".to_string())) } else { Some(GameEnd::WhiteWon("".to_string())) }; } pub fn get_board_after_move(fen: &str, chess_move: &ChessMove) -> String { @@ -181,7 +193,7 @@ mod tests { "2k5/3pn3/2pP4/1R1P3B/1Np5/3RPp2/1B6/6Kb w - - 0 1", "2K3B1/4P3/8/7p/4pPn1/1N1P1p1p/4bp2/2Rk4 b - - 0 1", "6N1/B2PP3/pR1b4/3P2nb/6P1/3P1k2/2p5/4r1K1 w - - 0 1", - "3n1K2/p4p2/3k1P2/b1p2P2/P7/8/3p2r1/8 w - - 0 1" + "3n1K2/p2k1p2/5P2/b1p2P2/P7/8/3p2r1/8 w - - 0 1" ]; let expected_results: [Option; 4] = [ None, -- 2.49.1 From 499b0fd152353cb6b007bc1eaf75799b513f416c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20D=C3=A1vid=20Lajos?= Date: Fri, 21 Nov 2025 23:43:57 +0200 Subject: [PATCH 6/7] removed unneeded log message --- engine/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 1d618b3..f3f6d39 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -32,7 +32,6 @@ pub fn is_game_over(fen: &str) -> Option { let mut temp_buffer = MoveBuffer::new(); let in_check = board.collect_moves(&mut buffer, &mut temp_buffer); - println!("found moves: {}", buffer.count()); println!("is_game_over answered"); if buffer.count() > 0 { return None; -- 2.49.1 From 1f3fff3501e41cdbb76108c7f871243a80d5cc97 Mon Sep 17 00:00:00 2001 From: htom Date: Mon, 24 Nov 2025 15:51:37 +0100 Subject: [PATCH 7/7] removed test upload dependenci, issue with sheets api --- .github/workflows/dispatcher.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/dispatcher.yml b/.github/workflows/dispatcher.yml index fd0a427..9f93a3f 100644 --- a/.github/workflows/dispatcher.yml +++ b/.github/workflows/dispatcher.yml @@ -77,7 +77,6 @@ jobs: release: - needs: test-data-upload if: github.ref == 'refs/heads/master' uses: ./.github/workflows/release.yml secrets: inherit -- 2.49.1