In our drum program, we had decided on a notation to describe a set of beat patterns. We could then store (pickle) that beat pattern notation and reproduce (unpickle) it later. The chess program is no different. It too needs a suitable notation for describing chess pieces and for locating their positions on the board.
We can define our own notation for representing chess piece and their positions, but it turns out that there already exists a globally accepted, simple, compact, and standard notation for representing a chessboard. The notation is called Forsyth-Edwards notation (FEN) available at http://en.wikipedia.org/wiki/Forsyth-Edwards_Notation.
We might have decided to define our notation, but we preferred not to reinvent the wheel here.
The FEN record for starting position of a chess game is written as:
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
The key things to note about the notation are as follows:
/
symbol.p
, knight = n
, bishop = b
, rook = r
, queen = q
and king = k
).PNBRQK
), but black pieces are represented by lowercase letters (pnbrqk
).1
through 8
(the number of blank squares).w
denotes white turn, and letter b
denotes black turn.KQkq
indicates whether or not castling feature is available. If neither castle, this is -
. Otherwise, this has one or more letters: K
(white can castle kingside), Q
(white can castle queenside), k
(black can castle kingside), and/or q
(black can castle queenside)._
captures En passant details for the game. We will not be implementing castling and En passant features in our game, so we can safely disregard these two records for now.The notation as previously stated can be represented pictorially along x and y axis as follows:
Using this notation, we can accurately represent any particular square on the chessboard.
The color of piece depends on whether the alphabet is in small letters (black) or capital letters (white).
Thus A1 denotes the bottom and left-most square on the chessboard. Currently, it is occupied by a white rook. The C3 position is currently empty, and E8 has black king and A8 has a black rook.
Following these rules, here is how the FEN notation would change after the following indicative turns played (http://en.wikipedia.org/wiki/Forsyth-Edwards_Notation):
After first move, P
to e4
:
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
After second move, p
to c5
:
rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2
After third move, N
to f3
:
rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2
All our chessboard and piece related logic will use the preceding notation. It is, therefore, very important that we fully understand this notation before we proceed to code our game.
Now that we are clear about the preceding notation, let's apply the notation to represent our chessboard. The key idea here is that, given a FEN notation, we should be able to represent it on the board.
Let's now first code the model code for pieces.py
(see code 4.02 pieces.py) by creating a Piece
super class as follows:
class Piece(): def __init__(self, color): if color == 'black': self.shortname = self.shortname.lower() elif color == 'white': self.shortname = self.shortname.upper() self.color = color def ref(self, board): ''' Get a reference of chessboard instance''' self.board = board
The description of the code is listed as follows:
Piece ()
. It's __init__
method, which takes a color as an argument. In accordance with our FEN notation, it changes the shortname to lowercase letter for black and uppercase letter for white. The color handling is done in the superclass, Piece
, because it is a common feature for all chess pieces.ref
. Its only purpose is to get an instance of the chessboard into the object namespace for the board and pieces to interact. We need this method, because our pieces will ultimately be interacting with the chessboard. Accordingly, we need a reference of the chessboard instance within the Piece
class.We can create individual child classes for all pieces as follows:
class King(Piece): shortname = 'k' class Queen(Piece): shortname = 'q' class Rook(Piece): shortname = 'r' class Knight(Piece): shortname = 'n' class Bishop(Piece): shortname = 'b' class Pawn(Piece): shortname = 'p'
The description of the code is listed as follows:
King
, Queen
, Rook
, Knight
, Bishop
, and Pawn
. These classes are derived from the Piece
super class.We will define a method to return the piece instance as follows:
import sys SHORT_NAME = {'R':'Rook', 'N':'Knight', 'B':'Bishop', 'Q':'Queen', 'K':'King', 'P':'Pawn'} def create_piece(piece, color='white'): if piece in (None, ''): return if piece.isupper(): color = 'white' else: color = 'black' piece = SHORT_NAME[piece.upper()] module = sys.modules[__name__] return module.__dict__[piece](color)
The description of the code is listed as follows:
Now that we have a basic model ready for pieces, let's code the model to deal with their placement on the chessboard. We code this in chessboard.py
.(see code 4.02 chessboard.py) by creating a Board
class as follows:
import pieces import re START_PATTERN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 1' class Board(dict): y_axis = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H') x_axis = (1,2,3,4,5,6,7,8) def __init__(self, patt = None): self.process_notation(START_PATTERN)
The description of the code is listed as follows:
Board
class as a subclass of built-in dict
type. This is because we will store the pattern as a dictionary.x_axis
and y_axis
for our chessboard as nonimmutable tuples.__init__
method of our class simply calls the process_notation
method of the class.Pieces on Board
for a given FEN notation can be displayed as follows:
def process_notation(self, patt): self.clear() patt = patt.split('') # expand_whitespaces blanks def expand_whitespaces(match): return '' * int(match.group(0)) patt[0] = re.compile(r'd').sub(expand_whitespaces, patt[0]) for x, row in enumerate(patt[0].split('/')): for y, alphabet in enumerate(row): if alphabet == '': continue xycoord = self.alpha_notation((7-x,y)) self[xycoord] = pieces.piece(alphabet) self[xycoord].ref(self) if patt[1] == 'w': self.player_turn = 'white' else: self.player_turn = 'black'
The description of the code is listed as follows:
process_notation
method is to first expand the blank spaces represented by integers into actual spaces. It uses Python built-in regular expression module (re
) to expand white spaces in a given FEN notation.expand_whitespaces
, does something that might be tricky for Python beginners. It replaces each digit by the corresponding number of whitespaces, so you can later assume that a whitespace is an empty square. It then converts the FEN notation into a string corresponding to x and y alphanumeric coordinate for every piece. For doing this, it calls another method named alpha_notation
, which is defined in step 7.Finally, let's end this iteration by defining a method to check if a given coordinate is on the board, as follows (see code 4.02 chessboard.py):
def is_on_board(self, coord): ifcoord[1] < 0 or coord[1] > 7 or coord[0] < 0 or coord[0] >7: return False else: return True
We need a way to convert the x and y coordinates for a piece to its alphabetic equivalent notation for example, A1, D5, E3, and so on. We accordingly define the alpha_notation
method as follows:
def alpha_notation(self,xycoord): if not self.is_on_board(xycoord): return return self.y_axis[xycoord[1]] + str(self.x_axis[xycoord[0]])
Similarly, we define a method that takes in an x,y coordinate as input and returns its equivalent numerical notation, as follows:
def num_notation(self, xycoord): return int(xycoord[1])-1, self.y_axis.index(xycoord[0])
Before every move, we will need to check all the places occupied by all the pieces of a given color. This is required not only to calculate valid moves, but to also ensure that move by some other piece does not cause a check on the king.
Accordingly, let's define a method to return a list of coordinates occupied by a given color (see code 4.02 chessboard.py) as follows:
def occupied(self, color): result = [] for coord in self: if self[coord].color == color: result.append(coord) return result
In this iteration, we created a basic Piece
class and dummy child classes for each of the pieces found on the chessboard. The individual piece classes inherit from the parent Piece
class. We handle color identification in the parent class because it is something we need to do for all child classes.
We then defined our Board
class and added some methods that we will surely need every time we want to move a piece on the board.
We are yet to display those pieces on the board. We do that in the next iteration.
3.149.27.72