Modeling a ChessBoard And Mechanics Of Its Pieces In Python

chessboard

Hello, Everyone. First of all, Happy New Year 2017. In this year, I sincerly hope success for you, for your friends and family members. This article is going to discuss how python enables us to materialize our ideas into a quick reality by taking chess as an example.

Coming to the point, we all love the chess game. It is a beautiful game with a lot of brain work needed. Openings, Middle games and Endgames are always tough to master. In the 21st century, we have powerful chess engines those can compete with world’s best players. Have you ever thought how the chess game is modeled on a computer?. How pieces are looked underneath and what abstraction does calculate everything. The beauty of mathematics and programming language like Python makes it easy to implement any given problem in an elegant way. This is not a tutorial to build a chess engine. But this is the building block of any chess game.

The code for this tutorial is always available at this link

https://github.com/narenaryan/ChessMoves

Objective

The main motto of this article is to design a program which actually takes the  input of a chess notation and returns all possible moves for a given piece. For example, “What are the all possible moves of a Knight which is stationed on “g2”. It should return all possible moves from that location.

  • e1
  • e3
  • f4
  • h4

For this we need:

  • ChessBoard
  • Pieces

Introduction

A chessboard is a 8 * 8 matrix. It has a notation from A-H and 1-8. Here (1-8) are rows and (A-H) are columns. We always refer the position of a chess piece by its chess notation. For example “e4” means 4th row, 5th column of the 8 * 8 matrix.

screen-shot-2017-01-01-at-3-18-13-pm

In Python, we can create a chessboard with one line.

>>> chessBoard = [[1] * 8 for i in xrange(8)]

This actually creates a list of lists with exactly 8 elements like this

>>> print chessBoard
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]]

Now we have a chessboard. Let us start modeling the pieces and their moves.

Before going into the pieces, we need to think about something. As I told, rows and columns are in 1-8 & A-H notation but not in (0-n) notation of a matrix. So we should write a conversion formulae for translating chess notation to actual matrix index notation.

>>> chess_map_from_alpha_to_index = {
   "a" : 0,
   "b" : 1,
   "c" : 2,
   "d" : 3,
   "e" : 4,
   "f" : 5,
   "g" : 6,
   "h" : 7
}
>>> chess_map_from_index_to_alpha = {
   0: "a",
   1: "b",
   2: "c",
   3: "d",
   4: "e",
   5: "f",
   6: "g",
   7: "h"
}

I here discuss 4 important chess pieces. You can implement for others in a similar fashion.

  • Knight (Horse)
  • Rook (Elephant)
  • Bishop (Camel)
  • Queen

I presume all know the rules of movement of each piece. If not please refer this short intro. https://en.wikipedia.org/wiki/Chess_piece#Moves_of_the_pieces

Knight

Now let us start with the Knight. We all know the Knight moves in an L shape path in all possible directions. First, we can assume a Knight is in the center. Then just pick up all possible positions of the matrix where knight can move to. Let us think the initial position of the knight is at D4. Then the matrix diagram would be like this

This slideshow requires JavaScript.

It means the coordinates of the neighboring moves of a knight can be easily put down into few mathematical equations. By careful observation, we can come to know that all the moves are in this form.

All the below calculations for the given index gives the neighbor co-ordinates. If i is row index and j is column index, then

  • (i + 2) , (j – 1)
  • (i – 1), (j + 2)
  • (i – 2), (j – 1)
  • (i + 2), (j + 1)
  • (i + 1), (j + 2)
  • (i – 1), (j  + 1)
  • (i + 1), (j – 1)
  • (i – 2), (j  + 1)

