0

After learning about alpha-beta pruning algorithm for a while, I decided to write a simple chess program. However, when running the program, the computer decides to make a silly move. I don't know where the functions are written wrong.

What do I have to fix for the program to work properly.

This is my static evaluation function, where m_turn is the side in turn, and m_xturn is the side that has not yet turned.:

int CChess::Evaluate()
{
    int score = 0;
    for (int r = 0; r < CHEIGHT; r++)
        for (int c = 0; c < CWIDTH; c++)
            if (m_color[r][c] == m_turn)
                score += PIECE_VALUE[m_piece[r][c]];
            else if (m_color[r][c] == m_xturn)
                score -= PIECE_VALUE[m_piece[r][c]];
    return score;
}

Alpha-beta pruning function:

int CChess::AlphaBeta(int depth, int alpha, int beta, bool isMaxPlayer)
{
    if (depth == 0)
        return Evaluate();
    std::vector<CChessMove> move_list = GenMove();
    size_t n = move_list.size();
    if (isMaxPlayer)
    {
        for (size_t i = 0; i < n; i++)
        {
            CChessPiece piece = Move(move_list[i]);
            int value = AlphaBeta(depth - 1, alpha, beta, false);
            UnMove(move_list[i], piece);
            if (value > alpha)
                alpha = value;
            if (alpha >= beta)
                break;
        }
        return alpha;
    }
    for (size_t i = 0; i < n; i++)
    {
        CChessPiece piece = Move(move_list[i]);
        int value = AlphaBeta(depth - 1, alpha, beta, true);
        UnMove(move_list[i], piece);
        if (value < beta)
            beta = value;
        if (alpha >= beta)
            break;
    }
    return beta;
}

The function to find the best move.

CChessMove CChess::ComputerThinks()
{
    int best_value = -CCHESS_INFINITY;
    CChessMove best_move = { {-1, -1}, {-1, -1 } };
    std::vector<CChessMove> move_list = GenMove();
    size_t n = move_list.size();
    for (size_t i = 0; i < n; i++)
    {
        CChessPiece piece = Move(move_list[i]);
        int value = AlphaBeta(CCHESS_DEPTH, -CCHESS_INFINITY, CCHESS_INFINITY, false);
        UnMove(move_list[i], piece);
        if (value > best_value)
        {
            best_value = value;
            best_move = move_list[i];
        }
    }
    return best_move;
}
  • 1
    Doesn't have to be anything wrong with the code, it could be the horizon effect. – john Jul 29 '22 at 09:08
  • In any case we obviously need to know, what the position was, what the move was, and what the depth of search was. – john Jul 29 '22 at 09:09
  • And a useful debugging step would be to test the same position without using alpha-beta pruning. If that produces a different result then that would indicate a bug. – john Jul 29 '22 at 09:10
  • `if (depth == 0) return Evaluate();` This is where the program has the chance to use the horizon effect, For example, if you are about to capture its queen, the program can do a silly check move, and delay the capture until depth -2. Now the problem has magically gone away! (Only to soon come back of course, but that is a problem for the next move). It is common to not call Evaluate() when some pieces are to be immediately captured, but to wait for a more "quiet" position. See [Quiescence Search](https://www.chessprogramming.org/Quiescence_Search) – BoP Jul 29 '22 at 09:27
  • Please provide more information. What is the silly move, in what position is it played, what depth are you looking at? Horizon effect might be the issue, but it is hard to know if we don't get more information. – eligolf Aug 02 '22 at 03:50

1 Answers1

1

What this really means is that your engine thought it found a refutation. For example, perhaps it analyzed QxP at depth 1. It would think that it had just won a pawn, which is great! But, one move later it realizes that it would lose the queen. This is a problem even at higher depths - an engine might thing QxP leads to a series of captures that ends with it being a pawn up, but in reality loses a rook at the very last capture that it didn't see. I would recommend implementing quiescience search as others in the comments have suggested, which plays through all captures instead of directly evaluating. Since there are very few captures compared to normal moves in a given position this is cheaper than trying to add a few extra depth.

I would also highly recommend putting it in a Negamax framework rather than the standard Alpha-Beta. It's much simpler.

AAce3
  • 136
  • 1
  • 2