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

Performance Reconstruction Phase Two

by aberent 3. April 2009 23:06

This is the second re-design I am doing on the ChessBin Chess Engine.  You can read all about the first one here, so you don’t make the same mistakes as me.  I guess that is what you get for re-inventing the wheel.  At least I am still having fun. 

This re-construction is related to how my chess engine stores the chess board.  Currently the chess board is described as a two dimensional array.  This way with a column and row you can locate any square on the board.  This is makes my chess engine easy to understand but slow. 

The new design will modify the chess board to be a single array of 64 squares.  This makes it necessary to refer to board positions via an index.  An index of 0 will locate the top left most square on the board and an index of 63 will locate the bottom right one.  This also allows me to drop the entire Position struct as it is no longer necessary to describe the position by two bytes. 

The new version of my ChessBin chess engine that I am currently testing is about 25% faster due to these changes.

I will be modifying each of the posts and the development kit over the next few weeks.  Stay tuned for updates.

Updated April 22nd 2009, I have finished updating all of the posts and the Chess Game Development Kit.

Chess Board Representation

by aberent 29. August 2008 03:22

Prior to Reading this post I suggest reviewing the pages explaining the Board Square and Chess Piece classes.

The chess board class is again declared as internal sealed to improve performance.

internal sealed class Board


Our chess board will contain 64 board squares represented by an array of [64] items. 

Originally I used a multidimensional array [][].  This way I can reference board position by columns and rows.  Although this made my code easier to understand, it also made move searching approximately 30%

internal Square[] Squares;


At this point I would like to explain some simple concepts related to how we represent a chess board using the above 64 item array of board squares.  Array item 0 will represent the top left most square on the board (A8).   Array item 63 will represent the bottom right most square on the board, H1.

0  1  2  3  4  5  6  7
8  9  10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63

When dealing with a single index to reference chess board positions there are certain things that one must know to make life easier.  For example how do you know that two positions are both on the same row or column?  There is an easy trick to figure that out.

Row

To figure out the row of a position you divide the position by 8 and take the integer portion of the result.  For example position 63 divided by 8 is 7.875 which equals row 7.   Position 3 divided by 8 is 0.375 so 0.  In C# by casting to an integer you will always get just the integer portion of the number, hence:

Row = (int)(position / 8)


Column

To figure out the column of a position you use the modulus operator by performing position modulus 8.  For example position 24 modulus 8 is column 0.  Position 15 modulus 8 is 7, hence

Column = position % 8


Armed with these two concepts we can convert any position on our 64 square board to a column and row.

Properties

The next property is the Board Score.  This is implemented as an internal integer.  The score works by increasing better positions for White and decreasing for better positions for Black.  Hence in our search methods Black is always trying to find boards with the lowest score and White with the highest.

internal int Score;


The next set of properties that contain information related to king checks and mates.  True if white king is in check, false if not etc.

internal bool BlackCheck;
internal bool BlackMate;
internal bool WhiteCheck;
internal bool WhiteMate;
internal bool StaleMate;


The next two variables are counters that allow us to keep track of the two tie scenarios related to the 50 move rule and the 3 move repetitions rule.  If the fifty move count reaches 50 or repeat move count reaches 3 we know that a tie has occurred.

internal byte FiftyMove;
internal byte RepeatedMove;


The two following flags are used to track if any of the two sides have castled.  This information is needed for the evaluation function to give bonus scores for castling and the move generator to allow for castling to occur if the circumstance is correct.

internal bool BlackCastled;
internal bool WhiteCastled;


The next flag tracks if the board is in the middle game or end game state.  This is determined later on by the amount of pieces remaining on the board in the Evaluation Function.  If the chess board is in an end game state certain behaviors will be modified to increase king safety and mate opportunities.

internal bool EndGamePhase;


The board will also keep track of the last move that occurred.  This is implemented as a Move Content class which we will discuss later.

internal MoveContent LastMove;


The next flags relate to the EnPassant rule, which was actually a bit of a pain to implement.  For now all we need to know is that our board will contain 2 pieces of information related to EnPassant.

1. Which side has last made a move that can cause an EnPassant (Which side moved the pawn 2 spots). 

internal ChessPieceColor EnPassantColor;