Now if we write a python function with the given details

 def getKnightMoves(pos, chessBoard):
    """ A function(positionString, board) that returns the all possible moves
        of a knight stood on a given position
    """
    column, row = list(pos.strip().lower())
    row = int(row) - 1
    column = chess_map_from_alpha_to_index[column]
    i,j = row, column
    solutionMoves = []
    try:
        temp = chessBoard[i + 1][j - 2]
        solutionMoves.append([i + 1, j - 2])
    except:
        pass
    try:
        temp = chessBoard[i + 2][j - 1]
        solutionMoves.append([i + 2, j - 1])
    except:
        pass
    try:
        temp = chessBoard[i + 2][j + 1]
        solutionMoves.append([i + 2, j + 1])
    except:
        pass
    try:
       temp = chessBoard[i + 1][j + 2]
       solutionMoves.append([i + 1, j + 2])
    except:
        pass
    try:
        temp = chessBoard[i - 1][j + 2]
        solutionMoves.append([i - 1, j + 2])
    except:
        pass
    try:
        temp = chessBoard[i - 2][j + 1]
        solutionMoves.append([i - 2, j + 1])
    except:
        pass
    try:
        temp = chessBoard[i - 2][j - 1]
        solutionMoves.append([i - 2, j - 1])
    except:
        pass
    try:
        temp = chessBoard[i - 1][j - 2]
        solutionMoves.append([i - 1, j - 2])
    except:
        pass

    # Filter all negative values
    temp = [i for i in solutionMoves if i[0] >=0 and i[1] >=0]
    allPossibleMoves = ["".join([chess_map_from_index_to_alpha[i[1]], str(i[0] + 1)]) for i in temp]
    allPossibleMoves.sort()
    return allPossibleMoves

We need to pass the position string and chess board to this function and it returns all possible moves in form of a string.

>>> print getKnightMoves("D4", chessBoard)
[b3, b5, c2, c6, e2, e6, f3, f5]
The output given by this function can be fed to any GUI engine to show all possible valid moves.

Rook

Rook moves in straight lines. It means it can move either horizontally or vertically. The logic for the movement is different from the Knight. So we need to observe what factors we need to collect to model the movements of a Rook.

rook1

In chess terminology Rook can move on Rank(row) and File(column). The Rook which is placed at” E6″ can move across 6th Rank and E file. So all possible moves are:

  • E1, E2, E3, E4, E5,  E7, E8, A6, B6, C6, D6, F6, G6, H6

Now in order to model it programmatically, we take end points as reference and by excluding the existing index we can compute all possible points in matrix. So let us define a function called getRookMoves()

def getRookMoves(pos, chessBoard):
    column, row = list(pos.strip().lower())
    row = int(row) - 1
    column = chess_map_from_alpha_to_index[column]
    i,j = row, column
    solutionMoves = []

    # Compute the moves in Rank
    for j in xrange(8):
        if j != column:
            solutionMoves.append((row, j))

    # Compute the moves in File
    for i in xrange(8):
        if i != row:
            solutionMoves.append((i, column))

    solutionMoves = ["".join([chess_map_from_index_to_alpha[i[1]], str(i[0] + 1)]) for i in solutionMoves]
    solutionMoves.sort()
    return solutionMoves
 >>> getRookMoves("E6", chessBoard)
['a6', 'b6', 'c6', 'd6', 'e1', 'e2', 'e3', 'e4', 'e5', 'e7', 'e8', 'f6', 'g6', 'h6']

So the logic is straightforward. We just iterated from the beginning index to the last index of both row and columns where rook is currently placed.
In order to make this program more interactive one, I use command line args to take inputs for specifying the type of chess piece and its location. Then all possible moves will be returned back. We are going to use an inbuilt python library called argparse for making a command line application. We are going to print the JSON string for other application to make use of it.
import argparse, json

parser = argparse.ArgumentParser()
parser.add_argument("-p", "--piece", help="chess piece name: ex- rook, knight, pawn etc")
parser.add_argument("-l", "--location", help="chess notation string: ex- E4, D6 etc")
args = parser.parse_args()

piece = args.piece.strip().lower()
location = args.location.strip()

# According to the type of piece adjust function
if (piece == "rook"):
    print json.dumps({"piece":piece,
                      "current_location": location,
                      "moves": getRookMoves(location, chessBoard)})
elif (piece == "knight"):
    print json.dumps({"piece":piece,
                      "current_location": location,
                      "moves": getKnightMoves(location, chessBoard)})
This output looks like this.

This slideshow requires JavaScript.

You can also view the help option if you don’t know what to do. Use -h or –help option with the program on command line.
So here for an illustrating purpose, I used Knight and Rook. In a similar way, we can compute functions for Pawn, King, Queen and Bishop too. That I am leaving as an exercise for you. The code for script and reference images are here.

Conclusion

This is the initial step for any chess game. From here you will build up logic and algorithms for gameplay. Hope you enjoyed this and Happy New Year once again.

Leave a comment