Before we get these chess pieces to move on click of mouse, we need to know how many squares a given piece can move. We need to enforce rules for each of the chess pieces.
Before we start coding the rules, let's quickly recap the rules of chess:
The bottom line here is that we need to track three common things for each of the piece:
Because the preceding things can be tracked at a central place, let's define a method named moves_available
in our superclass, Pieces
(see code 4.04: pieces.py), for tracking moves available for all pieces as follows:
def moves_available(self, pos, diagonal, orthogonal, distance): board = self.board allowed_moves = [] orth = ((-1,0),(0,-1),(0,1),(1,0)) diag = ((-1,-1),(-1,1),(1,-1),(1,1)) piece = self beginningpos = board.num_notation(pos.upper()) if orthogonal and diagonal: directions = diag+orth elif diagonal: directions = diag elif orthogonal: directions = orth for x,y in directions: collision = False for step in range(1, distance+1): if collision: break dest = beginningpos[0]+step*x, beginningpos[1]+step*y if self.board.alpha_notation(dest) not in board.occupied('white') + board.occupied('black'): allowed_moves.append(dest) elif self.board.alpha_notation(dest) in board.occupied(piece.color): collision = True else: allowed_moves.append(dest) collision = True allowed_moves = filter(board.is_on_board, allowed_moves) return map(board.alpha_notation, allowed_moves)
The description of the code is listed as follows:
allowed_moves
.allowed_moveslist
.collision = True
is our way to break out of the loop. We need to break out of the loop in two cases: when the destination is occupied, and when it is not occupied, and we have already appended that position into our list of possible moves.King, queen, rook, and bishop pieces on the chessboard have relatively simple rules governing them. These pieces can capture only in the direction in which they move.
Moreover, they move in either orthogonal, diagonal, or a combination of these two directions. We have already coded moves_available
in our superclass to handle these directions.
Accordingly, deciding their available moves is just a matter of passing the right arguments to our moves_available
method.
class King(Piece): shortname = 'k' def moves_available(self,pos): return super(King, self).moves_available(pos.upper(), True, True, 1) class Queen(Piece): shortname = 'q' def moves_available(self,pos): return super(Queen,self).moves_available(pos.upper(), True, True, 8) class Rook(Piece): shortname = 'r' def moves_available(self,pos): return super(Rook, self).moves_available(pos.upper(), False, True, 8) class Bishop(Piece): shortname = 'b' def moves_available(self,pos): return super(Bishop,self).moves_available(pos.upper(), True, False, 8)
Knight is a different beast because it does not move orthogonally or diagonally. It can also jump over pieces.
Let's, therefore override the moves_available
method from our Knight
class.
The Knight
class is defined as follows (see code 4.04: pieces.py):
class Knight(Piece): shortname = 'n' def moves_available(self,pos): board = self.board allowed_moves = [] beginningpos = board.num_notation(pos.upper()) piece = board.get(pos.upper()) changes=((-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)) for x,y in changes: dest = beginningpos[0]+x, beginningpos[1]+y if(board.alpha_notation(dest) not in board.occupied(piece.color)): allowed_moves.append(dest) allowed_moves = filter(board.is_on_board, allowed_moves) return map(board.alpha_notation, allowed_moves)
The description of the code is listed as follows:
Pawn too has a unique movement, in that it moves forward, but captures diagonally.
Let's similarly override the moves_available
class from within the Pawn
class as follows (see code 4.04: pieces.py):
class Pawn(Piece): shortname = 'p' def moves_available(self, pos): board = self.board piece = self if self.color == 'white': startpos, direction, enemy = 1, 1, 'black' else: startpos, direction, enemy = 6, -1, 'white' allowed_moves = [] prohibited = board.occupied('white') + board.occupied('black') beginningpos = board.num_notation(pos.upper()) forward = beginningpos[0] + direction, beginningpos[1] # Can a piece move forward? if board.alpha_notation(forward) not in prohibited: allowed_moves.append(forward) if beginningpos[0] == startpos: # If pawn in starting pos allow a double move double_forward = (forward[0] + direction, forward[1]) if board.alpha_notation(double_forward) not in prohibited: allowed_moves.append(double_forward) # Check for Capturing Moves Available for a in range(-1, 2, 2): attack = beginningpos[0] + direction, beginningpos[1] + a if board.letter_notation(attack) in board.occupied(enemy): allowed_moves.append(attack) allowed_moves = filter(board.is_on_board, allowed_moves) return map(board.alpha_notation, allowed_moves)
The description of the code is listed as follows:
startpos
, direction
, and enemy
depending on whether the pawn is black or white.moves_allowed
methods, this method also collects all allowed moves in a blank list, allowed_moves
.forward
, which holds the position of the one square immediately ahead of the current position of pawn.allowed_moves
list.allowed_moves
list.allowed_moves
.18.116.118.229