2020-11-10 23:56:21 +01:00
from typing import Iterable , Callable
from itertools import product
2020-11-12 00:17:02 +01:00
from copy import deepcopy
2020-11-10 23:56:21 +01:00
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
2020-11-12 00:17:02 +01:00
def possibleMoves ( x , y , board , legalMoves = None ) - > Callable [ [ int , int ] , Iterable [ tuple ] ] :
2020-11-10 23:56:21 +01:00
piece = board . getPieceAt ( x , y )
moves = [ ]
2020-11-12 00:17:02 +01:00
# 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
2020-11-10 23:56:21 +01:00
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
2020-11-12 00:17:02 +01:00
def addMoveIfTrue ( xOffset , yOffset , condition : Callable [ [ Piece ] , bool ] ) :
""" Tests a condition against a position away from self. Adds if condition returns true """
2020-11-10 23:56:21 +01:00
if condition ( board . getPieceAt ( x + xOffset , y + yOffset ) ) :
moves . append ( ( x + xOffset , y + yOffset ) )
return True
return False
2020-11-12 00:17:02 +01:00
def assertNotCheck ( newX , newY ) - > bool :
testBoard = deepcopy ( board )
testBoard . movePiece ( ( x , y ) , ( newX , newY ) ) # J
return not testBoard . checkCheck ( )
def addWhileInsideBoard ( direction : tuple ) :
2020-11-10 23:56:21 +01:00
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 )
2020-11-12 00:17:02 +01:00
moves = [ position for position in moves if assertNotCheck ( * position ) ]
2020-11-10 23:56:21 +01:00
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 )
2020-11-12 00:17:02 +01:00
#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 ]
2020-11-10 23:56:21 +01:00
return moves