diff --git a/src/controller/controller.py b/src/controller/controller.py index 739a00a..f5ad203 100644 --- a/src/controller/controller.py +++ b/src/controller/controller.py @@ -1,4 +1,7 @@ from logic.board import Board +from logic.move import Move +from logic.pieces.piece import Piece +from logic.position import Position from view.view import View @@ -8,6 +11,47 @@ class Controller: self._view = view self._view.set_controller(self) + self._reset_selection() + + self._selected_piece: Piece = None + self._legal_moves: list[Move] = [] + + def _reset_selection(self): + self._selected_piece = None + self._legal_moves = [] + self._view.update_board(self._board, self._selected_piece, self._legal_moves) + + + def _show_legal_moves(self, pos: Position): + piece = self._board.piece_at(pos.x, pos.y) + + if piece: + if piece.colour != self._board._turn: + return + self._selected_piece = piece + self._legal_moves = piece.legal_moves(self._board) + self._view.update_board(self._board, self._selected_piece, self._legal_moves) + else: + self._reset_selection() + + def _make_move(self, move: Move) -> None: + self._board = self._board.make_move(move) + self._reset_selection() def on_tile_selected(self, x: int, y: int) -> None: - raise NotImplementedError(f"Cannot handle tile selected event, {type(self).__name__} did not implement it") + pos = Position(x, y) + print(f"Clicked on {pos.to_algebraic()}") + + piece = self._board.piece_at(x, y) + + if self._selected_piece is None or (piece is not None and piece != self._selected_piece): + self._show_legal_moves(pos) + else: + legal_moves_positions = [move for move in self._legal_moves if move.pos == pos] + assert len(legal_moves_positions) <= 1, f"Apparently we can make multiple moves towards {pos.to_algebraic()} with {type(self._selected_piece)}, which doesn't make sense..." + + if len(legal_moves_positions) == 0: # click on a square outside of the possible moves + self._reset_selection() + else: + move = legal_moves_positions[0] + self._make_move(move) diff --git a/src/controller/gui_controller.py b/src/controller/gui_controller.py deleted file mode 100644 index 953e53b..0000000 --- a/src/controller/gui_controller.py +++ /dev/null @@ -1,20 +0,0 @@ -from logic.board import Board -from view.view import View -from .controller import Controller - - -class GuiController(Controller): - def __init__(self, board: Board, view: View) -> None: - super().__init__(board, view) - self._view.update_board(self._board, None, []) - - def on_tile_selected(self, x: int, y: int) -> None: - piece = self._board.piece_at(x, y) - print(f"Clicked on {x, y}, {piece = }") - - if piece: - self._view.update_board(self._board, piece, piece.legal_moves(self._board)) - else: - self._view.update_board(self._board, None, []) - - diff --git a/src/logic/board.py b/src/logic/board.py index 6c21950..e741c55 100644 --- a/src/logic/board.py +++ b/src/logic/board.py @@ -1,3 +1,4 @@ +from logic.move import Move from logic.pieces.bishop import Bishop from logic.pieces.king import King from logic.pieces.knight import Knight @@ -111,3 +112,32 @@ class Board: if white_piece != None: return white_piece return black_piece + + def make_move(self, move: Move) -> "Board": + dest_piece = self.piece_at(move.pos.x, move.pos.y) + + if dest_piece: + assert dest_piece.colour != move.piece.colour, "A piece cannot cannot eat another piece of the same colour" + + ret = Board() + ret._white = self._white.copy() + ret._black = self._black.copy() + ret._turn = Colour.WHITE if self._turn == Colour.BLACK else Colour.BLACK + ret._white_castling_write = self._white_castling_write.copy() + ret._black_castling_write = self._black_castling_write.copy() + ret._en_passant_target = self._en_passant_target + + piece = move.piece + + if piece.colour == Colour.WHITE: + del ret._white[piece.pos] + ret._white[move.pos] = piece.move_to(move.pos) + if move.pos in ret._black: + del ret._black[move.pos] + else: + del ret._black[piece.pos] + ret._black[move.pos] = piece.move_to(move.pos) + if move.pos in ret._white: + del ret._white[move.pos] + + return ret diff --git a/src/logic/pieces/pawn.py b/src/logic/pieces/pawn.py index fe2339e..bb89667 100644 --- a/src/logic/pieces/pawn.py +++ b/src/logic/pieces/pawn.py @@ -37,6 +37,4 @@ class Pawn(Piece): pos = Position(self.pos.x, self.pos.y - dy) ret.append(PieceMove(self, pos)) - - print(ret) return ret diff --git a/src/logic/pieces/piece.py b/src/logic/pieces/piece.py index 971130f..ab9ec66 100644 --- a/src/logic/pieces/piece.py +++ b/src/logic/pieces/piece.py @@ -43,5 +43,9 @@ class Piece: def position(self) -> Position: return self.pos + def move_to(self, pos: Position) -> "Piece": + ret = type(self)(pos, self.colour) + return ret + def legal_moves(self, board: "Board") -> list["Move"]: raise NotImplementedError(f"Can't say what the legal moves are for {type(self).__name__}, the method hasn't been implemented yet") diff --git a/src/logic/position.py b/src/logic/position.py index a636bd7..48724ce 100644 --- a/src/logic/position.py +++ b/src/logic/position.py @@ -1,4 +1,7 @@ class Position: + _RANKS = range(1, 9) + _FILES = "abcdefgh" + _MIN_POS = 0 _MAX_POS = 7 @@ -14,6 +17,8 @@ class Position: return x >= Position._MIN_POS and x <= Position._MAX_POS \ and y >= Position._MIN_POS and y <= Position._MAX_POS + def to_algebraic(self) -> str: + return f"{Position._FILES[self.x]}{Position._RANKS[self.y]}" def __eq__(self, value: object, /) -> bool: if type(value) != type(self): diff --git a/src/main.py b/src/main.py index 3610b3c..7bc3528 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,4 @@ -from controller.gui_controller import GuiController +from controller.controller import Controller from logic.board import Board from view.gui import GUI from view.tui import TUI @@ -9,6 +9,6 @@ if __name__ == "__main__": view = GUI() - controller = GuiController(board, view) + controller = Controller(board, view) view.show()