Oops. Chess programming can be somewhat addictive, one of the reasons being that it is quite objective; you can test your engines against others, and see the objective progress you're making (or not).lithander wrote: ↑Fri Feb 26, 2021 12:11 pm No. Up to my first functional min/max version I hadn't discovered this forums yet. I didn't know that I'd eventually have to pit it against Rustic Alpha and so I didn't worry about how others were doing it. In other words I hadn't fallen into this rabbit hole called 'chess programming' yet.
I'd like it a lot if you'd add PST's and QSearch (and if you don't have it, MVV-LVA and check extensions). Then you'd really have a complete, minimal chess engine. Even if you leave it at that and start over with a bitboard engine (I would, because you WILL eventually end up there), MinimalChess 0.1 and 0.2 will be good engines to test against for newcomers. There's a lot of crap down there in the rating list, especially below 1500. It would be perfect if you kept the binaries and code online.
That's good. Even if you leave MinimalChess as it is after version 0.2 (just rename it to 1.0, and be done with it), it will be a stable engine with easy to understand code in C#, a language you don't see often in chess engine programming.I think I didn't even know the words "bitboard" and "mailbox" and just reinvented the wheel because it didn't seem so hard that you'd need to read books or look at other implementations. I still like the resulting move generator code. I think it's pretty, because it's simple. When I forced my wife to watch my making-of videos she understood my explanation of how the move gen works just so. As she's not a programmer I doubt that would have been the case with bitboards!
I also often explain things to my GF. She's not a programmer either, but she often understands things before I even finish my sentences. I hope that this means that I'm explaining my stuff well, and thus I know what I'm doing and implementing. When she begins a sentence with "This might be a stupid question, but...", I already know: "Damn. There it goes... if I program this like I explained, it won't work."
If you have engine X with feature Y, and X with feature A, you can measure the differences; but you're right, it's guesswork for an engine X with both feature X and Y. In a chess engine, features are interdependent. If you measure the Elo-gain of feature Y, it may be more or less, depending on the fact if you have A already implemented or not.I don't think you can add and subtract ELO points like that. Otherwise, just play against a random mover and win all games and you get infinity ELO and you've solved Chess!
Don't you worry! You're completely safe at this point.
...but it's doing good against Sargon 1978 (1249 Elo on CCRL)Code: Select all
Score of MinimalChess 0.2.4 PST+Q vs Rustic: 13 - 49 - 13 [0.260] ... MinimalChess 0.2.4 PST+Q playing White: 7 - 25 - 6 [0.263] 38 ... MinimalChess 0.2.4 PST+Q playing Black: 6 - 24 - 7 [0.257] 37 ... White vs Black: 31 - 31 - 13 [0.500] 75 Elo difference: -181.7 +/- 81.2, LOS: 0.0 %, DrawRatio: 17.3 % 75 of 100 games finished.
To some extent, I had expected more from adding PST's and QSearch. Can I download the binary already? I wonder what the reason for the difference is. Could it be speed only?
PS: Have implemented check extension? "if in_check { depth += 1} " just before "if depth == 0 { qsearch() }"? It is very bad to go into qsearch if you're in check, because not all check evasions will be calculated (as QSearch only does captures).
Yes, indeed; but it's a N=1 test obviously. The engine used can make a big difference. In CCRL:So, I'd estimate MMC with QSearch and PST in it's current form to be at 1400-1500 ELO.Code: Select all
Score of Sargon 1978 vs MinimalChess 0.2.4 PST+Q: 8 - 46 - 10 [0.203] ... Sargon 1978 playing White: 3 - 24 - 5 [0.172] 32 ... Sargon 1978 playing Black: 5 - 22 - 5 [0.234] 32 ... White vs Black: 25 - 29 - 10 [0.469] 64 Elo difference: -237.5 +/- 97.0, LOS: 0.0 %, DrawRatio: 15.6 % 64 of 100 games finished.
Rustic vs. ShallowBlue (1705) => 21.5 − 10.5
Rustic vs. TSCP (1725) => 9 − 23
Rustic makes use of Shallow Blue's weaknesses; TSCP makes use of Rustic's weaknesses. You have to test against a range of engines for an accurate rating.
I'd love to have the preliminary binary.If you really want it I can send you the binary via PM. But I would prefer to take my time to make sure everything these new features are implemented to the best of my ability before I release a version with PSTs and QSearch. C# makes it easy to rapidly prototype stuff before you optimize it. For example the SortMvvLva is only a few lines of code currently and took me 10 minutes to write. I love C# making that possible. But then I've spend hours looking for a bug that probably is just a performance problem. So, as I've just painfully learned, you can implement a perfectly good optimization like qsearch so inefficiently that it negates it's effect entirely under certain conditions (e.g. too simplistic eval, depth > 7plys).
Two things:I wouldn't be surprised if the move ordering that looks up pieces in the board array and recomputes the score each time whatever sort-algorithm C# uses behind the scene needs to compare two elements. I know of course how this could be implemented faster but "premature optimization is the root of all evil"... well in this case Donald Knuth's aphorism was misleading me.
Code: Select all
public static void SortMvvLva(List<Move> moves, Board context) { int Score(Move move) { Piece victim = context[move.ToIndex]; Piece attacker = context[move.FromIndex]; //Rating: 100 * Victims value first, offset by the attackers value return (victim == Piece.None) ? 0 : ((100 * (int)victim) - (int)attacker); } moves.Sort((a, b) => Score(b).CompareTo(Score(a))); }
- Implement a piece-list, so you know where your pieces are. I even do this with bitboards, so I don't have to iterate over 12 bitboards to find the piece I need, and it already is a speed gain. Let alone if you make a piece list and you don't have to iterate over 64 squares.
- Don't sort the move list. You're doing unnecessary work, because some of the moves will never be tried due to cutoffs. Implement a score() function (where you give each move its MVV-LVA score), and a pick() function (where you set the move with the best score in the first spot of the move list just before you start iterating).