how to continue

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
lithander
Posts: 881
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: how to continue

Post by lithander »

tcusr wrote: Wed Sep 08, 2021 2:03 pm after i get out of the move/unamake loop with no moves played, what do i need check for?

Code: Select all

if (no_moves && in_check)
    return -MAX_EVAL
this seems correct but i have no way to detect stalemate in quiescence
that's what I do:

Code: Select all

            //checkmate?
            if (expandedNodes == 0 && inCheck)
                return Evaluation.Checkmate(color, ply);

            //stalemate?
            if (expandedNodes == 0 && !LegalMoves.HasMoves(position))
                return 0;

            //can't capture. We return the 'alpha' which may have been raised by "stand pat"
            return alpha;
        }
tcusr wrote: Wed Sep 08, 2021 2:03 pm i really hope im not at 1000 elo because even though i only have the most basic features the engine works correctly and is fast (it's written in C++ vs algerbrex's engine which is written in Go, so even when i'll reach his amount of features i expect (hope) my engine performs a bit better)
maybe I underestimated the amount of features you already have. My point was: do it now. The best way to know that a feature works as expected is if it made your engine stronger within the expected ELO range.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
tcusr
Posts: 323
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: how to continue

Post by tcusr »

lithander wrote: Wed Sep 08, 2021 2:38 pm
tcusr wrote: Wed Sep 08, 2021 2:03 pm after i get out of the move/unamake loop with no moves played, what do i need check for?

Code: Select all

if (no_moves && in_check)
    return -MAX_EVAL
this seems correct but i have no way to detect stalemate in quiescence
that's what I do:

Code: Select all

            //checkmate?
            if (expandedNodes == 0 && inCheck)
                return Evaluation.Checkmate(color, ply);

            //stalemate?
            if (expandedNodes == 0 && !LegalMoves.HasMoves(position))
                return 0;

            //can't capture. We return the 'alpha' which may have been raised by "stand pat"
            return alpha;
        }
tcusr wrote: Wed Sep 08, 2021 2:03 pm i really hope im not at 1000 elo because even though i only have the most basic features the engine works correctly and is fast (it's written in C++ vs algerbrex's engine which is written in Go, so even when i'll reach his amount of features i expect (hope) my engine performs a bit better)
maybe I underestimated the amount of features you already have. My point was: do it now. The best way to know that a feature works as expected is if it made your engine stronger within the expected ELO range.
reading this https://github.com/lithander/MinimalChe ... eSearch.cs i understand that expandNodes is the numbers of moves played in quiescence. if you have not played any move and you're in check that's checkmate, this part i got right with "if (no_moves && in_check)"
to check if it is stalemate you generate only legal moves and if there are none it is stalemate.
i guess this is what i have to implement now but i have a pseudo-legal generator, i would have to make all the quiet moves in that position and see if they are illegal, but this seems slow. is this why some engines have a special move generator for king evasions?

question for algerbrex, in your evaluation function you don't seem to consider material, all i can see here https://github.com/algerbrex/blunder/bl ... luation.go is that you're calculating the scores from the your tables, are you doing it somewhere else or am i missing something?
User avatar
algerbrex
Posts: 596
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: how to continue

Post by algerbrex »

tcusr wrote: Wed Sep 08, 2021 3:06 pm
lithander wrote: Wed Sep 08, 2021 2:38 pm
tcusr wrote: Wed Sep 08, 2021 2:03 pm after i get out of the move/unamake loop with no moves played, what do i need check for?

Code: Select all

if (no_moves && in_check)
    return -MAX_EVAL
this seems correct but i have no way to detect stalemate in quiescence
that's what I do:

Code: Select all

            //checkmate?
            if (expandedNodes == 0 && inCheck)
                return Evaluation.Checkmate(color, ply);

            //stalemate?
            if (expandedNodes == 0 && !LegalMoves.HasMoves(position))
                return 0;

            //can't capture. We return the 'alpha' which may have been raised by "stand pat"
            return alpha;
        }
