But with an 8x8 board you can store all free fields in a single 64-bit integer
That could be fast, would it not?
Tell that to AlphaZero
It's both actually. The former helps guide the search (MCTS, not an Alpha-Beta minmax), and the latter helps truncate the search before an end state.
> - A simpler but much faster engine will beat a more complex engine any time because the advantage of another ply easily outweighs the advantage of some clever algo.
Depends a lot on what you call "simple". Stockfish's search and evaluation subroutines are pretty complex and distinctly clever:
https://github.com/official-stockfish/Stockfish/blob/master/...
https://github.com/official-stockfish/Stockfish/blob/master/...
But I agree that early on, simple is the way to go. It's much easier to optimize a simple engine.
> - A 10x10 board with an unreachable edge has some advantages [...]
Maybe in theory, but FWIW I don't know of any modern engine that does this. A more popular variant of the 10x10 or 10x12 idea was, back in the day, the 0x88 layout:
https://www.chessprogramming.org/0x88
If you're going to be writing an engine today from scratch, use the bitboard representation. It's easy to implement and has the most resources out there if you need help.
(Bitboards is just the idea of representing the game state as a bunch of 64-bit ints, with one u64 per white/black type of piece.)
Your example use-case, of knight posisitions, is usually solved with bitboards using an 64-element array mapping squares to a bitboard of all the places a knight on that square can go. Here's where Stockfish does that:
https://github.com/official-stockfish/Stockfish/blob/b06ef36...
Other commenters have noted that you can do a slightly fancier version of this lookup table technique to solve for the sliding pieces (bishops and rooks (queens are a bitwise OR of bishops and rooks)), because the raw data is low entropy, so finding a perfect hash function ("magic bitboard", in the lingo) is fast enough to do on startup:
https://github.com/official-stockfish/Stockfish/blob/b06ef36...
It's existing techniques like this that make bitboards a good choice for beginners; if you get stuck, you can find resources online.
> - Optimization of engine code is much harder than optimization of the yield function.
Big +1 there! The yield function is also much easier to A/B test.
> - It is much better to not generate 'bad' moves than it is to prune them away after a lot of extra work has been done. Colin Wrights' law: 'You can't make computers faster, you can only make them do less work' clearly applies here.
Yes, but it's pretty hard to reliably get your move generator to generate good moves first. The other side of making mixmax search fast is quickly throwing out branches that aren't relevant.
For instance, delta pruning and null-move pruning do this by trying to detect if one of the sides has thrown the game with their last move; since minmax is about assuming optimal play on both sides, branches where someone makes a blunder aren't worth looking into.
> - memoization can bring insane speed gains.
Yup! Also, a lot of engines have optimized routines that let you undo a move quickly, without having to keep a redundant stack of every position's state, which would involve a lot of memcpy-ing.
Have fun! I had to stop doing chess engines, they were becoming too much of a distraction for me. I'm kind of glad ML-AI is starting to beat human-crafted AI in chess, that way the space can go back to being a fun little hacker cottage industry.
Edit: Oh! When making a chess engine, start by implementing "perft":
https://www.chessprogramming.org/Perft
That way you can compare how many legal moves your engine thinks there is in a position, versus how many Stockfish or some other known-good engine thinks there is. It's the closest thing there is to unit tests in the space.
Some notes from past efforts:
- A simpler but much faster engine will beat a more complex engine any time because the advantage of another ply easily outweighs the advantage of some clever algo.
- A 10x10 board with an unreachable edge has some advantages when laid out as a linear array because it allows for much easier memory management (premature optimizations and all that...). On an 8x8 board laid out linearly the edges have no way of limiting piece movement but on a 10x10 you get that for free by putting an 'impossible' value in the unreachable edge fields. Even a knight won't be able to jump that effectively two field wide edge. This turns all legal moves for all pieces into a simple offset rather than a two dimensional affair.
- Optimization of engine code is much harder than optimization of the yield function.
- It is much better to not generate 'bad' moves than it is to prune them away after a lot of extra work has been done. Colin Wrights' law: 'You can't make computers faster, you can only make them do less work' clearly applies here.
- memoization can bring insane speed gains.
Good luck!