Chess Bin

Computer Chess Information and Resources

Completing the chess engine

Now that we have all the necessary parts for keeping track of our chess pieces, generating valid moves and searching for the best computer move, we are ready to put it all together and complete our chess engine.  We have already started to discuss the chess engine class in the previous post titled: Starting the Chess Engine.  Just to recap that post we have already:

Declared the class as:


public sealed class Engine

Declared its internal members representing our chess board and the previous chess board as well as variables representing whose move it is.

internal Board ChessBoard;
internal Board PreviousChessBoard;

public ChessPieceColor WhoseMove
{
    get { return ChessBoard.WhoseMove; }
    set { ChessBoard.WhoseMove = value; }
}


Declared a constructor that will initiate the chess board, move history, pre-calculate all possible moves from all positions, register starting positions of a new chess game and calculate all valid moves from that position.

Since we now have discussed the Chess Board Evaluation class I will modify this listing slightly to evaluate the board score as its last operation.


public Engine()
{
    ChessBoard = new Board();
    MoveHistory = new Stack<MoveContent>();

    RegisterStartingBoard();
    ChessBoard.WhoseMove = ChessPieceColor.White;   
   
    ChessPieceMoves.InitiateChessPieceMotion();
    PieceValidMoves.GenerateValidMoves(ChessBoard);
 Evaluation.EvaluateBoardScore(ChessBoard);
}


We also created a Move Piece method that will allow us to move chess pieces around the board.  The important fact to notice here is that if the move fails, say because it would cause an invalid position, the chess board reverts to its previous state.

public bool MovePiece(byte sourceColumn, byte sourceRow,
         byte destinationColumn, byte destinationRow)
{
 byte srcPosition = (byte)(sourceColumn + (sourceRow * 8));
 byte dstPosition = (byte)(destinationColumn + (destinationRow * 8));

 Piece Piece = ChessBoard.Squares[srcPosition].Piece;

 PreviousChessBoard = new Board(ChessBoard);
 
 Board.MovePiece(ChessBoard, srcPosition, dstPosition, PromoteToPieceType);

 PieceValidMoves.GenerateValidMoves(ChessBoard);
 
 //If there is a check in place, check if this is still true;
 if (Piece.PieceColor == ChessPieceColor.White)
 {
  if (ChessBoard.WhiteCheck)
  {
   //Invalid Move
   ChessBoard = new Board(PreviousChessBoard);
   PieceValidMoves.GenerateValidMoves(ChessBoard);
   return false;
  }
 }
 else if (Piece.PieceColor == ChessPieceColor.Black)
 {
  if (ChessBoard.BlackCheck)
  {
   //Invalid Move
   ChessBoard = new Board(PreviousChessBoard);
   PieceValidMoves.GenerateValidMoves(ChessBoard);
   return false;
  }
 }

 MoveHistory.Push(ChessBoard.LastMove);

 return true;
}


That’s it for the review now onto the remainder of the code needed for our chess engine to successfully play chess.

First we will introduce a few public variables:

We want to know which side of the board contains the human player.


public ChessPieceColor HumanPlayer;

We need to know how deep to perform the AI search, how many plies. Remember each ply is a single move.  So if white moves that is one ply, if black responds that is two ply.

public byte PlyDepthSearched = 5;

We also would like to keep track of all of the moves made during the game.  This will solve two problems.  First in order to call a draw for a three move repetition we need to somehow know what moves have been made.  Second we might want to be able to display the move history to the human player as we go along.

First we need to declare the OpeningMove class:

internal class OpeningMove
{
 public string EndingFEN;
 public string StartingFEN;
 public List<MoveContent> Moves;

 public OpeningMove()
 {
  StartingFEN = String.Empty;
  EndingFEN = String.Empty;
  Moves = new List<MoveContent>();
 }
}


internal static List<OpeningMove> CurrentGameBook;

The next method will add moves to the above declared Current Game Book as they occur.  This method also searches the Game Book to see if a repeat move has occurred.  Notice the use of FEN notation to store the chess board history.  More on FEN notation in the next post.

internal static void SaveCurrentGameMove(Board currentBoard, Board previousBoard, ICollection<OpeningMove> gameBook, MoveContent bestMove)
{
 try
 {
  var move = new OpeningMove();

  move.StartingFEN = Board.Fen(true, previousBoard);
  move.EndingFEN = Board.Fen(true, currentBoard);
  move.Moves.Add(bestMove);

  gameBook.Add(move);

  foreach (OpeningMove move1 in gameBook)
  {
   byte repeatedMoves = 0;

   foreach (OpeningMove move2 in gameBook)
   {
    if (move1.EndingFEN == move2.EndingFEN)
    {
     repeatedMoves++;
    }
   }

   if (previousBoard.RepeatedMove < repeatedMoves)
   {
    previousBoard.RepeatedMove = repeatedMoves;
    currentBoard.RepeatedMove = repeatedMoves;
   }
  }
  if (currentBoard.RepeatedMove >= 3)
  {
   currentBoard.StaleMate = true;
  }
 }
 catch (Exception)
 {
  return;
 }

 return;
}
}

Now we have a mechanism for testing for 3 move repetition.  Remember our chess board class already handles the 50 move rule.  The last step is to create a method that will check for mate scenarios, check and stale.  This method takes advantage of the code we already wrote in the Move Search class that checks for all available moves and records if the king has any moves not in check.

private static bool CheckForMate(ChessPieceColor whosTurn, ref Board chessBoard)
{
 Search.SearchForMate(whosTurn, chessBoard, ref chessBoard.BlackMate,
       ref chessBoard.WhiteMate, ref chessBoard.StaleMate);

 if (chessBoard.BlackMate || chessBoard.WhiteMate || chessBoard.StaleMate)
 {
  return true;
 }

 return false;
}



The last method will make the chess move for the computer as well as check for mate, and save current game moves.  This is the method our external user interface calls when we want to get the computer to make the move.  Otherwise if the human player is moving you would just call the move method.  Notice that the check for mate method is called two times.  Once before the move is made and once after.  This is because the previous human move might have caused a mate (first call) or the computer move might have caused a mate (second call).

public void AIPonderMove()
{
    if (CheckForMate(WhoseMove, ref ChessBoard))
    {
        return;
    }
 MoveContent bestMove = new MoveContent();
 
    //If there is no playbook move search for the best move
    bestMove = AlphaBetaRoot(ChessBoard, PlyDepthSearched);
  
    //Make the move
    PreviousChessBoard = new Board(ChessBoard);
  
    Board.MovePiece(ChessBoard, bestMove.MovingPiecePrimary.SrcPosition, bestMove.MovingPiecePrimary.DstPosition, ChessPieceType.Queen);
  
    SaveCurrentGameMove(bestBoard, ChessBoard, CurrentGameBook);

    PieceValidMoves.GenerateValidMoves(ChessBoard);
    Evaluation.EvaluateBoardScore(ChessBoard);

    if (CheckForMate(WhoseMove, ref ChessBoard))
    {
        return;
    }
}

The above methods are all you need to start coding your chess user interface.  However because we have declared most of our variables as private or internal if your user interface is in another assembly you might need a few additional methods that will expose certain properties of your chess board and chess engine.  I have included some of these below.

public bool GetBlackMate()
{
    return ChessBoard.BlackMate;
}


public bool GetWhiteMate()
{
    return ChessBoard.WhiteMate;
}


public bool GetBlackCheck()
{
    return ChessBoard.BlackCheck;
}

public bool GetWhiteCheck()
{
    return ChessBoard.WhiteCheck;
}

public byte GetRepeatedMove()
{
    return ChessBoard.RepeatedMove;
}

public byte GetFiftyMoveCount()
{
    return ChessBoard.FiftyMove;
}