tcusr wrote: Wed Sep 08, 2021 2:03 pm i really hope im not at 1000 elo because even though i only have the most basic features the engine works correctly and is fast (it's written in C++ vs algerbrex's engine which is written in Go, so even when i'll reach his amount of features i expect (hope) my engine performs a bit better)
maybe I underestimated the amount of features you already have. My point was: do it now. The best way to know that a feature works as expected is if it made your engine stronger within the expected ELO range.
...
question for algerbrex, in your evaluation function you don't seem to consider material, all i can see here https://github.com/algerbrex/blunder/bl ... luation.go is that you're calculating the scores from the your tables, are you doing it somewhere else or am i missing something?
No, you're not :lol: The nice thing about the scheme I'm using is that the material values for each piece are already factored into the PST. So the table squares for each piece contain the relative material value of a piece on that given square.

I remember I first saw this trick used in PeSTO's evaluation and Lithander's code, and I thought it was pretty clever.

The only downside I've experienced using this scheme is having situations when you need the direct material value of say, a queen, for pruning purposes. But it's not a huge issue, and it makes the code much cleaner overall.
tcusr
Posts: 323
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: how to continue

Post by tcusr »

algerbrex wrote: Wed Sep 08, 2021 3:39 pm
tcusr wrote: Wed Sep 08, 2021 3:06 pm
lithander wrote: Wed Sep 08, 2021 2:38 pm
tcusr wrote: Wed Sep 08, 2021 2:03 pm after i get out of the move/unamake loop with no moves played, what do i need check for?

Code: Select all

if (no_moves && in_check)
    return -MAX_EVAL
this seems correct but i have no way to detect stalemate in quiescence
that's what I do:

Code: Select all

            //checkmate?
            if (expandedNodes == 0 && inCheck)
                return Evaluation.Checkmate(color, ply);

            //stalemate?
            if (expandedNodes == 0 && !LegalMoves.HasMoves(position))
                return 0;

            //can't capture. We return the 'alpha' which may have been raised by "stand pat"
            return alpha;
        }