2. The Board Square of the EnPassant position, which is the position directly behind the pawn that moved 2 spots.

internal byte EnPassantPosition;


The Board will keep track of whose move it is

internal ChessPieceColor WhosMove;


As well as how many moves have occurred.

internal int MoveCount;

Constructors

The Board class with have 4 constructors as follows:

Default Constructor:

internal Board()
{
    Squares = new Square[64];

    for (byte i = 0; i < 64; i++)
    {
        Squares[i] = new Square();
    }

    LastMove = new MoveContent();
}


Copy Constructor:

internal Board(Board board)
{
    Squares = new Square[64];

    for (byte x = 0; x < 64; x++)
    {
        if (board.Squares[x].Piece != null)
        {
            Squares[x] = new Square(board.Squares[x].Piece);
        }
    }
    EndGamePhase = board.EndGamePhase;

    FiftyMove = board.FiftyMove;
    RepeatedMove = board.RepeatedMove;

    WhiteCastled = board.WhiteCastled;
    BlackCastled = board.BlackCastled;

    BlackCheck = board.BlackCheck;
    WhiteCheck = board.WhiteCheck;
    StaleMate = board.StaleMate;
    WhiteMate = board.WhiteMate;
    BlackMate = board.BlackMate;
    WhosMove = board.WhosMove;
    EnPassantPosition = board.EnPassantPosition;
    EnPassantColor = board.EnPassantColor;

    Score = board.Score;

    LastMove = new MoveContent(board.LastMove);

    MoveCount = board.MoveCount;
}


Constructor that allows to pass in the default Score.  This is useful during move searching where we can initially construct the best Board we found so far to something ridiculous like int.MinValue

internal Board(int score) : this()
{
    Score = score;
}


Constructor that will accept an array of Board Squares

private Board(Square[] squares)
{
    Squares = new Square[64];

    for (byte x = 0; x < 64; x++)
    {
        if (squares[x].Piece != null)
        {
            Squares[x].Piece = new Piece(squares[x].Piece);
        }
    }
}


As you may have noticed above the copy constructor is actually quite meaty.  There are too many fields to copy and this has a performance impact during move generation.  For this reason I created another method called Fast Copy.  The idea here is that during move generation some fields will get overwritten anyways, so I don’t really care what the previous values of these fields were.  The Fast Copy method will copy only the values that must persist from one board to another during move generation.

internal Board FastCopy()
{
    Board clonedBoard = new Board(Squares);

    clonedBoard.EndGamePhase = EndGamePhase;
    clonedBoard.WhoseMove = WhoseMove;
    clonedBoard.MoveCount = MoveCount;
    clonedBoard.FiftyMove = FiftyMove;
    clonedBoard.BlackCastled = BlackCastled;
    clonedBoard.WhiteCastled = WhiteCastled;
    return clonedBoard;
}


Board Movement

The following listings are a set of methods that will help us with chess piece movement on our board.  Before we can actually write the main movement method, we need to handle all of the special scenarios such as pawn promotion, en passant and castling.  These helper methods basically have a set of hard coded positions and some logic that states, if I am in this position and this piece type, do something different.  Else the move will be handled by the main move method.

Pawn Promotion

The Promote Pawns method will check for the destination position of the pawn and promote it to a Queen Piece.  Most Chess programs allow the user to choose the piece they promote the pawn too; however in most cases I don’t see why you would not choose a queen anyways.  Furthermore choosing the queen always simplifies the implementation for now.

private static bool PromotePawns(Board board, Piece piece, byte dstPosition,
                  ChessPieceType promoteToPiece)
{
    if (piece.PieceType == ChessPieceType.Pawn)
    {
        if (dstPosition < 8)
        {
            board.Squares[dstPosition].Piece.PieceType = promoteToPiece;
            return true;
        }
        if (dstPosition > 55)
        {
            board.Squares[dstPosition].Piece.PieceType = promoteToPiece;
            return true;
        }
    }

    return false;
}

En Passant 

The Record En Passant method sets the En Passant flag if the piece currently moving is a pawn that moves 2 squares.

private static void RecordEnPassant(ChessPieceColor pcColor, ChessPieceType pcType,
        Board board, byte srcPosition, byte dstPosition)
{
    //Record En Passant if Pawn Moving
    if (pcType == ChessPieceType.Pawn)
    {
        //Reset FiftyMoveCount if pawn moved
        board.FiftyMove = 0;

        int difference = srcPosition - dstPosition;

        if (difference == 16 || difference == -16)
        {
            board.EnPassantPosition = (byte)(dstPosition + (difference / 2));
            board.EnPassantColor = pcColor;
        }
    }
}

Set En Passant Move Method will move the En Passant piece and kill the advanced pawn based on the En Passant flags of the board and the destination move requested.

private static bool SetEnpassantMove(Board board, byte dstPosition,
                    ChessPieceColor pcColor)
{
    //En Passant
    if (board.EnPassantPosition == dstPosition)
    {
        //We have an En Passant Possible
        if (pcColor != board.EnPassantColor)
        {
            int pieceLocationOffset = 8;

            if (board.EnPassantColor == ChessPieceColor.White)
            {
                pieceLocationOffset = -8;
            }

            dstPosition = (byte)(dstPosition + pieceLocationOffset);

            Square sqr = board.Squares[dstPosition];

            board.LastMove.TakenPiece =
                new PieceTaken(sqr.Piece.PieceColor, sqr.Piece.PieceType,
                        sqr.Piece.Moved, dstPosition);

            board.Squares[dstPosition].Piece = null;
           
            //Reset FiftyMoveCount if capture
            board.FiftyMove = 0;

            return true;
        }
    }

    return false;
}

Castling 

The next Method will move the Rook to its correct position if castling is requested.

private static void KingCastle(Board board, Piece piece,
         byte srcPosition, byte dstPosition)
{
    if (piece.PieceType != ChessPieceType.King)
    {
        return;
    }

    //Lets see if this is a casteling move.
    if (piece.PieceColor == ChessPieceColor.White &&
           srcPosition == 60)
    {
        //Castle Right
        if (dstPosition == 62)
        {
            //Ok we are casteling we need to move the Rook
            if (board.Squares[63].Piece != null)
            {
                board.Squares[61].Piece = board.Squares[63].Piece;
                board.Squares[63].Piece = null;
                board.WhiteCastled = true;
                board.LastMove.MovingPieceSecondary =
                 new PieceMoving(board.Squares[61].Piece.PieceColor,
                     board.Squares[61].Piece.PieceType,
                          board.Squares[61].Piece.Moved, 63, 61);
                board.Squares[61].Piece.Moved = true;
                return;
            }
        }
        //Castle Left
        else if (dstPosition == 58)
        {  
            //Ok we are casteling we need to move the Rook
            if (board.Squares[56].Piece != null)
            {
                board.Squares[59].Piece = board.Squares[56].Piece;
                board.Squares[56].Piece = null;
                board.WhiteCastled = true;
                board.LastMove.MovingPieceSecondary =
                     new PieceMoving(board.Squares[59].Piece.PieceColor,
                            board.Squares[59].Piece.PieceType,
                                 board.Squares[59].Piece.Moved, 56, 59);
                board.Squares[59].Piece.Moved = true;
                return;
            }
        }
    }
    else if (piece.PieceColor == ChessPieceColor.Black &&
           srcPosition == 4)
    {
        if (dstPosition == 6)
        {
            //Ok we are casteling we need to move the Rook
            if (board.Squares[7].Piece != null)
            {
                board.Squares[5].Piece = board.Squares[7].Piece;
                board.Squares[7].Piece = null;
                board.BlackCastled = true;
                board.LastMove.MovingPieceSecondary =
                    new PieceMoving(board.Squares[5].Piece.PieceColor,
                             board.Squares[5].Piece.PieceType,
                                  board.Squares[5].Piece.Moved, 7, 5);
                board.Squares[5].Piece.Moved = true;
                return;
            }
        }
            //Castle Left
        else if (dstPosition == 2)
        {
            //Ok we are casteling we need to move the Rook
            if (board.Squares[0].Piece != null)
            {
                board.Squares[3].Piece = board.Squares[0].Piece;
                board.Squares[0].Piece = null;
                board.BlackCastled = true;
                board.LastMove.MovingPieceSecondary = 
                   new PieceMoving(board.Squares[3].Piece.PieceColor,
                            board.Squares[3].Piece.PieceType,
                                 board.Squares[3].Piece.Moved, 0, 3);
                board.Squares[3].Piece.Moved = true;
                return;
            }
        }
    }

    return;
}

