Forsyth–Edwards Notation

by aberent 22. June 2009 07:47

In this post I am going to discuss Forsyth-Edwards Notation (FEN) and its implementation in a chess engine.   FEN is a standard way of describing a chess position, containing enough information to restart the chess game from that position.  It is based on a notation developed by a Scottish journalist, David Forsyth in the 19th century.

Why is FEN useful to us?

1. We can use FEN to store game history allowing us to search for move repetitions as well as display the history of the game to the user.  Furthermore if we find a FEN position that has occurred in the past, we can skip searching for the best move and use the same response we used before.

2. We can use FEN strings to implement an Opening Book.    With two FEN strings I can store position pairs representing a starting position and the prescribed response.

The implementation of Forsyth–Edwards Notation

FEN notation uses only ASCII characters stored in a single line.  A FEN string or record contains 6 fields.  These are separated by a space.

  • Piece placement from white’s perspective.  Each row is noted, starting from row 8 (blacks row0 and ending with row 1 (white’s row).  Each piece is described from column to column h.  Each piece is identified by a single letter. 

Pawn: P

Knight: K

Bishop: B

Rook: R

Queen: Q

King: K

White pieces are noted using capital letters and black using lower case.  So P would be a white pawn and p would signify a black pawn.
Empty squares (spaces) are described using numbers, each number representing the number of empty squares before the next chess pieces.  The number 8 would describe a completely empty row. 
The character / describes a new row.

So for a starting position we may see: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR

  • The second column in the Forsyth–Edwards Notation represents whose turn it is.  A single character is used w for white and b for black.
  • The third column represents if castling is still allowed.  If neither side can castle then the character – is used.   Otherwise the following letters are used.  K means white can castle King Side, Q means White can castle Queen side.  Lower case k and q mean the same for black.
  • The fourth column represents an En Passant target square.  The square that the pawn hopped to get to its row, or the position behind the pawn.  If there is no En Passant square then the character – is used.  So if the last move was pawn to e4, we will record e3 in this column.
  • The fifth column contains the number of half moves since the last pawn move or capture.  This is used to determine the 50 move draw scenario.  
  • The last column contains the full move number.  The number starts at 1 and is incremented after black’s move.

Examples:

FEN for the starting position:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

FEN after the white pawn moved to E4:

rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1

FEN after the black pawn moved to C5

rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2

And then after the white knight moves to F3:

rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2

Forsyth–Edwards Notation Code

In my chess engine FEN is implemented in two methods.  The first method will produce a FEN string for any chess Board.

internal static string Fen(bool boardOnly, Board board)
{
 string output = String.Empty;
 byte blankSquares = 0;

 for (byte x = 0; x < 64; x++)
 {
  byte index = x;

  if (board.Squares[index].Piece != null)
  {
   if (blankSquares > 0)
   {
    output += blankSquares.ToString();
    blankSquares = 0;
   }

   if (board.Squares[index].Piece.PieceColor == ChessPieceColor.Black)
   {
    output += Piece.GetPieceTypeShort(board.Squares[index].Piece.PieceType).ToLower();
   }
   else
   {
    output += Piece.GetPieceTypeShort(board.Squares[index].Piece.PieceType);
   }
  }
  else
  {
   blankSquares++;
  }

  if (x % 8 == 7)
  {
   if (blankSquares > 0)
   {
    output += blankSquares.ToString();
    output += "/";
    blankSquares = 0;
   }
   else
   {
    if (x > 0 && x != 63)
    {
     output += "/";
    }
   }
  }
 }

 if (board.WhoseMove == ChessPieceColor.White)
 {
  output += " w ";
 }
 else
 {
  output += " b ";
 }

 string spacer = "";

 if (board.WhiteCastled == false)
 {
  if (board.Squares[60].Piece != null)
  {
   if (board.Squares[60].Piece.Moved == false)
   {
    if (board.Squares[63].Piece != null)
    {
     if (board.Squares[63].Piece.Moved == false)
     {
      output += "K";
      spacer = " ";
     }
    }
    if (board.Squares[56].Piece != null)
    {
     if (board.Squares[56].Piece.Moved == false)
     {
      output += "Q";
      spacer = " ";
     }
    }
   }
  }
 }

 if (board.BlackCastled == false)
 {
  if (board.Squares[4].Piece != null)
  {
   if (board.Squares[4].Piece.Moved == false)
   {
    if (board.Squares[7].Piece != null)
    {
     if (board.Squares[7].Piece.Moved == false)
     {
      output += "k";
      spacer = " ";
     }
    }
    if (board.Squares[0].Piece != null)
    {
     if (board.Squares[0].Piece.Moved == false)
     {
      output += "q";
      spacer = " ";
     }
    }
   }
  }

  
 }

 if (output.EndsWith("/"))
 {
  output.TrimEnd('/');
 }


 if (board.EnPassantPosition != 0)
 {
  output += spacer + GetColumnFromByte((byte)(board.EnPassantPosition % 8)) + "" + (byte)(8 - (byte)(board.EnPassantPosition / 8)) + " ";
 }
 else
 {
  output += spacer + "- ";
 }

 if (!boardOnly)
 {
  output += board.FiftyMove + " ";
  output += board.MoveCount + 1;
 }
 return output.Trim();
}

The second method is a Board constructor that will accept a FEN string and create a Chess Board based on the content of the string.  Strictly speaking you will not need this code.  I only use this to allow people to enter FEN strings in the user interface.   Since FEN is a standard used in many chess programs allowing users to input FEN strings will allow them to visualize chess positions they might find on the internet. 

internal Board(string fen) : this()
{
 byte index = 0;
 byte spc = 0;

 WhiteCastled = true;
 BlackCastled = true;
 byte spacers = 0;

 WhoseMove = ChessPieceColor.White;

 if (fen.Contains("a3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 40;
 }
 else if (fen.Contains("b3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 41;
 }
 else if (fen.Contains("c3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 42;
 }
 else if (fen.Contains("d3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 43;
 }
 else if (fen.Contains("e3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 44;
 }
 else if (fen.Contains("f3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 45;
 }
 else if (fen.Contains("g3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 46;
 }
 else if (fen.Contains("h3"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 47;
 }


 if (fen.Contains("a6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 16;
 }
 else if (fen.Contains("b6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 17;
 }
 else if (fen.Contains("c6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition =18;
 }
 else if (fen.Contains("d6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 19;
 }
 else if (fen.Contains("e6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 20;
 }
 else if (fen.Contains("f6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 21;
 }
 else if (fen.Contains("g6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 22;
 }
 else if (fen.Contains("h6"))
 {
  EnPassantColor = ChessPieceColor.White;
  EnPassantPosition = 23;
 }

 foreach (char c in fen)
 {

  if (index < 64 && spc == 0)
  {
   if (c == '1' && index < 63)
   {
    index++;
   }
   else if (c == '2' && index < 62)
   {
    index += 2;
   }
   else if (c == '3' && index < 61)
   {
    index += 3;
   }
   else if (c == '4' && index < 60)
   {
    index += 4;
   }
   else if (c == '5' && index < 59)
   {
    index += 5;
   }
   else if (c == '6' && index < 58)
   {
    index += 6;
   }
   else if (c == '7' && index < 57)
   {
    index += 7;
   }
   else if (c == '8' && index < 56)
   {
    index += 8;
   }
   else if (c == 'P')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Pawn, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'N')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Knight, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'B')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Bishop, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'R')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Rook, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'Q')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Queen, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'K')
   {
    Squares[index].Piece = new Piece(ChessPieceType.King, ChessPieceColor.White);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'p')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Pawn, ChessPieceColor.Black);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'n')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Knight, ChessPieceColor.Black);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'b')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Bishop, ChessPieceColor.Black);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'r')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Rook, ChessPieceColor.Black);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'q')
   {
    Squares[index].Piece = new Piece(ChessPieceType.Queen, ChessPieceColor.Black);
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == 'k')
   {
    Squares[index].Piece = new Piece(ChessPieceType.King, ChessPieceColor.Black);     
    Squares[index].Piece.Moved = true;
    index++;
   }
   else if (c == '/')
   {
    continue;
   }
   else if (c == ' ')
   {
    spc++;
   }
  }
  else
  {
   if (c == 'w')
   {
    WhoseMove = ChessPieceColor.White;
   }
   else if (c == 'b')
   {
    WhoseMove = ChessPieceColor.Black;
   }
   else if (c == 'K')
   {
    if (Squares[60].Piece != null)
    {
     if (Squares[60].Piece.PieceType == ChessPieceType.King)
     {
      Squares[60].Piece.Moved = false;
     }
    }

    if (Squares[63].Piece != null)
    {
     if (Squares[63].Piece.PieceType == ChessPieceType.Rook)
     {
      Squares[63].Piece.Moved = false;
     }
    }

    WhiteCastled = false;
   }
   else if (c == 'Q')
   {
    if (Squares[60].Piece != null)
    {
     if (Squares[60].Piece.PieceType == ChessPieceType.King)
     {
      Squares[60].Piece.Moved = false;
     }
    }

    if (Squares[56].Piece != null)
    {
     if (Squares[56].Piece.PieceType == ChessPieceType.Rook)
     {
      Squares[56].Piece.Moved = false;
     }
    }

    WhiteCastled = false;
   }
   else if (c == 'k')
   {
    if (Squares[4].Piece != null)
    {
     if (Squares[4].Piece.PieceType == ChessPieceType.King)
     {
      Squares[4].Piece.Moved = false;
     }
    }

    if (Squares[7].Piece != null)
    {
     if (Squares[7].Piece.PieceType == ChessPieceType.Rook)
     {
      Squares[7].Piece.Moved = false;
     }
    }

    BlackCastled = false;
   }
   else if (c == 'q')
   {
    if (Squares[4].Piece != null)
    {
     if (Squares[4].Piece.PieceType == ChessPieceType.King)
     {
      Squares[4].Piece.Moved = false;
     }
    }

    if (Squares[0].Piece != null)
    {
     if (Squares[0].Piece.PieceType == ChessPieceType.Rook)
     {
      Squares[0].Piece.Moved = false;
     }
    }

    BlackCastled = false;
   }
   else if (c == ' ')
   {
    spacers++;
   }
   else if (c == '1' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 1);
   }
   else if (c == '2' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 2);
   }
   else if (c == '3' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 3);
   }
   else if (c == '4' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 4);
   }
   else if (c == '5' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 5);
   }
   else if (c == '6' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 6);
   }
   else if (c == '7' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 7);
   }
   else if (c == '8' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 8);
   }
   else if (c == '9' && spacers == 4)
   {
    FiftyMove = (byte)((FiftyMove * 10) + 9);
   }
   else if (c == '0' && spacers == 4)
   {
    MoveCount = (byte)((MoveCount * 10) + 0);
   }
   else if (c == '1' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 1);
   }
   else if (c == '2' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 2);
   }
   else if (c == '3' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 3);
   }
   else if (c == '4' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 4);
   }
   else if (c == '5' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 5);
   }
   else if (c == '6' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 6);
   }
   else if (c == '7' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 7);
   }
   else if (c == '8' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 8);
   }
   else if (c == '9' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 9);
   }
   else if (c == '0' && spacers == 5)
   {
    MoveCount = (byte)((MoveCount * 10) + 0);
   }

  }
 }

  
}