tcusr wrote: Wed Sep 08, 2021 2:03 pm i really hope im not at 1000 elo because even though i only have the most basic features the engine works correctly and is fast (it's written in C++ vs algerbrex's engine which is written in Go, so even when i'll reach his amount of features i expect (hope) my engine performs a bit better)
maybe I underestimated the amount of features you already have. My point was: do it now. The best way to know that a feature works as expected is if it made your engine stronger within the expected ELO range.
...
question for algerbrex, in your evaluation function you don't seem to consider material, all i can see here https://github.com/algerbrex/blunder/bl ... luation.go is that you're calculating the scores from the your tables, are you doing it somewhere else or am i missing something?
No, you're not :lol: The nice thing about the scheme I'm using is that the material values for each piece are already factored into the PST. So the table squares for each piece contain the relative material value of a piece on that given square.

I remember I first saw this trick used in PeSTO's evaluation and Lithander's code, and I thought it was pretty clever.

The only downside I've experienced using this scheme is having situations when you need the direct material value of say, a queen, for pruning purposes. But it's not a huge issue, and it makes the code much cleaner overall.
are you talking about this part of the code? (taken from https://www.chessprogramming.org/PeSTO% ... n_Function)

Code: Select all

void init_tables()
{
    int pc, p, sq;
    for (p = PAWN, pc = WHITE_PAWN; p <= KING; pc += 2, p++) {
        for (sq = 0; sq < 64; sq++) {
            mg_table[pc]  [sq] = mg_value[p] + mg_pesto_table[p][sq];
            eg_table[pc]  [sq] = eg_value[p] + eg_pesto_table[p][sq];
            mg_table[pc+1][sq] = mg_value[p] + mg_pesto_table[p][FLIP(sq)];
            eg_table[pc+1][sq] = eg_value[p] + eg_pesto_table[p][FLIP(sq)];
        }
    }
}
i guess in your code you already added the piece value instead of always initializing it to the same value, i admit this is simpler than having multiple functions for each thing you want to evaluate.

i don't understand one thing though, where do these number come from? i ask this because if i want to give a bonus for passed pawns how would i decide the value of this bonus?
Mergi
Posts: 127
Joined: Sat Aug 21, 2021 9:55 pm
Full name: Jen

Re: how to continue

Post by Mergi »

tcusr wrote: Wed Sep 08, 2021 12:27 pm another thing, i also decided to order moves in my negamax function instead of only at the root (i still don't have an iterative deepening loop) and i noticed that it is 2x faster, even though mergi, i think, told me it was not a good idea.
Yes, you order moves using the MVVLVA method during the search, it's just the root moves that i order differently.
i don't understand one thing though, where do these number come from? i ask this because if i want to give a bonus for passed pawns how would i decide the value of this bonus?
These values are generated by a method called Texel Tuning, which is a form of supervised machine learning. The tuner itself to write and get going isn's totally trivial (at least for me :) ), but the nice thing about it is that you as a programmer could have never touched a chess piece in your life and still make an extremely competent evaluation function this way.

These automatically tuned tables work best when you use them as they are, without adding anything hand-written. Because of the way the tuning works, adding any of your own evaluation might (although not always) actually make them worse. So if you wanted to take for example the Pesto tables and then add a special passed pawn bonus, the engine might be weaker than without it. You preferably always want to tune them all together.

I started with the Simplified Evaluation that is on the chess programming wiki. It provides very simple but still quite strong PST. As evaluation is a fairly stand-alone thing, not closely coupled with the rest of the engine, it's very easy to just replace it later on for whatever else you wish to use. For that reason i feel like starting with the simplest possible solution might be the best choice, where the values are easily predictable, so that debugging the rest of the engine is much easier.
tcusr
Posts: 323
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: how to continue

Post by tcusr »

Mergi wrote: Wed Sep 08, 2021 7:07 pm
tcusr wrote: Wed Sep 08, 2021 12:27 pm another thing, i also decided to order moves in my negamax function instead of only at the root (i still don't have an iterative deepening loop) and i noticed that it is 2x faster, even though mergi, i think, told me it was not a good idea.
Yes, you order moves using the MVVLVA method during the search, it's just the root moves that i order differently.
i don't understand one thing though, where do these number come from? i ask this because if i want to give a bonus for passed pawns how would i decide the value of this bonus?
These values are generated by a method called Texel Tuning, which is a form of supervised machine learning. The tuner itself to write and get going isn's totally trivial (at least for me :) ), but the nice thing about it is that you as a programmer could have never touched a chess piece in your life and still make an extremely competent evaluation function this way.

These automatically tuned tables work best when you use them as they are, without adding anything hand-written. Because of the way the tuning works, adding any of your own evaluation might (although not always) actually make them worse. So if you wanted to take for example the Pesto tables and then add a special passed pawn bonus, the engine might be weaker than without it. You preferably always want to tune them all together.

I started with the Simplified Evaluation that is on the chess programming wiki. It provides very simple but still quite strong PST. As evaluation is a fairly stand-alone thing, not closely coupled with the rest of the engine, it's very easy to just replace it later on for whatever else you wish to use. For that reason i feel like starting with the simplest possible solution might be the best choice, where the values are easily predictable, so that debugging the rest of the engine is much easier.
why can't all engines use the same psqt that is considered best? is this more of a programmer choice?

btw i finished implementing all the things i wanted to:
MVVLVA ordering: debugged and tested, improved the engine's speed by a lot
PSQT (i'm using algerbrex's for now, thanks): i don't know if i did anything wrong because it plays decent chess (the move it chooses is _usually_ in the top 3 recommendations of stockfish) but sometimes it sneaks in a weaker move
for example here 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - i don't know why it wants to play b4c4 at depth 7
1: b4f4
2: b4f4
3: b4f4
4: b4f4
5: b4f4
6: b4f4
7: b4c4
8: b4f4
9: b4f4
10: b4f4
quiscence search: it seems to be working correctly, now it doesn't recommend stupid captures anymore.

one question, my engine reaches a depth of 8 in most middlegames within at least 30 seconds, is this normal for a weak engine or are there bugs somewhere in the code? because 3 minutes for depth 10 seems too much. in endgames i can reach, at most, 14

after fixing these things i will implement the UCI protocol.
Ras
Posts: 2488
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: how to continue

Post by Ras »

tcusr wrote: Wed Sep 08, 2021 2:03 pmthis seems correct but i have no way to detect stalemate in quiescence
You mostly don't need that. I only use a special stalemate verification in QS that if the side to move is down to the bare king and not in check. That's helpful for some endgames with K+Q:K+P. During normal game, I defer that to main search only, not QS.

My QS mate detection works quite simple. First, I don't transition from main search to QS if I'm in check (check extension). Within QS, I don't verify for in-check in the first QS level because there cannot be a check.

The next three QS levels have the in-check detection. Assuming that I'm in check, then if alpha is below -MATE+ply, I set alpha to -MATE+ply. If none of the check evasions (special movegen) gets out of check, alpha stays at -MATE+ply, hence returning a proper mate score with correct distance.

Conversely, if alpha is already above -MATE+ply, then there's still no move that would improve alpha because there's no legal move at all, hence I return the node's score as alpha, which is a fail-low. The kicker is that it doesn't matter how low it fails because that branch will be discarded anyway.
Rasmus Althoff
https://www.ct800.net
Mergi
Posts: 127
Joined: Sat Aug 21, 2021 9:55 pm
Full name: Jen

Re: how to continue

Post by Mergi »

tcusr wrote: Wed Sep 08, 2021 8:45 pm why can't all engines use the same psqt that is considered best? is this more of a programmer choice?
Not what i said. Any good PSQT will work great, just that texel tuning works best when at the time of tuning it already knows about all the variables that will be used for evaluation. Of course you can nudge the evaluation a bit with some custom stuff even later on, but making bigger changes with custom tables in addition to the auto-tuned ones might be difficult. That's that i meant in response to this:
ask this because if i want to give a bonus for passed pawns how would i decide the value of this bonus?

By the way, if you are only after the strongest evaluation, you can just stick Stockfish's NNUE in your engine and reach grandmaster levels easily :D
tcusr
Posts: 323
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: how to continue

Post by tcusr »

Ras wrote: Wed Sep 08, 2021 9:10 pm
tcusr wrote: Wed Sep 08, 2021 2:03 pmthis seems correct but i have no way to detect stalemate in quiescence
You mostly don't need that. I only use a special stalemate verification in QS that if the side to move is down to the bare king and not in check. That's helpful for some endgames with K+Q:K+P. During normal game, I defer that to main search only, not QS.

My QS mate detection works quite simple. First, I don't transition from main search to QS if I'm in check (check extension). Within QS, I don't verify for in-check in the first QS level because there cannot be a check.

The next three QS levels have the in-check detection. Assuming that I'm in check, then if alpha is below -MATE+ply, I set alpha to -MATE+ply. If none of the check evasions (special movegen) gets out of check, alpha stays at -MATE+ply, hence returning a proper mate score with correct distance.

Conversely, if alpha is already above -MATE+ply, then there's still no move that would improve alpha because there's no legal move at all, hence I return the node's score as alpha, which is a fail-low. The kicker is that it doesn't matter how low it fails because that branch will be discarded anyway.
i don't think i understand.
lithander said that when in check he generates all the moves. if none of the move tried are legal it has to be checkmate.
but you have check extension at root, so you check if you are in check after the search. but since you have not tried all the moves you still don't know if it's checkmate, so you have to generate the rest and try them right?
lithander's approach seems simpler, i will still skip checking for stalemate because you said i don't need to
tcusr
Posts: 323
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: how to continue

Post by tcusr »

tcusr wrote: Wed Sep 08, 2021 10:22 pm
Ras wrote: Wed Sep 08, 2021 9:10 pm
tcusr wrote: Wed Sep 08, 2021 2:03 pmthis seems correct but i have no way to detect stalemate in quiescence
You mostly don't need that. I only use a special stalemate verification in QS that if the side to move is down to the bare king and not in check. That's helpful for some endgames with K+Q:K+P. During normal game, I defer that to main search only, not QS.

My QS mate detection works quite simple. First, I don't transition from main search to QS if I'm in check (check extension). Within QS, I don't verify for in-check in the first QS level because there cannot be a check.

The next three QS levels have the in-check detection. Assuming that I'm in check, then if alpha is below -MATE+ply, I set alpha to -MATE+ply. If none of the check evasions (special movegen) gets out of check, alpha stays at -MATE+ply, hence returning a proper mate score with correct distance.

Conversely, if alpha is already above -MATE+ply, then there's still no move that would improve alpha because there's no legal move at all, hence I return the node's score as alpha, which is a fail-low. The kicker is that it doesn't matter how low it fails because that branch will be discarded anyway.
i don't think i understand.
lithander said that when in check he generates all the moves. if none of the move tried are legal it has to be checkmate.
but you have check extension at root, so you check if you are in check after the search. but since you have not tried all the moves you still don't know if it's checkmate, so you have to generate the rest and try them right?
lithander's approach seems simpler, i will still skip checking for stalemate because you said i don't need to
sorry i only saw now that you use a special move generator when in check. i understand now

i'm still worried about my engine speed though
it takes 8 seconds to reach depth 10 here 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -. i suppose this is mostly an evaluation problem or maybe some pruning techniques (which i don't have) improve speed a lot here. i'm curious on how long it takes for algerbrex's engine to reach depth 10 (my evaluation function is basically his)