Skip to content

Chess Engine Programming: Developing an Alpha Beta Chess Engine

Shaheryar Sohail edited this page Aug 16, 2022 · 2 revisions

Before we begin...

It is crucial to recognize three things:

  • Code written for chess engines needs to be extremely fast. The choice of language one uses for their engine does matter. While you may be able to follow along with this Wiki, you may not be able to get the same performance as others (and thus make your engine weaker).
  • StockNemo isn't perfect in any regard. The project was started so that I could learn stuff myself. This Wiki serves as a space where I can share this information with others who may find the following optimizations and insight beneficial. This information may be incorrect and up to debate from time to time. Furthermore, while the intention is to provide language-agnostic readable code, it does assume you have a general knowledge of low-level languages.
  • The algorithms mentioned here may or may not be the latest ones in StockNemo. While the intention is to keep the Wiki as up-to-date as possible with the findings from StockNemo's development, there is no implied or explicitly stated guarantee.

Representing the Board

There are numerous ways to represent the board. Some prefer using a double array of Pieces (Piece[8][8]). Some prefer joining that into one array (Piece[64]). Some even prefer high-level data structures like Lists, HashMaps, or Dictionaries (Dictionary<Square, Piece>(64)).

However, the most performant way is by using BitBoards. The name might sound confusing to beginners, but it isn't complicated. A BitBoard is another name for uint64: an unsigned 64-bit integer. Many languages, including C#, specify this type as: ulong.

Java and potentially some other languages lack unsigned 64-bit integer support, so careful use of signed 64-bit integer will work just as well.

In StockNemo, to make coding and development easier (and a bit more high-level), a struct is wrapped around the unsigned 64-bit integer.

struct BitBoard
{

    // The uint64 (or BitBoard) this struct is wrapping over and providing API methods.
    ulong Internal;

    // This serves as a struct constructor. In many languages, this isn't necessary. In C#, it is.
    BitBoard(ulong from)
    {
        Internal = from;
    }

    // This is a language feature of C#. Other languages may or may not have it. It's called an INDEXER.
    // The idea behind it is that it allows one to do the following:
    // bool x = BitBoard[0];
    // BitBoard[0] = true;
    // Essentially, providing two methods in one and an array-like syntax. In other languages, it may be necessary to do the methods separately. 
    bool this[int i]
    {
        // The method corresponding to the syntax:
        // bool x = BitBoard[0];
        // Essentially: IsBitSet(int i)
        // Checks whether a bit at that specific i (0 <= i <= 63) is set.
        get
        {
            return (bool)(byte)(Internal >> i & 1UL);
        }

        // The method corresponding to the syntax:
        // BitBoard[0] = true;
        // Essentially: SetBitTo(int i, bool set)
        // Sets or unsets a bit at that specific i (0 <= i <= 63).
        // In C# and StockNemo's code, the name for the set variable is "value"; however, "set" is used to avoid confusion.
        set
        {
            if (set) Internal |= 1UL << i;
            else Internal &= ~(1UL << i);
        }
    }

}
Clone this wiki locally