import board from board import BLACK, WHITE, onBoard def addPos((c,r),(dc,dr)): return (c+dc,r+dr) class Piece (object): def isOpponent(self, otherPieceOrNone): if otherPieceOrNone == None: return False return otherPieceOrNone.color != self.color def isMyPiece(self, otherPieceOrNone): if otherPieceOrNone == None: return False return otherPieceOrNone.color == self.color class Fog (Piece): def code(self): return "?" class MoveablePiece (Piece): def __init__(self, board, color): self.board = board self.color = color def moves(self): possibleMoves = [] return possibleMoves def attacks(self): """Used to determine visibility. This is only different for pawns""" return self.moves() def openSquare(self,pos): return onBoard(pos) and not self.isMyPiece(self.board.pieceAt(pos)) def neighbors(self, *offsets): src = self.board.whereIs(self) return filter(self.openSquare, [addPos(src,off) for off in offsets]) def ray(self, src, offset): """Generator for ranged piece movement""" pos = addPos(src,offset) while self.openSquare(pos): yield(pos) if self.isOpponent(self.board.pieceAt(pos)): break pos = addPos(pos,offset) def rays(self, *offsets): src = self.board.whereIs(self) return [p for off in offsets for p in self.ray(src,off)] class Bishop(MoveablePiece): def code(self): if self.color == BLACK: return "b" else: return "B" def moves(self): return self.rays((1,1), (-1,1), (1,-1), (-1,-1)) class King(MoveablePiece): def code(self): if self.color == BLACK: return "k" else: return "K" def moves(self): return self.neighbors((1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,1), (1,-1), (-1,-1)) class Knight(MoveablePiece): def code(self): if self.color == BLACK: return "n" else: return "N" def moves(self): return self.neighbors((-1, 2) ,(-1, -2), (1,2),(1,-2),(2,1),(2,-1),(-2,1),(-2,-1)) class Pawn(MoveablePiece): def code(self): if self.color == BLACK: return "p" else: return "P" def forward(self): if self.color == WHITE: return 1 else: return -1 def unmovedPawnRank(self): if self.color == WHITE: return 1 else: return 6 def moves(self): possibleMoves = [] (col, rank) = self.board.whereIs(self) spot = (col, rank + self.forward()) # straight forward if onBoard(spot) and not self.board.pieceAt(spot): possibleMoves.append(spot) # Initial two-space pawn move. if rank == self.unmovedPawnRank(): spot = (col, rank + 2*self.forward()) if not self.board.pieceAt(spot): possibleMoves.append(spot) # pawn captures for delta in (-1, 1): spot = (col + delta, rank + self.forward()) if onBoard(spot) and self.isOpponent(self.board.pieceAt(spot)): possibleMoves.append(spot) # En passant capture. if rank == self.enPassantRank(): start, stop = self.board.lastMove otherCol, otherRank = stop if (abs(otherCol - col) == 1 and stop[1] == rank and abs(start[1] - stop[1]) == 2 and isinstance(self.board.pieceAt(stop), Pawn)): possibleMoves.append((otherCol, (start[1] + stop[1]) // 2)) return possibleMoves def attacks(self): possibleAttacks = [] (col, rank) = self.board.whereIs(self) for delta in (-1, 1): # attacks spot = (col + delta, rank + self.forward()) if onBoard(spot): possibleAttacks.append(spot) # En passant capture. if rank == self.enPassantRank(): start, stop = self.board.lastMove otherCol, otherRank = stop if (abs(otherCol - col) == 1 and stop[1] == rank and abs(start[1] - stop[1]) == 2 and isinstance(self.board.pieceAt(stop), Pawn)): possibleAttacks.append((otherCol, (start[1] + stop[1]) // 2)) return possibleAttacks def enPassantRank(self): if self.color == WHITE: return 4 else: return 3 class Queen(MoveablePiece): def code(self): if self.color == BLACK: return "q" else: return "Q" def moves(self): return self.rays((1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,1), (1,-1), (-1,-1)) class Rook(MoveablePiece): def code(self): if self.color == BLACK: return "r" else: return "R" def moves(self): return self.rays((1,0), (-1,0), (0,1), (0,-1))