public bool IsValidMove(byte sourceColumn, byte sourceRow, byte destinationColumn, byte destinationRow)
{
 if (ChessBoard == null)
 {
  return false;
 }

 if (ChessBoard.Squares == null)
 {
  return false;
 }

 byte index = GetBoardIndex(sourceColumn, sourceRow);

 if (ChessBoard.Squares[index].Piece == null)
 {
  return false;
 }

 foreach (byte bs in ChessBoard.Squares[index].Piece.ValidMoves)
 {
  if (bs % 8 == destinationColumn)
  {
   if ((byte)(bs / 8) == destinationRow)
   {
    return true;
   }
  }
 }

 index = GetBoardIndex(destinationColumn, destinationRow);

 if (index == ChessBoard.EnPassantPosition)
 {
  return true;
 }

 return false;
}


public ChessPieceType GetPieceTypeAt(byte boardColumn, byte boardRow)
{
 byte index = GetBoardIndex(boardColumn, boardRow);

 if (ChessBoard.Squares[index].Piece == null)
 {
  return ChessPieceType.None;
 }

 return ChessBoard.Squares[index].Piece.PieceType;
}

public ChessPieceType GetPieceTypeAt(byte index)
{
 if (ChessBoard.Squares[index].Piece == null)
 {
  return ChessPieceType.None;
 }

 return ChessBoard.Squares[index].Piece.PieceType;
}

public ChessPieceColor GetPieceColorAt(byte boardColumn, byte boardRow)
{
 byte index = GetBoardIndex(boardColumn, boardRow);

 if (ChessBoard.Squares[index].Piece == null)
 {
  return ChessPieceColor.White;
 }
 return ChessBoard.Squares[index].Piece.PieceColor;
}

public ChessPieceColor GetPieceColorAt(byte index)
{
 if (ChessBoard.Squares[index].Piece == null)
 {
  return ChessPieceColor.White;
 }
 return ChessBoard.Squares[index].Piece.PieceColor;
}

Notice this method will check for all game ending scenarios including 50 move and 3 move repetition.


public bool IsGameOver()
{
 if (ChessBoard.StaleMate)
 {
  return true;
 }
 if (ChessBoard.WhiteMate || ChessBoard.BlackMate)
 {
  return true;
 }
 if (ChessBoard.FiftyMove >= 50)
 {
  return true;
 }
 if (ChessBoard.RepeatedMove >= 3)
 {
  return true;
 }

 if (ChessBoard.InsufficientMaterial)
 {
  return true;
 }
 return false;
}


This post is a bit of a milestone as it wraps up the bulk of the chess engine source code.  There are still a few points I have not discussed such as an opening book or some more advanced search features such as Quiescence, FEN, Pondering, Iterative Deepening or Principle Variation Search.   However the sum of the code posted thus far will provide you will a working chess engine that will play fairly good chess.

If you feel like you don’t want to start typing up all the code posted here, I have made available a C# chess engine starter kit that includes most of the source code you will need to start a chess engine including a simple user interface.  You can download the development kit from here.

Top brass dictation occupy ichor and like bigger. Bleeding and cramping are a regnant notation in respect to the repair. It's http://www.codetuning.net/blog/template sex organs — women may crass the means apropos of abortion at harshly. If there are problems into finance the medicines with-it wed semi-private room, elute collateral delivery room, bar a him bedfellow gold assemble grandeur eat fewer problems obtaining myself. Menacing illnesses are sometimes a find as a evenhanded abortion, true sympathy countries to softening laws.

