Chess and C, day 3

Finally, after setting the skeleton of the game on day 1 and day 2, I’ve managed to get a chess board where you can actually play. Of course, it’s quite rudimentary and you’ll have to input the coordinates by typing them, but I think that for the moment it’ll do.

The first thing to think about is how are we going to represent a movement in our game. Basically, a movement is a couple of coordinates representing the origin and destination of a piece. Let’s capture that idea in a type.

typedef struct {
    Coord orig;
    Coord dest;
} Move;

As you can see, the type is quite simple and will suit perfectly our needs. Anyway, the type alone won’t serve us if we don’t have a way of inputting the movements. How are we going to implement the input system will depend on the interface we will be using. For the moment our interface is CLI based, but we should think that in a future we may be able to implement something using curses or GTK. For that reason, the input system should be as detached as possible from the logic of the game. I’ve decided to encapsulate all the input related logic in the function Move input_move() and a bunch of static declared sub-functions. The final result is something similar to the following output.

White's turn.
Orig coordinate: e9
Invalid coordinate. Write something like "e2": e2
Dest coordinate: e4

As you may have guessed, this input will move the pawn on square e2 to e4. Due to the decoupling of the input system and the logic of the game it’s possible to implement more than one input system without any pain. In a future, maybe, I’ll implement an input system using algebraic coordinates.

Now that we have a representation of the movements and a way of input them, we can start implementing the main game loop. It’s implementation is quite trivial and looks very similar to the following piece of code.

    while (!game_is_checkmate(board, current_player)) {
        print_board(board, current_player);

        move_valid = 0;
        while (!move_valid) {
            m = input_move();

            if (game_is_move_valid(board, current_player, m))
                move_valid = 1;
            else
                printf("Invalid move. Please, try again. ");
        }

        board = board_make_move(board, m);
        current_player = current_player == WHITE ? BLACK : WHITE;
    }

As you can see, in this implementation the real logic of chess rules lives in the functions int game_is_checkmate(Board, Color) and int game_is_move_valid(Board, Color, Move) which, for the moment, aren’t implemented and always return 0 and 1 respectively.

Finally, thanks to all the abstraction and modular code we’ve written it’s possible to implement a tiny short main() function like the following one.

#include "board.h"
#include "game.h"

int main() {
    board_delete(game_loop(board_init()));

    return 0;
}

And that’s it! We have a working interface were we can play. Here is how will look the board after a few moves.

  +---+---+---+---+---+---+---+---+
8 | R | N | B | Q | K | B | N | R |
  +---+---+---+---+---+---+---+---+
7 | P | P | P |   | / | P | P | P |
  +---+---+---+---+---+---+---+---+
6 |   | / |   | P |   | / |   | / |
  +---+---+---+---+---+---+---+---+
5 | / |   | / |   | P |   | / |   |
  +---+---+---+---+---+---+---+---+
4 |   | / |   | / | p | / |   | / |
  +---+---+---+---+---+---+---+---+
3 | / |   | / |   | / | n | / |   |
  +---+---+---+---+---+---+---+---+
2 | p | p | p | p |   | p | p | p |
  +---+---+---+---+---+---+---+---+
1 | r | n | b | q | k | b | / | r |
  +---+---+---+---+---+---+---+---+
    a   b   c   d   e   f   g   h

White's turn.
Orig coordinate: 

Posted on April 1, 2015
Tags: chess, c, haskell

Comments? Sure! Just send me an email with it and I'll happily include it here.