This concludes the post on Forsyth–Edwards Notation.  If you want to get started on creating your own chess engine download my C# Chess Game Starter Kit

Move Searching Alpha Beta Part 2

by aberent 14. April 2009 05:15

Last time I discussed Min Max and the Alpha Beta algorithms.  However you might have noticed that the algorithm I showed last time does not really tell you which of the available moves is the best, but rather which was the best score out of all the available moves.  To figure out which resulting chess board is the best I have implemented another method called Alpha Beta Root.

Alpha Beta Root is very similar to the regular Alpha Beta Method with the exception of keeping track of the best board found so far.  Alpha Beta Root is also our entry method into searching; it calls the regular Alpha Beta method.  You pass it a chess board and it returns Move Content containing the best move you can make.  Alpha Beta Root does not also need to perform a Quiescence Search since it is already performed in the regular Alpha Beta method.

The code below can be divided into 3 sections.

  1. Initial examination of what legal moves I can make and what their resulting score is.  This is followed by a sort to give us the best chance of trying the best move first
  2. Initial 1 ply call of Alpha Beta to see if there is an instant check mate so we can exit.
  3. Regular Alpha Beta call.

Before we get started we will need a helper struct to keep a list of our starting positions.

internal struct ResultBoards
{      
 internal List<Board> Positions;      
}

