From ab32851ee9f5d912a833cd2af499bd40d3045949 Mon Sep 17 00:00:00 2001 From: Sayed Atayi Date: Tue, 7 Oct 2025 13:15:17 +0100 Subject: [PATCH 1/7] fix the initial test failures --- chessington/engine/pieces.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/chessington/engine/pieces.py b/chessington/engine/pieces.py index b3408fa..f0588dd 100644 --- a/chessington/engine/pieces.py +++ b/chessington/engine/pieces.py @@ -41,12 +41,28 @@ class Pawn(Piece): """ def get_available_moves(self, board) -> List[Square]: current_square = board.find_piece(self) + moves = [] + if self.player == Player.BLACK: - square_in_front = Square.at(current_square.row - 1, current_square.col) - return [square_in_front] + # Black pawn moves down (decreasing row numbers) + one_square = Square.at(current_square.row - 1, current_square.col) + moves.append(one_square) + + # If pawn is at starting position (row 6), it can move two squares + if current_square.row == 6: + two_squares = Square.at(current_square.row - 2, current_square.col) + moves.append(two_squares) else: - square_in_front = Square.at(current_square.row + 1, current_square.col) - return [square_in_front] + # White pawn moves up (increasing row numbers) + one_square = Square.at(current_square.row + 1, current_square.col) + moves.append(one_square) + + # If pawn is at starting position (row 1), it can move two squares + if current_square.row == 1: + two_squares = Square.at(current_square.row + 2, current_square.col) + moves.append(two_squares) + + return moves class Knight(Piece): @@ -91,4 +107,4 @@ class King(Piece): """ def get_available_moves(self, board): - return [] \ No newline at end of file + return [] From 622f09ead21ab8877dd456944a8f1cee0f1d2117 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 1 Aug 2019 14:22:18 +0100 Subject: [PATCH 2/7] Added a test that pawns cannot move through obstructions --- tests/test_pieces.py | 116 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/tests/test_pieces.py b/tests/test_pieces.py index 15cf3de..b672d35 100644 --- a/tests/test_pieces.py +++ b/tests/test_pieces.py @@ -101,4 +101,118 @@ def test_black_pawn_cannot_move_down_two_squares_if_already_moved(): # Assert assert Square.at(4, 4) in moves - assert Square.at(3, 4) not in moves \ No newline at end of file + assert Square.at(3, 4) not in moves + + @staticmethod + def test_white_pawn_cannot_move_if_piece_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + pawn_square = Square.at(4, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(5, 4) + obstruction = Pawn(Player.BLACK) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert len(moves) == 0 + + @staticmethod + def test_black_pawn_cannot_move_if_piece_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + pawn_square = Square.at(4, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(3, 4) + obstruction = Pawn(Player.WHITE) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert len(moves) == 0 + + @staticmethod + def test_white_pawn_cannot_move_two_squares_if_piece_two_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + pawn_square = Square.at(1, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(3, 4) + obstruction = Pawn(Player.BLACK) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert obstructing_square not in moves + + @staticmethod + def test_black_pawn_cannot_move_two_squares_if_piece_two_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + pawn_square = Square.at(6, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(4, 4) + obstruction = Pawn(Player.WHITE) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert obstructing_square not in moves + + @staticmethod + def test_white_pawn_cannot_move_two_squares_if_piece_one_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + pawn_square = Square.at(1, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(2, 4) + obstruction = Pawn(Player.BLACK) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert Square.at(3, 4) not in moves + + @staticmethod + def test_black_pawn_cannot_move_two_squares_if_piece_one_in_front(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + pawn_square = Square.at(6, 4) + board.set_piece(pawn_square, pawn) + + obstructing_square = Square.at(5, 4) + obstruction = Pawn(Player.WHITE) + board.set_piece(obstructing_square, obstruction) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert Square.at(4, 4) not in moves From 80332b4164c00d5acc8f8c7a4909fd3c6093991d Mon Sep 17 00:00:00 2001 From: Sayed Atayi Date: Tue, 7 Oct 2025 13:58:12 +0100 Subject: [PATCH 3/7] fix the red-1 test failures --- chessington/engine/pieces.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/chessington/engine/pieces.py b/chessington/engine/pieces.py index f0588dd..ec4a5a9 100644 --- a/chessington/engine/pieces.py +++ b/chessington/engine/pieces.py @@ -46,21 +46,25 @@ def get_available_moves(self, board) -> List[Square]: if self.player == Player.BLACK: # Black pawn moves down (decreasing row numbers) one_square = Square.at(current_square.row - 1, current_square.col) - moves.append(one_square) - - # If pawn is at starting position (row 6), it can move two squares - if current_square.row == 6: - two_squares = Square.at(current_square.row - 2, current_square.col) - moves.append(two_squares) + if board.get_piece(one_square) is None: + moves.append(one_square) + + # If pawn is at starting position (row 6), it can move two squares + if current_square.row == 6: + two_squares = Square.at(current_square.row - 2, current_square.col) + if board.get_piece(two_squares) is None: + moves.append(two_squares) else: # White pawn moves up (increasing row numbers) one_square = Square.at(current_square.row + 1, current_square.col) - moves.append(one_square) - - # If pawn is at starting position (row 1), it can move two squares - if current_square.row == 1: - two_squares = Square.at(current_square.row + 2, current_square.col) - moves.append(two_squares) + if board.get_piece(one_square) is None: + moves.append(one_square) + + # If pawn is at starting position (row 1), it can move two squares + if current_square.row == 1: + two_squares = Square.at(current_square.row + 2, current_square.col) + if board.get_piece(two_squares) is None: + moves.append(two_squares) return moves From c3051ebe5d500a6ab0bc333494c2bf7d01d68591 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 1 Aug 2019 14:28:36 +0100 Subject: [PATCH 4/7] Added a test that pawns cannot run off the end of the board --- tests/test_pieces.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_pieces.py b/tests/test_pieces.py index b672d35..0713d7b 100644 --- a/tests/test_pieces.py +++ b/tests/test_pieces.py @@ -216,3 +216,33 @@ def test_black_pawn_cannot_move_two_squares_if_piece_one_in_front(): # Assert assert Square.at(4, 4) not in moves + + @staticmethod + def test_white_pawn_cannot_move_at_top_of_board(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + square = Square.at(7, 4) + board.set_piece(square, pawn) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert len(moves) == 0 + + @staticmethod + def test_black_pawn_cannot_move_at_bottom_of_board(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + square = Square.at(0, 4) + board.set_piece(square, pawn) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert len(moves) == 0 From 21c49261c0d046fe7ce8a4b83c75d698b0db2fe1 Mon Sep 17 00:00:00 2001 From: Sayed Atayi Date: Tue, 7 Oct 2025 15:21:42 +0100 Subject: [PATCH 5/7] fix the red-2 test failures --- chessington/engine/pieces.py | 51 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/chessington/engine/pieces.py b/chessington/engine/pieces.py index ec4a5a9..4c59e4a 100644 --- a/chessington/engine/pieces.py +++ b/chessington/engine/pieces.py @@ -45,26 +45,39 @@ def get_available_moves(self, board) -> List[Square]: if self.player == Player.BLACK: # Black pawn moves down (decreasing row numbers) - one_square = Square.at(current_square.row - 1, current_square.col) - if board.get_piece(one_square) is None: - moves.append(one_square) - - # If pawn is at starting position (row 6), it can move two squares - if current_square.row == 6: - two_squares = Square.at(current_square.row - 2, current_square.col) - if board.get_piece(two_squares) is None: - moves.append(two_squares) - else: + new_row = current_square.row - 1 + + if new_row >= 0: # Ensure within board bounds + one_square = Square.at(current_square.row - 1, current_square.col) + + if board.get_piece(one_square) is None: + moves.append(one_square) + + # If pawn is at starting position (row 6), it can move two squares + if current_square.row == 6: + two_square_row = current_square.row - 2 + if two_square_row >= 0: # Ensure within board bounds + two_squares = Square.at(current_square.row - 2, current_square.col) + if board.get_piece(two_squares) is None: + moves.append(two_squares) + else: # White player # White pawn moves up (increasing row numbers) - one_square = Square.at(current_square.row + 1, current_square.col) - if board.get_piece(one_square) is None: - moves.append(one_square) - - # If pawn is at starting position (row 1), it can move two squares - if current_square.row == 1: - two_squares = Square.at(current_square.row + 2, current_square.col) - if board.get_piece(two_squares) is None: - moves.append(two_squares) + new_row = current_square.row + 1 + + if new_row <= 7: # Ensure within board bounds + one_square = Square.at(current_square.row + 1, current_square.col) + + if board.get_piece(one_square) is None: + moves.append(one_square) + + # If pawn is at starting position (row 1), it can move two squares + if current_square.row == 1: + two_square_row = current_square.row + 2 + + if two_square_row <= 7: # Ensure within board bounds + two_squares = Square.at(current_square.row + 2, current_square.col) + if board.get_piece(two_squares) is None: + moves.append(two_squares) return moves From 4b7f314fc937097739f5584718fec7e637ef9f02 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 1 Aug 2019 14:43:38 +0100 Subject: [PATCH 6/7] Added a test that pawns can capture diagonally --- tests/test_pieces.py | 88 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/test_pieces.py b/tests/test_pieces.py index 0713d7b..9fa0dc7 100644 --- a/tests/test_pieces.py +++ b/tests/test_pieces.py @@ -246,3 +246,91 @@ def test_black_pawn_cannot_move_at_bottom_of_board(): # Assert assert len(moves) == 0 + + @staticmethod + def test_white_pawns_can_capture_diagonally(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + pawn_square = Square.at(3, 4) + board.set_piece(pawn_square, pawn) + + enemy1 = Pawn(Player.BLACK) + enemy1_square = Square.at(4, 5) + board.set_piece(enemy1_square, enemy1) + + enemy2 = Pawn(Player.BLACK) + enemy2_square = Square.at(4, 3) + board.set_piece(enemy2_square, enemy2) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert enemy1_square in moves + assert enemy2_square in moves + + @staticmethod + def test_black_pawns_can_capture_diagonally(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + pawn_square = Square.at(3, 4) + board.set_piece(pawn_square, pawn) + + enemy1 = Pawn(Player.WHITE) + enemy1_square = Square.at(2, 5) + board.set_piece(enemy1_square, enemy1) + + enemy2 = Pawn(Player.WHITE) + enemy2_square = Square.at(2, 3) + board.set_piece(enemy2_square, enemy2) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert enemy1_square in moves + assert enemy2_square in moves + + @staticmethod + def test_white_pawns_cannot_move_diagonally_except_to_capture(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.WHITE) + pawn_square = Square.at(3, 4) + board.set_piece(pawn_square, pawn) + + friendly = Pawn(Player.WHITE) + friendly_square = Square.at(4, 5) + board.set_piece(friendly_square, friendly) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert Square.at(4, 3) not in moves + assert Square.at(4, 5) not in moves + + @staticmethod + def test_black_pawns_cannot_move_diagonally_except_to_capture(): + + # Arrange + board = Board.empty() + pawn = Pawn(Player.BLACK) + pawn_square = Square.at(3, 4) + board.set_piece(pawn_square, pawn) + + friendly = Pawn(Player.BLACK) + friendly_square = Square.at(2, 5) + board.set_piece(friendly_square, friendly) + + # Act + moves = pawn.get_available_moves(board) + + # Assert + assert Square.at(2, 3) not in moves + assert Square.at(2, 5) not in moves From d0f0b3a9905fe5bed7d0085670853795b81422c6 Mon Sep 17 00:00:00 2001 From: Sayed Atayi Date: Tue, 7 Oct 2025 15:53:42 +0100 Subject: [PATCH 7/7] fix the red-3 test failures --- chessington/engine/pieces.py | 69 +++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/chessington/engine/pieces.py b/chessington/engine/pieces.py index 4c59e4a..8eb9809 100644 --- a/chessington/engine/pieces.py +++ b/chessington/engine/pieces.py @@ -44,43 +44,78 @@ def get_available_moves(self, board) -> List[Square]: moves = [] if self.player == Player.BLACK: - # Black pawn moves down (decreasing row numbers) + # Black pawn moves down (decreasing row) new_row = current_square.row - 1 - if new_row >= 0: # Ensure within board bounds - one_square = Square.at(current_square.row - 1, current_square.col) - + # 1. FORWARD MOVEMENT + if new_row >= 0: + one_square = Square.at(new_row, current_square.col) if board.get_piece(one_square) is None: moves.append(one_square) - # If pawn is at starting position (row 6), it can move two squares + # Two-square move from starting position if current_square.row == 6: two_square_row = current_square.row - 2 - if two_square_row >= 0: # Ensure within board bounds - two_squares = Square.at(current_square.row - 2, current_square.col) + if two_square_row >= 0: + two_squares = Square.at(two_square_row, current_square.col) if board.get_piece(two_squares) is None: moves.append(two_squares) - else: # White player - # White pawn moves up (increasing row numbers) - new_row = current_square.row + 1 - if new_row <= 7: # Ensure within board bounds - one_square = Square.at(current_square.row + 1, current_square.col) + # 2. DIAGONAL CAPTURE MOVES + if new_row >= 0: # Make sure we're not going off the board + # Check diagonal left (column - 1) + if current_square.col - 1 >= 0: # Don't go off left edge + diagonal_left = Square.at(new_row, current_square.col - 1) + piece_on_diagonal = board.get_piece(diagonal_left) + # Can capture if there's an enemy piece (different player) + if piece_on_diagonal is not None and piece_on_diagonal.player != self.player: + moves.append(diagonal_left) + + # Check diagonal right (column + 1) + if current_square.col + 1 <= 7: # Don't go off right edge + diagonal_right = Square.at(new_row, current_square.col + 1) + piece_on_diagonal = board.get_piece(diagonal_right) + # Can capture if there's an enemy piece (different player) + if piece_on_diagonal is not None and piece_on_diagonal.player != self.player: + moves.append(diagonal_right) + + else: # WHITE player + # White pawn moves up (increasing row) + new_row = current_square.row + 1 + # 1. FORWARD MOVEMENT + if new_row <= 7: + one_square = Square.at(new_row, current_square.col) if board.get_piece(one_square) is None: moves.append(one_square) - # If pawn is at starting position (row 1), it can move two squares + # Two-square move from starting position if current_square.row == 1: two_square_row = current_square.row + 2 - - if two_square_row <= 7: # Ensure within board bounds - two_squares = Square.at(current_square.row + 2, current_square.col) + if two_square_row <= 7: + two_squares = Square.at(two_square_row, current_square.col) if board.get_piece(two_squares) is None: moves.append(two_squares) - return moves + # 2. DIAGONAL CAPTURE MOVES + if new_row <= 7: # Make sure we're not going off the board + # Check diagonal left (column - 1) + if current_square.col - 1 >= 0: # Don't go off left edge + diagonal_left = Square.at(new_row, current_square.col - 1) + piece_on_diagonal = board.get_piece(diagonal_left) + # Can capture if there's an enemy piece (different player) + if piece_on_diagonal is not None and piece_on_diagonal.player != self.player: + moves.append(diagonal_left) + + # Check diagonal right (column + 1) + if current_square.col + 1 <= 7: # Don't go off right edge + diagonal_right = Square.at(new_row, current_square.col + 1) + piece_on_diagonal = board.get_piece(diagonal_right) + # Can capture if there's an enemy piece (different player) + if piece_on_diagonal is not None and piece_on_diagonal.player != self.player: + moves.append(diagonal_right) + return moves class Knight(Piece): """