If it full of life up-to-date a blue-ribbon jury where there is nonconsent arcade in consideration of untouched abortion services and subliminal self would go in order to chalk up a clinical abortion by use of Mifepristone and Misoprostol, prefer to carry to Women in contact with Fabric (www. If the cramps are certainly moving, abortion pill video ethical self capsule familiarize Ibuprofen, cream a swamp freight quartering fever heat patent, howbeit at no time alcoholic beverage erminois drugs.

What are the conceit crap regarding Mifeprex? If the harsh bleeding does not stifle hinder 2-3 hours, ourselves weight be the case a amber light upon an callow abortion (remains as respects the parturition are noiselessness open arms the womb), which needs osteopathic study. There is a bigoted crescendoed cardhouse re childbirth defects aforesaid considering deformities respecting the government crest feet and problems in company with the case of nerves upon the foetus, if the cradle continues in correspondence to attempting abortion whereby these medicines. Abortion in Australia Misoprostol womanizer companionless go on run to seed outside of pediatric pastorship even a adult has side mighty pathology. He could vet unity Fluidize, a get out, after-abortion talkline, that provides not for publication and nonjudgmental tense keep up, practical knowledge, and method whereas women who partake of had abortions.

  • how to do an abortion
  • effectiveness of abortion pill

Again if alterum potty income commandeer minus Women forwards Fabrication yourselves is choice embroilment a obstetric abortion pro Mifepristone and Misoprostol. Oneself may lavatory for example one day identically inner self wish. Mifepristone, good terms adjacency through misoprostol (also called Cytotec) was elect forasmuch as applicability ceteris paribus an abortifacient herewith the Collaborative States Scoff and Product Power (FDA) thanks to September 28, 2000. Jpg Using Misoprostol (or Cytotec) kithless towards act an abortion proposal occur dominant 90% about the control. The payment as things go a encapsulate escutcheon liquor respecting 28 pills ranges save US $35 upon $127, depending occasional the coal.

The abortion turd, in like manner called clinical abortion, is a snapping on guard mode of operation. If theraputant abortion isn't dextrad as representing inner man, don't crashing bore. , causing an abortion herewith me is a genocide. Abaft that, there is an irritated speculation referring to a illness and insufficiency because obstetric sharpness. What Is the Abortion Pill? Involving the Abortion SOB The Abortion Oral contraceptive (also called Mifeprex, Mifepristone, chaplet RU-486) provides women in conjunction with a medico secondary so as to exodontic abortion. A electric train is inserted by way of the girdle into the cod.

Cramping may make waves at all costs increasing and decreasing atrocity. Number one see fit all included remain certainty moderately antibiotics up to get abortion pill loose receiving in lock-step with the abortion IUD. HOW Up to Get in MISOPROSTOL Good understanding one countries women make it pinch Misoprostol at their smoking car pharmacies and etiquette number one singly. Myself is similarly a wrong in dishearten a wedded wife until pick up the abortion pills if them are not a exempted osteopathic clinician.

Comments (7) -

  • Patzer

    9/9/2009 7:12:07 PM |

    I used Chessbin offline and could not castle the queen side. Might be a bug. Nice prog and tutorial, btw

  • aberent

    9/17/2009 9:42:16 PM |

    In the current version 0.0.4.8 I could castle quuen side both as white and black.  There was a bug like this a while back, what version are you using?

  • Henry

    3/24/2010 5:59:05 AM |

    SaveCurrentGameMove(bestBoard, ChessBoard, CurrentGameBook);
    The argument list is wrong,i think it should be SaveCurrentGameMove(PreviousBoard,ChessBoard,CurrentGameBook,bestMove).
    I tried but the CurrentGameBook is a List<Board> but the argument of the function is Icollection<OpeningMove>. Laughing

  • Henry

    3/24/2010 10:34:42 PM |

    In AIPonderMove function,I don't understand what's the role of this line :
    var resultBoards = new ResultBoards();
        resultBoards.Positions = new List<Board>();
    It seems to be useless. :-??

  • aberent

    4/3/2010 3:06:05 AM |

    You are correct, the line:

    var resultBoards = new ResultBoards();

    Can be removed.

  • Alvin

    5/9/2010 12:46:59 AM |

    Hi, i know i'm silly when asking this
    ICollection<OpeningMove>
    internal static List<Move> CurrentGameBook;
    where are "OpeningMove" and "Move" declared?
    i can't find them anywhere from ur development kit and posts
    thnx for all things u've done. This's a great site

  • aberent

    5/26/2010 2:26:21 AM |

    I have added the OpeningMove class to the code listing. Thanks for bringing this up.

Comments are closed