This is the actual Move Method, where each piece is moved, captured.  The logic here basically boils down to, recording the move, and assigning the moving piece to the new square, while clearing the old one.  This method also calls the helper movement methods we have just listed above to handle the more complex scenarios such as castling, pawn promotion and En Passant.

internal static MoveContent MovePiece(Board board, byte srcPosition,
                    byte dstPosition,
                    ChessPieceType promoteToPiece)
{
    Piece piece = board.Squares[srcPosition].Piece;

    //Record my last move
    board.LastMove = new MoveContent();

    //Add One to FiftyMoveCount to check for tie.
    board.FiftyMove++;

    if (piece.PieceColor == ChessPieceColor.Black)
    {
        board.MoveCount++;
    }

    //En Passant
    if (board.EnPassantPosition > 0)
    {
        board.LastMove.EnPassantOccured =
              SetEnpassantMove(board, dstPosition, piece.PieceColor);
    }

    if (!board.LastMove.EnPassantOccured)
    {
        Square sqr = board.Squares[dstPosition];

        if (sqr.Piece != null)
        {
            board.LastMove.TakenPiece =
                  new PieceTaken(sqr.Piece.PieceColor, sqr.Piece.PieceType,
                                       sqr.Piece.Moved, dstPosition);
            board.FiftyMove = 0;
        }
        else
        {
            board.LastMove.TakenPiece =
                  new PieceTaken(ChessPieceColor.White, ChessPieceType.None,
                          false, dstPosition);
           
        }
    }

    board.LastMove.MovingPiecePrimary =
              new PieceMoving(piece.PieceColor, piece.PieceType,
                      piece.Moved, srcPosition, dstPosition);

    //Delete the piece in its source position
    board.Squares[srcPosition].Piece = null;

    //Add the piece to its new position
    piece.Moved = true;
    piece.Selected = false;
    board.Squares[dstPosition].Piece = piece;

    //Reset EnPassantPosition
    board.EnPassantPosition = 0;
 
    //Record En Passant if Pawn Moving
    if (piece.PieceType == ChessPieceType.Pawn)
    {
       board.FiftyMove = 0;
       RecordEnPassant(piece.PieceColor, piece.PieceType,
                board, srcPosition, dstPosition);
    }

    board.WhoseMove = board.WhoseMove == ChessPieceColor.White
              ? ChessPieceColor.Black
              : ChessPieceColor.White;

    KingCastle(board, piece, srcPosition, dstPosition);

    //Promote Pawns
    if (PromotePawns(board, piece, dstPosition, promoteToPiece))
    {
        board.LastMove.PawnPromoted = true;
    }
    else
    {
        board.LastMove.PawnPromoted = false;
    }

    if ( board.FiftyMove >= 50)
    {
        board.StaleMate = true;
    }

    return board.LastMove;
}

 

If you compile this listing along with the Chess Piece, Move Content and Board Square classes you should have all the necessary code for declaring and moving pieces around the board.  Of course you still don't have a graphical chess board or the move generator.

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

Currently rated 5.0 by 2 people

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

Tags: , , , ,

Chess Bin Engine

Chess Board Square

by aberent 27. August 2008 07:47

In this post I will discuss the chess board square representation.  Before we can discuss the chess board we need to model how each of the chess board squares will be represented on our board.

The chess board square will be declared as an internal struct.  I have found that small structs seem to perform better then small classes.  Also making objects internal or even better private, tends to increase performance.

internal struct Square


Each chess board square can contain a chess piece.

internal Piece Piece;


Each Board Square will also have the following copy constructor that will copy the chess piece from the copied chess board square or set the chess piece to null, signifying that the current square is empty.

internal Square(Piece piece)
{
    Piece = new Piece(piece);
}


That's it for this post, next time I will discuss Chess Board Representation.

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

Currently rated 4.7 by 6 people

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

Tags: , ,

Chess Bin Engine

Created and Maintained by Adam Berent
www.adamberent.com