Now onto the main Alpha Beta Root Method:

internal static MoveContent AlphaBetaRoot(Board examineBoard, byte depth)
{
 int alpha = -400000000;
 const int beta = 400000000;

 Board bestBoard = new Board(short.MinValue);

 //We are going to store our result boards here          
 ResultBoards succ = new ResultBoards
 {
  Positions = new List<Board>(30)
 };

 for (byte x = 0; x < 64; x++)
 {
  Square sqr = examineBoard.Squares[x];

  //Make sure there is a piece on the square
  if (sqr.Piece == null)
   continue;

  //Make sure the color is the same color as the one we are moving.
  if (sqr.Piece.PieceColor != examineBoard.WhoseMove)
   continue;

  //For each valid move for this piece
  foreach (byte dst in sqr.Piece.ValidMoves)
  {
   //We make copies of the board and move so that we can move it without effecting the parent board
   Board board = examineBoard.FastCopy();

   //Make move so we can examine it
   Board.MovePiece(board, x, dst, ChessPieceType.Queen);

   //We Generate Valid Moves for Board
   PieceValidMoves.GenerateValidMoves(board);

   //Invalid Move
   if (board.WhiteCheck && examineBoard.WhoseMove == ChessPieceColor.White)
   {
    continue;
   }

   //Invalid Move
   if (board.BlackCheck && examineBoard.WhoseMove == ChessPieceColor.Black)
   {
    continue;
   }

   //We calculate the board score
   Evaluation.EvaluateBoardScore(board);

   //Invert Score to support Negamax
   board.Score = SideToMoveScore(board.Score, board.WhoseMove);

   succ.Positions.Add(board);
  }
 }

 succ.Positions.Sort(Sort);

 //Can I make an instant mate?
 foreach (Board pos in succ.Positions)
 {
  int value = -AlphaBeta(pos, 1, -beta, -alpha);

  if (value >= 32767)
  {
   return pos.LastMove;
  }
 }
 depth--;

 byte plyDepthReached = ModifyDepth(depth, succ.Positions.Count);

 int currentBoard = 0;

 alpha = -400000000;

 succ.Positions.Sort(Sort);

 foreach (Board pos in succ.Positions)
 {
  currentBoard++;

  int value = -AlphaBeta(pos, plyDepthReached, -beta, -alpha);

  pos.Score = value;

  //If value is greater then alpha this is the best board
  if (value > alpha)
  {
   alpha = value;
   bestBoard = new Board(pos);
  }

 }

 return bestBoard.LastMove;
}

