thank you for explaining, now i get it.algerbrex wrote: ↑Tue Sep 07, 2021 2:12 pmNot quite. The way I've usually seen MVV/LVA implemented is using a two-dimensional array. Here's how Blunder does MVV-LVA move ordering:tcusr wrote: ↑Tue Sep 07, 2021 10:19 am i rewrote the search function and now the engine seems to be working correctly consistently, it solves lichess puzzles if i give enough depth to see the combination (i'm only evaluating material for now).
now i'm going to add:
1) move ordering (i'll start with MVV/LVA because it is the simplest)
2) PSQT tables to improve strength
3) quiescence search
i have one question, is MVV ordering basically running a sort function on all the captures using the value of the piece on the "to" square to compare? and LVA just sorting in descending order using the value of the piece on the "from" square? this is the case for me because i use this enumCode: Select all
enum { KING = 1, PAWN, KNIGHT, BISHOP, ROOK, QUEEN };
And here's how "scoreMoves" and "orderMoves" are called in negamax:Code: Select all
// An array that maps move scores to attacker and victim piece types // for MVV-LVA move ordering: https://www.chessprogramming.org/MVV-LVA. var MvvLva [7][6]int16 = [7][6]int16{ {16, 15, 14, 13, 12, 11}, // victim Pawn {26, 25, 24, 23, 22, 21}, // victim Knight {36, 35, 34, 33, 32, 31}, // victim Bishop {46, 45, 44, 43, 42, 41}, // vitcim Rook {56, 55, 54, 53, 52, 51}, // victim Queen {0, 0, 0, 0, 0, 0}, // victim King {0, 0, 0, 0, 0, 0}, // No piece } ... // Score the moves given func (search *Search) scoreMoves(moves *MoveList, ttBestMove Move, ply uint8) { for index := 0; index < int(moves.Count); index++ { move := &moves.Moves[index] captured := &search.Pos.Squares[move.ToSq()] moved := &search.Pos.Squares[move.FromSq()] move.AddScore(MvvLva[captured.Type][moved.Type]) } } ... // Order the moves given by finding the best move and putting it // at the index given. func orderMoves(index int, moves *MoveList) { bestIndex := index bestScore := moves.Moves[bestIndex].Score() for index := bestIndex; index < int(moves.Count); index++ { if moves.Moves[index].Score() > bestScore { bestIndex = index bestScore = (*moves).Moves[index].Score() } } tempMove := moves.Moves[index] moves.Moves[index] = moves.Moves[bestIndex] moves.Moves[bestIndex] = tempMove }
Code: Select all
// Score the moves search.scoreMoves(&moves, ttBestMove, ply) for index := 0; index < int(moves.Count); index++ { // Order the moves to get the best moves first. orderMoves(index, &moves) move := moves.Moves[index] ... }
i have another problem now, i thought my search functions worked but i changed something and now i don't know what's going on.
even though i don't know Go i looked at your code and i think i'm doing the same thing but the engine gives me random moves even for simple positions like this k7/8/K7/8/8/8/8/2R5 w - - 0 1or k7/8/K3q3/3P4/8/8/8/8 w - - 0 1 (moves that my material-only evaluation functions could easily find)
Code: Select all
template<int C>
int negamax(Board& board, int depth, int alpha, int beta)
{
if (depth == 0)
return eval<C>(board);
Move list[250], *end;
int score;
bool no_moves = true;
end = generate_noisy<C>(board, list);
end = generate_quiet<C>(board, end);
for (Move *m = list; m != end; ++m) {
board.make_move<C>(*m);
if (board.move_was_legal()) {
no_moves = false;
score = -negamax<C ^ 1>(board, depth - 1, -beta, -alpha);
}
board.undo_move<C>(*m);
if (score >= beta)
return beta;
if (score > alpha)
alpha = score;
}
if (no_moves)
return board.in_check() ? -MAX_EVAL : 0;
return alpha;
}
// root negamax
template<int C>
Move search(Board& board, int depth)
{
Move list[250], *end;
Move best_move;
int alpha = -MAX_EVAL;
int beta = MAX_EVAL;
int score;
end = generate_noisy<C>(board, list); // eventually order these
end = generate_quiet<C>(board, end);
for (Move *m = list; m != end; ++m) {
board.make_move<C>(*m);
if (board.move_was_legal())
score = -negamax<C ^ 1>(board, depth - 1, -beta, -alpha);
board.undo_move<C>(*m);
if (score == beta) {
alpha = beta;
best_move = *m;
break;
}
if (score > alpha) {
alpha = score;
best_move = *m;
}
}
return best_move;
}