Raúl Benencia


Chess and C, day 1

I’ve been programming in Haskell as my main language for almost a year now. Among other things, I love the concept of purity and expressiveness it provides. In fact, I’ve gotten so used to the functional paradigm that I’m having problems when writing code in other languages, as C, which kind of sucks because I’m a teaching assistant of a subject where we use that language.

In order to remove the dust from my C skills I’ve decided to write a small chess game. Nothing fancy, just a program with a small interface to receive user movements and maybe a PGN re-player. As I’m thinking about portability, I’ll avoid the use of non-portable libraries.

As good ol’ Haskell teach us, let’s start by defining some types. We’ll start with the very basics, the pieces. I can’t help thinking about algebraic data types when coding this :-).

typedef enum {WHITE, BLACK} Color;
typedef enum {PAWN, ROCK, KNIGHT, BISHOP, QUEEN, KING} PieceType;

And then a struct to contain these enums.

typedef struct {
    Color color;
    PieceType type;
} Piece;

A Piece will be placed in square, so let’s also define it a type. We can reuse our Color type.

typedef struct {
    Color color;
    Piece* piece;
} Square;

When a Square is empty, it’s piece field will be NULL. I have to admit that when I designed the type I really missed the functional approach of a Maybe data type because it would easily allow me to express an empty square by using Nothing.

Last but no least, we’ll need a type for containing our sixty-four squares. For the moment let’s use this simple type synonym.

typedef Square** Board;

All right, now that we have defined the types, let’s start coding some logic. We’ll start by initializing a Board with its squares and piece positions.

I’ve defined the function Board board_init() which will allocate memory for the board and then call the function Board _initial_setup(Board).

Board _setup_pieces(Board b) {
    return _pawns(_rocks(_knights(_bishops(_queens(_kings(b)))))); // :-)
}

Board _initial_setup(Board b) {
    return _setup_pieces(_setup_colors(b));
}

As you may have guessed, when coding _setup_pieces I used the functional approach of function composition. The smalls functions that set up the pieces just malloc memory for a Piece and set it up in its initial position. For example, here is the function that initialize the pawns.

Board _pawns(Board b) {
    short white_pawns_row = 1, black_pawns_row = 6, i;

    for (i = 0; i < SIZE; i++)
        b[white_pawns_row][i].piece = new_piece(WHITE, PAWN);

    for (i = 0; i < SIZE; i++)
        b[black_pawns_row][i].piece = new_piece(BLACK, PAWN);

    return b;
}

I’m not happy with directly using the matrix indices. I’ll probably make an API for using chess coordinates.

Aside from initializing the board I’m also interested in watching it appear on the screen, so I’ve coded a print_board(Board) function that loops trough the board and calls print_square(Square) which, if the square is not empty, will call print_piece(Piece). This last function will call int piece_character(Piece) to get the piece representation of our choice. I would like to implement something like:

int piece_character(Piece p) {
    switch (p.color) {

    case WHITE:
        switch (p.type) {
        case PAWN:   return '♙';
        case ROCK:   return '♖';

… but I’ve yet to understand how to use UTF-8 characters in a portable way. For the moment I will stay with the following implementation:

    switch (p.type) {

    case PAWN:   res =  'p'; break;
    case ROCK:   res =  'r'; break;
    case KNIGHT: res =  'n'; break;
    case BISHOP: res =  'b'; break;
    case QUEEN:  res =  'q'; break;
    case KING:   res =  'k'; break;
    }

    if (p.color == BLACK)
        return toupper(res);
    
    return res;

Finally, here is the small main() I’ve implemented:

int main() {
    Board b = board_init();
    print_board(b);
    board_delete(b);

    return 0;
}

And here is how the board will be printed on the screen:

➜  chess git:(master) ./main 
+---|---|---|---|---|---|---|---+
| r | n | b | k | q | b | n | r |
+---|---|---|---|---|---|---|---+
| p | p | p | p | p | p | p | p |
+---|---|---|---|---|---|---|---+
|   | / |   | / |   | / |   | / |
+---|---|---|---|---|---|---|---+
| / |   | / |   | / |   | / |   |
+---|---|---|---|---|---|---|---+
|   | / |   | / |   | / |   | / |
+---|---|---|---|---|---|---|---+
| / |   | / |   | / |   | / |   |
+---|---|---|---|---|---|---|---+
| P | P | P | P | P | P | P | P |
+---|---|---|---|---|---|---|---+
| R | N | B | K | Q | B | N | R |
+---|---|---|---|---|---|---|---+

Stay tuned for the following post! I’ll add a coordinate system and user input.