The obvious question might be why do we do this?  Why not simply copy the best board in the regular Alpha Beta method and return it.  The simple answer is performance.  Because the regular Alpha Beta method is recursive we want it to be as fast as possible.  It is much faster to copy integers rather than calling the copy constructor for the board object.

One last piece of code that I would like to add here is the Modify Ply method.  One thing I noticed while testing my chess engine is that during the end game my engine made moves at a much faster rate than it did during the opening and middle game.  This had a very simple explanation as during the end game there are far fewer chess pieces and there are less moves to calculate.  For this reason I added a small method to that adds 2 plies to my search if there are less then 6 root moves on the board.  This way I can search deeper during the end game, increasing my odds of finding a check mate.

private static byte ModifyDepth(byte depth, int possibleMoves)
{
 if (possibleMoves <= 15)
 {
  depth += 1;
 }

 return depth;
}

If you have any questions about this post feel free to post a comment below.  Chances are someone else has the same question and I would love a chance for improvement.

If you want to get started on creating your own chess engine download my C# Chess Game Starter Kit.   

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , , , , ,

Chess Bin Engine

Piece Square Table

by aberent 26. September 2008 03:17

Today I want to discuss the Piece Square Table

Originally the piece square tables were declared in a separate class that was used by the Evaluation function.  However I found that it is more efficient to save the extra method calls and perform the piece square table lookups directly in the evaluation function. 

Hence I have modified this post to simply describe the piece square table and the logic behind the numbers assigned to each position.

