90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
from typing import Iterable, Callable
|
|
from itertools import product
|
|
from copy import deepcopy
|
|
|
|
|
|
class Piece:
|
|
|
|
def __init__(self, type, color):
|
|
self.type = type
|
|
self.color = color
|
|
|
|
def __str__(self):
|
|
return self.type.upper() if self.color == 'white' else self.type
|
|
|
|
@staticmethod
|
|
def possibleMoves(x, y, board, legalMoves=None) -> Callable[[int, int], Iterable[tuple]]:
|
|
piece = board.getPieceAt(x, y)
|
|
moves = []
|
|
|
|
# TODO: If player is in check, only validate the moves that are leading to places that can be blocked in order to save the king. Make a function that overwrites `moves`. Notice: The king is the only piece that can 'Escape' to a position that may or may not be in the list of positions to be blocked. Make an exception
|
|
|
|
pieceIsEnemyColor = lambda pieceToCheck: pieceToCheck != None and pieceToCheck.color != piece.color
|
|
pieceIsEmpty = lambda pieceToCheck: pieceToCheck == None
|
|
pieceIsEmptyOrEnemyColor = lambda pieceToCheck: pieceToCheck == None or pieceToCheck.color != piece.color
|
|
|
|
def addMoveIfTrue(xOffset, yOffset, condition: Callable[[Piece], bool]):
|
|
"""Tests a condition against a position away from self. Adds if condition returns true"""
|
|
if condition(board.getPieceAt(x + xOffset, y + yOffset)):
|
|
moves.append((x + xOffset, y + yOffset))
|
|
return True
|
|
return False
|
|
|
|
def assertNotCheck(newX, newY) -> bool:
|
|
testBoard = deepcopy(board)
|
|
testBoard.movePiece((x, y), (newX, newY)) # J
|
|
return not testBoard.checkCheck()
|
|
|
|
def addWhileInsideBoard(direction: tuple):
|
|
localX = x
|
|
localY = y
|
|
while localX not in [0, 7] and localY not in [0, 7]:
|
|
localX += direction[0]
|
|
localY += direction[1]
|
|
if board.getPieceAt(localX, localY) == None:
|
|
moves.append((localX, localY))
|
|
else:
|
|
if board.getPieceAt(localX, localY).color != piece.color:
|
|
moves.append((localX, localY))
|
|
return
|
|
|
|
if piece.type == 'p':
|
|
addMoveIfTrue(1, 1, pieceIsEnemyColor)
|
|
addMoveIfTrue(-1, 1, pieceIsEnemyColor)
|
|
if addMoveIfTrue(0, 1, pieceIsEmpty):
|
|
addMoveIfTrue(0, 2, lambda pieceToCheck: pieceToCheck == None and piece.moves == 0)
|
|
|
|
elif piece.type == 'n':
|
|
positions = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)]
|
|
for position in positions:
|
|
addMoveIfTrue(*position, pieceIsEmptyOrEnemyColor)
|
|
|
|
elif piece.type == 'k':
|
|
positions = list(product([-1, 0, 1], repeat=2))
|
|
positions.remove((0, 0))
|
|
for position in positions:
|
|
addMoveIfTrue(*position, pieceIsEmptyOrEnemyColor)
|
|
|
|
moves = [position for position in moves if assertNotCheck(*position)]
|
|
|
|
elif piece.type == 'r':
|
|
for direction in product([0, 1], repeat=2):
|
|
addWhileInsideBoard(direction)
|
|
|
|
elif piece.type == 'b':
|
|
for direction in product([-1, 1], repeat=2):
|
|
addWhileInsideBoard(direction)
|
|
|
|
elif piece.type == 'q':
|
|
directions = list(product([-1, 0, 1], repeat=2))
|
|
directions.remove((0, 0))
|
|
for direction in directions:
|
|
addWhileInsideBoard(direction)
|
|
|
|
#TODO: remove moves that will put the king in check
|
|
|
|
if legalMoves != None and piece.type != 'k':
|
|
moves = [move for move in moves if move in legalMoves]
|
|
|
|
return moves
|