Search code examples
algorithmevaluationchess

Simple Minimax Evaluation Function for Chess Position


I'm putting together a simple chess position evaluation function. This being the first time for me building a chess engine, I am feeling very tentative with putting in just any evaluation function. The one shown on this Chess Programming Wiki page looks like a good candidate. However this has an ellipsis at the end which makes me unsure of whether it will be a good one to use?

Once the whole engine is in place and functional, I intend to come back to the evaluation function and make a real attempt to sorting it out properly. But for now I need some sort of function which is good enough to play against an average amateur.


Solution

  • The most basic component of an evaluation function is material, obviously. This should be perfectly straightforward, but on its own does not lead to interesting play. The engine has no sense of position at all, and simply reacts to tactical lines. But we will start here:

    value = white_material - black_material           // calculate delta material
    

    Next we introduce some positional awareness through piece-square tables. For example, this is a such a predefined table for pawns:

    pawn_table = {
         0,  0,  0,  0,  0,  0,  0,  0,
        75, 75, 75, 75, 75, 75, 75, 75,
        25, 25, 29, 29, 29, 29, 25, 25,
         4,  8, 12, 21, 21, 12,  8,  4,
         0,  4,  8, 17, 17,  8,  4,  0,
         4, -4, -8,  4,  4, -8, -4,  4,
         4,  8,  8,-17,-17,  8,  8,  4,
         0,  0,  0,  0,  0,  0,  0,  0
    }
    

    Note that this assumes the common centipawn (value of pawn is ~100) value system. For each white pawn we encounter, we index into the table with the pawn's square and add the corresponding value.

    for each p in white pawns
        value += pawn_table[square(p)]
    

    Note that we can use use a simple calculation to reflect the table when indexing for black pieces. Alternatively you can define separate tables.

    For simple evaluation this will work very well and your engine will probably already be playing common openings. However, it's not too hard to make some simple improvements. For example, you can create tables for the opening and the endgame, and interpolate between them using some sort of phase calculation. This is especially effective for kings, where their place shifts from the corners to the middle of the board as the game progresses.

    Thus our evaluation function may look something like:

    evaluate(position, colour) {
        phase = total_pieces / 32                     // this is just an example
    
        opening_value += ...                          // sum of evaluation terms
        endgame_value += ...
    
        final_value = phase * opening_value + (1 - phase) * endgame_value
        return final_value * sign(colour)             // adjust for caller's perspective
    }
    

    This type of evaluation, along with quiescence search, should be enough to annihilate most amateurs.