As I have already stated the piece square tables are used chess board Evaluation class to score points based on the current position of the chess piece.  The main idea behind this code is that certain positions for chess pieces are better than others.  Fox example it is better for knights to stay away from the edge of the board.  Pawns should control the center of the board and advance forward. 

I have decided not to create a piece square table for every single chess piece.  I have omitted Queens and Rooks.  I could not find good enough positional tactical advantages for Rooks and Queens to warrant the performance cost of a table lookup for each of their positions.

Here are the piece square tables used by my chess engine:

Pawns are encouraged to stay in the center and advance forward:

private static readonly short[] PawnTable = new short[]
{
     0,  0,  0,  0,  0,  0,  0,  0,
    50, 50, 50, 50, 50, 50, 50, 50,
    10, 10, 20, 30, 30, 20, 10, 10,
     5,  5, 10, 27, 27, 10,  5,  5,
     0,  0,  0, 25, 25,  0,  0,  0,
     5, -5,-10,  0,  0,-10, -5,  5,
     5, 10, 10,-25,-25, 10, 10,  5,
     0,  0,  0,  0,  0,  0,  0,  0
};

Knights are encouraged to control the center and stay away from edges to increase mobility:

private static readonly short[] KnightTable = new short[]
{
    -50,-40,-30,-30,-30,-30,-40,-50,
    -40,-20,  0,  0,  0,  0,-20,-40,
    -30,  0, 10, 15, 15, 10,  0,-30,
    -30,  5, 15, 20, 20, 15,  5,-30,
    -30,  0, 15, 20, 20, 15,  0,-30,
    -30,  5, 10, 15, 15, 10,  5,-30,
    -40,-20,  0,  5,  5,  0,-20,-40,
    -50,-40,-20,-30,-30,-20,-40,-50,
};

Bishops are also encouraged to control the center and stay away from edges and corners:

private static readonly short[] BishopTable = new short[]
{
    -20,-10,-10,-10,-10,-10,-10,-20,
    -10,  0,  0,  0,  0,  0,  0,-10,
    -10,  0,  5, 10, 10,  5,  0,-10,
    -10,  5,  5, 10, 10,  5,  5,-10,
    -10,  0, 10, 10, 10, 10,  0,-10,
    -10, 10, 10, 10, 10, 10, 10,-10,
    -10,  5,  0,  0,  0,  0,  5,-10,
    -20,-10,-40,-10,-10,-40,-10,-20,
};

Kings have 2 piece square tables, one for the end game and one for the middle game.  During the middle game kings are encouraged to stay in the corners, while in the end game kings are encouraged to move towards the center.

private static readonly short[] KingTable = new short[]
{
  -30, -40, -40, -50, -50, -40, -40, -30,
  -30, -40, -40, -50, -50, -40, -40, -30,
  -30, -40, -40, -50, -50, -40, -40, -30,
  -30, -40, -40, -50, -50, -40, -40, -30,
  -20, -30, -30, -40, -40, -30, -30, -20,
  -10, -20, -20, -20, -20, -20, -20, -10,
   20,  20,   0,   0,   0,   0,  20,  20,
   20,  30,  10,   0,   0,  10,  30,  20
};

private static readonly short[] KingTableEndGame = new short[]
{
    -50,-40,-30,-20,-20,-30,-40,-50,
    -30,-20,-10,  0,  0,-10,-20,-30,
    -30,-10, 20, 30, 30, 20,-10,-30,
    -30,-10, 30, 40, 40, 30,-10,-30,
    -30,-10, 30, 40, 40, 30,-10,-30,
    -30,-10, 20, 30, 30, 20,-10,-30,
    -30,-30,  0,  0,  0,  0,-30,-30,
    -50,-30,-30,-30,-30,-30,-30,-50
};

The above tables are used during the evaluation method to lookup the positional values to help calculate the chess board score.

Here is an example of how the above tables would be used to lookup a value for a white pawn position:

score += PawnTable[position];

And here is the code to perform the same lookup for a black pawn:

byte index = (byte)(((byte)(position + 56)) - (byte)((byte)(position / 8) * 16));

score += PawnTable[index];

If you want to download a C# Solution project that contains all of the above code plus a graphical user interface that will allow you to make valid moves on the board have a look my C# Chess Game Starter Kit.

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

Chess Bin Engine

Created and Maintained by Adam Berent
www.adamberent.com