From 92e1ff26fc6eb2bf96d6140d4af6bc11c838698d Mon Sep 17 00:00:00 2001 From: Karma Riuk Date: Sat, 1 Feb 2025 16:43:02 +0100 Subject: [PATCH] added pawn promotion --- src/logic/board.py | 4 ++++ src/logic/move.py | 4 +++- src/logic/pieces/pawn.py | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/logic/board.py b/src/logic/board.py index 8b34dad..581b86b 100644 --- a/src/logic/board.py +++ b/src/logic/board.py @@ -184,6 +184,10 @@ class Board: pos_to_remove = Position(move.pos.x, move.pos.y + (1 if self._turn == Colour.BLACK else -1)) del other_pieces[pos_to_remove] + if move.promotes_to is not None: + assert type(piece) == Pawn, "Trying to promote something that is not a pawn: not good!" + pieces_moving[move.pos] = move.promotes_to(move.pos, piece.colour) + # -- Set en passant target if needed if move.becomes_en_passant_target: ret._en_passant_target = pieces_moving[move.pos] diff --git a/src/logic/move.py b/src/logic/move.py index 0336e55..8de98e1 100644 --- a/src/logic/move.py +++ b/src/logic/move.py @@ -1,4 +1,5 @@ # from logic.pieces.piece import Piece +from typing import Type from logic.position import Position from enum import Enum @@ -8,13 +9,14 @@ class CastleSide(Enum): Queen = "O-O-O" class Move: - def __init__(self, piece: "Piece", pos: Position,/, is_capturing: bool = False, castle_side: CastleSide = CastleSide.Neither, en_passant: bool = False, becomes_en_passant_target: bool = False) -> None: + def __init__(self, piece: "Piece", pos: Position,/, is_capturing: bool = False, castle_side: CastleSide = CastleSide.Neither, en_passant: bool = False, becomes_en_passant_target: bool = False, promotes_to: Type["Piece"] = None) -> None: self.piece = piece self.pos = pos self.is_capturing = is_capturing self.castle_side = castle_side self.becomes_en_passant_target = becomes_en_passant_target self.en_passant = en_passant + self.promotes_to = promotes_to def to_algebraic(self) -> str: raise NotImplementedError("The move can't be translated to algbraic notation, as it was not implemented") diff --git a/src/logic/pieces/pawn.py b/src/logic/pieces/pawn.py index a01abda..03a6c65 100644 --- a/src/logic/pieces/pawn.py +++ b/src/logic/pieces/pawn.py @@ -1,5 +1,9 @@ from logic.move import Move +from logic.pieces.bishop import Bishop +from logic.pieces.knight import Knight from logic.pieces.piece import Colour, Piece +from logic.pieces.queen import Queen +from logic.pieces.rook import Rook from logic.position import Position class Pawn(Piece): @@ -13,7 +17,11 @@ class Pawn(Piece): (self.colour == Colour.BLACK and (capturable_piece := board.piece_at(self.pos.x - 1, self.pos.y - 1))) ): if capturable_piece.colour != self.colour: - ret.append(Move(self, capturable_piece.pos, is_capturing = True)) + if (self.colour == Colour.WHITE and capturable_piece.pos.y == 7) or (self.colour == Colour.BLACK and capturable_piece.pos.y == 0): + for piece in [Queen, Knight, Bishop, Rook]: + ret.append(Move(self, capturable_piece.pos, is_capturing=True, promotes_to=piece)) + else: + ret.append(Move(self, capturable_piece.pos, is_capturing = True)) # can we capture to the right? if self.pos.x < 7 and ( @@ -22,7 +30,11 @@ class Pawn(Piece): (self.colour == Colour.BLACK and (capturable_piece := board.piece_at(self.pos.x + 1, self.pos.y - 1))) ): if capturable_piece.colour != self.colour: - ret.append(Move(self, capturable_piece.pos, is_capturing = True)) + if (self.colour == Colour.WHITE and capturable_piece.pos.y == 7) or (self.colour == Colour.BLACK and capturable_piece.pos.y == 0): + for piece in [Queen, Knight, Bishop, Rook]: + ret.append(Move(self, capturable_piece.pos, is_capturing=True, promotes_to=piece)) + else: + ret.append(Move(self, capturable_piece.pos, is_capturing = True)) # -- Can we capture en passant? if board._en_passant_target is not None and \ @@ -38,16 +50,26 @@ class Pawn(Piece): # -- Normal moves if self.colour == Colour.WHITE: for dy in range(1, 3 if self.pos.y == 1 else 2): - if self.pos.y + dy > 7 or board.piece_at(self.pos.x, self.pos.y + dy): + y = self.pos.y + dy + if y > 7 or board.piece_at(self.pos.x, y): break - pos = Position(self.pos.x, self.pos.y + dy) - ret.append(Move(self, pos, becomes_en_passant_target=dy==2)) + pos = Position(self.pos.x, y) + if y == 7: + for piece in [Queen, Knight, Bishop, Rook]: + ret.append(Move(self, pos, promotes_to=piece)) + else: + ret.append(Move(self, pos, becomes_en_passant_target=dy==2)) else: for dy in range(1, 3 if self.pos.y == 6 else 2): - if self.pos.y - dy < 0 or board.piece_at(self.pos.x, self.pos.y - dy): + y = self.pos.y - dy + if y < 0 or board.piece_at(self.pos.x, y): break - pos = Position(self.pos.x, self.pos.y - dy) - ret.append(Move(self, pos, becomes_en_passant_target=dy==2)) + pos = Position(self.pos.x, y) + if y == 0: + for piece in [Queen, Knight, Bishop, Rook]: + ret.append(Move(self, pos, promotes_to=piece)) + else: + ret.append(Move(self, pos, becomes_en_passant_target=dy==2)) if not looking_for_check and board.is_check_for(self.colour): return self.keep_only_blocking(ret, board)