implemented checkmate
This commit is contained in:
parent
496207861e
commit
6c0819428e
@ -55,3 +55,9 @@ class Controller:
|
|||||||
else:
|
else:
|
||||||
move = legal_moves_positions[0]
|
move = legal_moves_positions[0]
|
||||||
self._make_move(move)
|
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)
|
||||||
|
@ -131,11 +131,27 @@ class Board:
|
|||||||
if Position.is_within_bounds(x, y):
|
if Position.is_within_bounds(x, y):
|
||||||
possible_pos.append(Position(x, y))
|
possible_pos.append(Position(x, y))
|
||||||
else:
|
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:
|
if king.pos in possible_pos:
|
||||||
return True
|
return True
|
||||||
return False
|
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]:
|
def castling_writes_for(self, colour: Colour) -> set[CastleSide]:
|
||||||
return self._white_castling_write if colour == Colour.WHITE else self._black_castling_write
|
return self._white_castling_write if colour == Colour.WHITE else self._black_castling_write
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from logic.move import Move
|
|||||||
from .piece import Piece
|
from .piece import Piece
|
||||||
|
|
||||||
class Bishop(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 = []
|
ret = []
|
||||||
|
|
||||||
# looking north east
|
# looking north east
|
||||||
@ -17,5 +17,8 @@ class Bishop(Piece):
|
|||||||
# looking north west
|
# looking north west
|
||||||
ret.extend(self._look_direction(board, -1, 1))
|
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
|
return ret
|
||||||
|
|
||||||
|
@ -19,11 +19,13 @@ class King(Piece):
|
|||||||
if not board_after_move.is_check_for(self.colour):
|
if not board_after_move.is_check_for(self.colour):
|
||||||
ret.append(move)
|
ret.append(move)
|
||||||
|
|
||||||
|
if board.is_check_for(self.colour):
|
||||||
|
return self.keep_only_blocking(ret, board)
|
||||||
|
|
||||||
# -- Castles
|
# -- Castles
|
||||||
castling_writes = board.castling_writes_for(self.colour)
|
castling_writes = board.castling_writes_for(self.colour)
|
||||||
if len(castling_writes) == 0:
|
if len(castling_writes) == 0:
|
||||||
return ret
|
return ret
|
||||||
print(castling_writes)
|
|
||||||
|
|
||||||
if CastleSide.King in castling_writes:
|
if CastleSide.King in castling_writes:
|
||||||
clear = True
|
clear = True
|
||||||
@ -62,8 +64,6 @@ class King(Piece):
|
|||||||
if clear:
|
if clear:
|
||||||
ret.append(Move(self, Position(2, self.pos.y), castle_side=CastleSide.Queen))
|
ret.append(Move(self, Position(2, self.pos.y), castle_side=CastleSide.Queen))
|
||||||
|
|
||||||
print(ret)
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ class Knight(Piece):
|
|||||||
def letter(self):
|
def letter(self):
|
||||||
return "n"
|
return "n"
|
||||||
|
|
||||||
def legal_moves(self, board: "Board") -> list["Move"]:
|
def legal_moves(self, board: "Board", / , looking_for_check = False) -> list["Move"]:
|
||||||
ret = []
|
ret = []
|
||||||
for dx, dy in [
|
for dx, dy in [
|
||||||
(+2, +1), (+1, +2), # north east
|
(+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)
|
move = self._move_for_position(board, self.pos.x + dx, self.pos.y + dy)
|
||||||
if move is not None:
|
if move is not None:
|
||||||
ret.append(move)
|
ret.append(move)
|
||||||
|
|
||||||
|
if not looking_for_check and board.is_check_for(self.colour):
|
||||||
|
return self.keep_only_blocking(ret, board)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ from logic.pieces.piece import Colour, Piece
|
|||||||
from logic.position import Position
|
from logic.position import Position
|
||||||
|
|
||||||
class Pawn(Piece):
|
class Pawn(Piece):
|
||||||
def legal_moves(self, board) -> list[Move]:
|
def legal_moves(self, board, / , looking_for_check = False) -> list[Move]:
|
||||||
ret = []
|
ret = []
|
||||||
|
|
||||||
# can we capture to the left?
|
# can we capture to the left?
|
||||||
@ -37,4 +37,7 @@ class Pawn(Piece):
|
|||||||
pos = Position(self.pos.x, self.pos.y - dy)
|
pos = Position(self.pos.x, self.pos.y - dy)
|
||||||
ret.append(Move(self, pos))
|
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
|
return ret
|
||||||
|
@ -7,6 +7,9 @@ class Colour(Enum):
|
|||||||
WHITE = "white"
|
WHITE = "white"
|
||||||
BLACK = "black"
|
BLACK = "black"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.value
|
||||||
|
|
||||||
class Piece:
|
class Piece:
|
||||||
def __init__(self, pos: Position, colour: Colour) -> None:
|
def __init__(self, pos: Position, colour: Colour) -> None:
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
@ -16,6 +19,14 @@ class Piece:
|
|||||||
def letter(self):
|
def letter(self):
|
||||||
return type(self).__name__[0].lower()
|
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):
|
def _look_direction(self, board: "Board", mult_dx: int, mult_dy: int):
|
||||||
ret = []
|
ret = []
|
||||||
for d in range(1, 8):
|
for d in range(1, 8):
|
||||||
@ -50,5 +61,5 @@ class Piece:
|
|||||||
ret = type(self)(pos, self.colour)
|
ret = type(self)(pos, self.colour)
|
||||||
return ret
|
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")
|
raise NotImplementedError(f"Can't say what the legal moves are for {type(self).__name__}, the method hasn't been implemented yet")
|
||||||
|
@ -2,7 +2,7 @@ from logic.move import Move
|
|||||||
from .piece import Piece
|
from .piece import Piece
|
||||||
|
|
||||||
class Queen(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 = []
|
ret = []
|
||||||
|
|
||||||
# looking north east
|
# looking north east
|
||||||
@ -29,4 +29,7 @@ class Queen(Piece):
|
|||||||
# looking north
|
# looking north
|
||||||
ret.extend(self._look_direction(board, 0, 1))
|
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
|
return ret
|
||||||
|
@ -2,7 +2,7 @@ from logic.move import Move
|
|||||||
from .piece import Piece
|
from .piece import Piece
|
||||||
|
|
||||||
class Rook(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 = []
|
ret = []
|
||||||
|
|
||||||
# looking east
|
# looking east
|
||||||
@ -17,4 +17,7 @@ class Rook(Piece):
|
|||||||
# looking north
|
# looking north
|
||||||
ret.extend(self._look_direction(board, 0, 1))
|
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
|
return ret
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from tkinter import messagebox
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from PIL import ImageTk, Image
|
from PIL import ImageTk, Image
|
||||||
import os
|
import os
|
||||||
@ -60,6 +61,12 @@ class GUI(View):
|
|||||||
|
|
||||||
self._controller.on_tile_selected(x, y)
|
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:
|
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
|
||||||
self.canvas.delete("all")
|
self.canvas.delete("all")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from logic.board import Board
|
from logic.board import Board
|
||||||
from logic.move import Move
|
from logic.move import Move
|
||||||
from logic.pieces.piece import Piece
|
from logic.pieces.piece import Colour, Piece
|
||||||
|
|
||||||
|
|
||||||
class View:
|
class View:
|
||||||
@ -13,6 +13,12 @@ class View:
|
|||||||
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
|
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")
|
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:
|
def set_controller(self, controller: "Controller") -> None:
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user