implemented checkmate
Some checks failed
pre-release / Pre Release (push) Waiting to run
tagged-release / Tagged Release (push) Has been cancelled

This commit is contained in:
Karma Riuk 2025-01-31 18:19:27 +01:00
parent 496207861e
commit 6c0819428e
11 changed files with 73 additions and 11 deletions

View File

@ -55,3 +55,9 @@ class Controller:
else:
move = legal_moves_positions[0]
self._make_move(move)
if self._board.is_checkmate_for(self._board._turn):
self._view.notify_checkmate(self._board._turn)
if self._board.is_stalemate_for(self._board._turn):
self._view.notify_stalemate(self._board._turn)

View File

@ -131,11 +131,27 @@ class Board:
if Position.is_within_bounds(x, y):
possible_pos.append(Position(x, y))
else:
possible_pos += [move.pos for move in piece.legal_moves(self)]
possible_pos += [move.pos for move in piece.legal_moves(self, looking_for_check=True)]
if king.pos in possible_pos:
return True
return False
def is_checkmate_for(self, colour: Colour) -> bool:
""" Is it checkmate for the defending colour passed as parameter """
return self.is_check_for(colour) and self._no_legal_moves_for(colour)
def is_stalemate_for(self, colour: Colour) -> bool:
""" Is it stalemate for the defending colour passed as parameter """
return not self.is_check_for(colour) and self._no_legal_moves_for(colour)
def _no_legal_moves_for(self, colour: Colour) -> bool:
""" Return true if there are indeed no legal moves for the given colour (for checkmate or stalemate)"""
pieces = self._white if colour == Colour.WHITE else self._black
for piece in pieces.values():
if len(piece.legal_moves(self)) > 0:
return False
return True
def castling_writes_for(self, colour: Colour) -> set[CastleSide]:
return self._white_castling_write if colour == Colour.WHITE else self._black_castling_write

View File

@ -2,7 +2,7 @@ from logic.move import Move
from .piece import Piece
class Bishop(Piece):
def legal_moves(self, board: "Board") -> list[Move]:
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list[Move]:
ret = []
# looking north east
@ -17,5 +17,8 @@ class Bishop(Piece):
# looking north west
ret.extend(self._look_direction(board, -1, 1))
if not looking_for_check and board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
return ret

View File

@ -19,11 +19,13 @@ class King(Piece):
if not board_after_move.is_check_for(self.colour):
ret.append(move)
if board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
# -- Castles
castling_writes = board.castling_writes_for(self.colour)
if len(castling_writes) == 0:
return ret
print(castling_writes)
if CastleSide.King in castling_writes:
clear = True
@ -62,8 +64,6 @@ class King(Piece):
if clear:
ret.append(Move(self, Position(2, self.pos.y), castle_side=CastleSide.Queen))
print(ret)
return ret

View File

@ -4,7 +4,7 @@ class Knight(Piece):
def letter(self):
return "n"
def legal_moves(self, board: "Board") -> list["Move"]:
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list["Move"]:
ret = []
for dx, dy in [
(+2, +1), (+1, +2), # north east
@ -15,5 +15,9 @@ class Knight(Piece):
move = self._move_for_position(board, self.pos.x + dx, self.pos.y + dy)
if move is not None:
ret.append(move)
if not looking_for_check and board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
return ret

View File

@ -3,7 +3,7 @@ from logic.pieces.piece import Colour, Piece
from logic.position import Position
class Pawn(Piece):
def legal_moves(self, board) -> list[Move]:
def legal_moves(self, board, / , looking_for_check = False) -> list[Move]:
ret = []
# can we capture to the left?
@ -37,4 +37,7 @@ class Pawn(Piece):
pos = Position(self.pos.x, self.pos.y - dy)
ret.append(Move(self, pos))
if not looking_for_check and board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
return ret

View File

@ -7,6 +7,9 @@ class Colour(Enum):
WHITE = "white"
BLACK = "black"
def __str__(self) -> str:
return self.value
class Piece:
def __init__(self, pos: Position, colour: Colour) -> None:
self.pos = pos
@ -16,6 +19,14 @@ class Piece:
def letter(self):
return type(self).__name__[0].lower()
def keep_only_blocking(self, candidates: list[Move], board: "Board") -> list[Move]:
ret = []
for move in candidates:
board_after_move = board.make_move(move)
if not board_after_move.is_check_for(self.colour):
ret.append(move)
return ret
def _look_direction(self, board: "Board", mult_dx: int, mult_dy: int):
ret = []
for d in range(1, 8):
@ -50,5 +61,5 @@ class Piece:
ret = type(self)(pos, self.colour)
return ret
def legal_moves(self, board: "Board") -> list["Move"]:
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list["Move"]:
raise NotImplementedError(f"Can't say what the legal moves are for {type(self).__name__}, the method hasn't been implemented yet")

View File

@ -2,7 +2,7 @@ from logic.move import Move
from .piece import Piece
class Queen(Piece):
def legal_moves(self, board: "Board") -> list[Move]:
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list[Move]:
ret = []
# looking north east
@ -29,4 +29,7 @@ class Queen(Piece):
# looking north
ret.extend(self._look_direction(board, 0, 1))
if not looking_for_check and board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
return ret

View File

@ -2,7 +2,7 @@ from logic.move import Move
from .piece import Piece
class Rook(Piece):
def legal_moves(self, board: "Board") -> list[Move]:
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list[Move]:
ret = []
# looking east
@ -17,4 +17,7 @@ class Rook(Piece):
# looking north
ret.extend(self._look_direction(board, 0, 1))
if not looking_for_check and board.is_check_for(self.colour):
return self.keep_only_blocking(ret, board)
return ret

View File

@ -1,4 +1,5 @@
import tkinter as tk
from tkinter import messagebox
from typing import Type
from PIL import ImageTk, Image
import os
@ -60,6 +61,12 @@ class GUI(View):
self._controller.on_tile_selected(x, y)
def notify_checkmate(self, colour: Colour) -> None:
messagebox.showinfo("Checkmate", f"{colour} is currently checkmated")
def notify_stalemate(self, colour: Colour) -> None:
messagebox.showinfo("Stalemate", f"{colour} is currently stalemated")
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
self.canvas.delete("all")

View File

@ -1,6 +1,6 @@
from logic.board import Board
from logic.move import Move
from logic.pieces.piece import Piece
from logic.pieces.piece import Colour, Piece
class View:
@ -13,6 +13,12 @@ class View:
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
raise NotImplementedError(f"Can't update the board, the update_board() method of {type(self)} is not implemented")
def notify_checkmate(self, colour: Colour) -> None:
raise NotImplementedError(f"Can't notify of the checkmate, the notify_checkmate() method of {type(self)} is not implemented")
def notify_stalemate(self, colour: Colour) -> None:
raise NotImplementedError(f"Can't notify of the stalemate, the notify_stalemate() method of {type(self)} is not implemented")
def set_controller(self, controller: "Controller") -> None:
self._controller = controller