Saturday, December 22, 2012

Getting used to some C++ techniques

In the new release of my engine I plan to rewrite its board evaluation (again). This is necessary because the old evaluation uses weights declared as compile time constants.

e.g. const int BISHOP_PAIR_BONUS = 50;

This is easy to maintain and also very fast because the compiler just inserts the value in the evaluation code and no memory access is later required to find out what the bonus for having two bishops is. The problem starts when you want to change that value. It requires a recompilation of the whole program. As I want to be able to change that value at run-time, maybe even while the engine is running using constant values is not an option anymore. I have to replace them with variables even if it might slowdown execution a bit, probably not much because those values are accessed so frequently that they will stay in the L1 cache of the CPU.

But it means that I have to touch everything in my board evaluation code and if I have to touch everything anyway I can just as well clean it up a bit.

One thing that bothered me a bit is code duplication. Every feature is evaluated first for white and then again for black. The implementation of the features is not identical, e.g. white pawns move up black pawns move down, white king is safe at G1, black king is safe at G8. But the source code is very similar anyway and differs only in a few parameters. It also makes the code harder to maintain because every time I change something I must remember to change it in the WHITE and in the BLACK part of the code.

Fortunately C++ offers a language construct called function template. It's main purpose is to uses the same code to work with different types of variables e.g. a sort function that sorts integers uses the same logic as a function that sorts floats, it uses just a different declaration. C++ templates allow the programmer now to write the source code only once and the compiler will create the different code for ints and floats automatically.

This is awesome and just what I need.

While rewriting the evaluation I extract those parts where templates might be helpful and clean up my code.

Instead of a function

void TEvaluator::evaluateThreats()
{
     // do something for white threats against black pieces
     ...

    // now do the same for black threats against white pieces
    ...
}

I have now a template function

template< EColor side > void TEvaluator::evaluateThreats()
{
    const EColor enemySide = (side == WHITE ? BLACK : WHITE);

    // do something for threats of "side" against the pieces of the "enemy side"
    ...
}

which is then called via

evaluateThreats< WHITE >();
evaluateThreats< BLACK >();

This works so well that I might rewrite other parts of the engine as well at some point in the future. The move generator currently duplicates code like hell and could definitely benefit from this technique a lot.

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete