The Common Header
The abc.h file is the common language of ABC. It contains the definitions, constants, data structures, global variables, and function declarations that are shared by the different parts of the engine.
Almost every source file in ABC includes this header. Instead of defining the same information separately in every file, we define it once in abc.h and make it available wherever it is needed.
Protecting the Header
The first thing in the file is an include guard:
#ifndef ARRAY_BASED_CHESS
#define ARRAY_BASED_CHESS
...
#endif
An include guard prevents the contents of the header from being processed more than once during compilation. Since different source files can include other headers as well, the same header could otherwise be included multiple times and cause duplicate definitions.
The first line checks whether ARRAY_BASED_CHESS has already been defined. If it has not, the macro is defined and the contents of the header are processed. A later inclusion sees that the macro already exists and skips the entire header.
Library Includes
ABC uses several standard C and operating-system libraries. The first group contains commonly used headers such as stdio.h, unistd.h, and string.h.
The operating-system-specific section is controlled by the WIN64 macro:
#ifdef WIN64
#include "windows.h"
#else
#include "sys/time.h"
#include "sys/select.h"
#include "string.h"
#endif
This allows the same source code to handle differences between Windows and Unix-like systems. When WIN64 is defined, the Windows-specific header is included. Otherwise, the Unix-like system headers are used.
The Starting Position
The standard chess starting position is stored as a FEN string:
#define START_POSITION "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "
Using a constant for this position means that the initial board can be referred to consistently throughout the engine without repeating the entire FEN string.
Position and Move Lists
Two important structures are defined in the header. The first is Position, which stores a snapshot of the current board state.
typedef struct {
int board[128];
int king_square[2];
int side;
int enpassant;
int castle;
} Position;
The board itself uses 128 elements because ABC uses the 0x88 board representation. The structure also stores the locations of both kings, the side to move, the en passant square, and the current castling rights.
This structure is particularly useful when making a move. A position can be saved before a move and restored afterwards, allowing the search to explore one variation and then return to the previous position.
The second structure represents a list of generated moves:
typedef struct {
int moves[256];
int count;
} Movelist;
The array stores the encoded moves, while count tells us how many moves are currently in the list. A single Movelist can therefore be passed between move generation, move ordering, and search functions.
Squares, Sides, and Pieces
ABC uses enums to give meaningful names to values that would otherwise be simple integers. The square enum maps chessboard coordinates onto the 0x88 board:
enum squares {
A8 = 0, B8, C8, D8, E8, F8, G8, H8,
A7 = 16, B7, C7, D7, E7, F7, G7, H7,
A6 = 32, B6, C6, D6, E6, F6, G6, H6,
...
A1 = 112, B1, C1, D1, E1, F1, G1, H1
};
Instead of writing numbers such as 112 when referring to the white king's starting square, the engine can simply use E1. This makes the code much easier to read.
Other enums define the sides, piece types, actual pieces, castling rights, move-generation modes, and game phases:
enum sides { WHITE, BLACK };
enum types { NONE = -1, EMPTY, KING, PAWN, KNIGHT, BISHOP, ROOK, QUEEN };
enum pieces { WK = 1, WP, WN, WB, WR, WQ, BK = 9, BP, BN, BB, BR, BQ };
enum castling { WKC = 1, WQC = 2, BKC = 4, BQC = 8 };
enum capture_flags { ALL_MOVES, ONLY_CAPTURES };
enum game_phase { OPENING, ENDGAME, MIDDLEGAME };
These values become the vocabulary used throughout the engine. A function can work with WHITE, BLACK, KNIGHT, or WKC instead of unexplained numeric constants.
Global Variables
The next section contains a long list of extern declarations. These are the global variables defined in defs.c.
extern int board[128];
extern int king_square[2];
extern int side;
extern int enpassant;
extern int castle;
The keyword extern tells the compiler that these variables exist somewhere else. The header does not create another copy of them. Their actual definitions and storage are provided by defs.c.
This gives every source file access to the same engine state. Move generation can access the board, search can access the current side, the UCI code can access the time-control variables, and evaluation can access the scoring tables.
Some of these globals describe the chess position, while others belong to the search itself. There are arrays for move ordering, killer moves, history heuristics, the principal variation, repetition detection, piece-square tables, and many other parts of the engine.
There are also variables used by the UCI interface and time management, such as movetime, starttime, stoptime, timeset, and stopped.
Function Declarations
The final sections of abc.h declare the functions implemented by the different source files. The declarations are grouped according to where their implementations live.
For example, io.c provides functions for loading and displaying positions:
extern void set_board(char *fen);
extern void print_board();
extern void print_move(int source, int target, int promoted);
movegen.c contains the functions responsible for encoding moves, generating legal moves, detecting attacks, making moves, and saving or restoring positions.
perft.c contains the perft functions used to test move generation. hash.c contains the random-number and position-hashing functions. search.c contains evaluation, move ordering, quiescence search, negamax, and the main search function.
The UCI interface lives in uci.c, while misc.c contains utility functions such as time measurement, input handling, and communication with the GUI.
NOTE: Since not all the functions are used globally there is no need to declare those extern, however they have been declared just for you to see all the functions available
The Header as the Engine's Interface
With all of these declarations in one place, abc.h acts as the interface between the different components of ABC. A source file does not need to know how another component is implemented. It only needs to know which functions and data structures are available.
This is one of the main reasons the engine can be divided into separate source files without becoming difficult to connect together. The implementation stays in the .c files, while the shared definitions and declarations stay in abc.h.
As the engine becomes more complicated, this separation becomes increasingly valuable. The search code can call generate_moves() without knowing how move generation works internally. The UCI code can call search_position() without knowing how the search algorithm is implemented.
The header therefore provides a simple contract between the different parts of ABC: these are the types, constants, variables, and functions that make up the engine's shared interface.
It is not the most sophisticated architecture possible, and that is intentional. ABC is designed to keep the connection between the concepts of a chess engine and their implementation in C as visible as possible.