Open alemelis opened 4 years ago
I am reopening this because adding support for chess is something I am interested in.
The main thing to consider is that for AlphaZero to be effective on a relatively hard game such as chess, we will probably need heavy support for distributed learning.
This raises a very interesting challenge: how can we push AlphaZero.jl towards solving harder and harder games, while keeping its codebase simple and accessible enough for students and researchers who want to experiment on a single machine.
The lc0 approach of having separated training and engine might be good here. It makes distributed computing easier.
@jonathan-laurent sorry for closing, happy to re-open for discussion
I've already implemented what I think should go in the game.jl
file as the package Bobby.jl. There are some parts of the API yet to be added (for example, a random game function), but the most of the game logic is there.
Note that Bobby was from the beginning not supposed to use a minmax approach, hence it's not super fast. For reference, Chess.jl by Tord Romstad (yep, Stockfish developer) gets to ~75Mnodes/s while Bobby is one order of magnitude slower with ~5Mnodes/s. However, the beauty of AlphaZero approach is exactly that you don't need 800Mnodes/s (stockfish c++) to be competitive.
I'd be interested in porting Bobby to this repo, at least to make a working example.
One thing that could be a problem with using Bobby.jl is that it's move description is rather verbose. Lc0 runs into significant memory pressure, so we use a format for storing moves that only takes 2 bytes. For longer searches, this matters a lot as search is bottle-necked on memory (if you have really fast gpu).
@oscardssmith
this is the Move
struct in Bobby
mutable struct Move
type::Symbol
from::UInt64
to::UInt64
take::Piece
enpassant::UInt64
promotion::Symbol
castling::UInt8
end
whereas in Lc0 you managed to squeeze all the basic info in 16bit (!) https://github.com/LeelaChessZero/lc0/blob/0622049bbcb2f348a75083c957041eada36b5cbd/src/chess/bitboard.h#L285-L289
it seems like you only need from
, to
, and promotion
to define a move. I guess then that en-passant and castling are checked elsewhere.
Reducing to
mutable struct Move
from::UInt64
to::UInt64
promotion::Symbol
end
can be done, but changing to Move::UInt16
will probably mean rewriting the entire engine.
I guess the best thing to do here is to use this engine (even tho it may be seen as cheating) https://github.com/romstad/Chess.jl
You actually can fit en peasant, castling, capturing and promotions into the 2 bytes (the reason capturing is hard is because to unmake the move, you need to know what you captured. This link https://www.chessprogramming.org/Encoding_Moves does a pretty good job of explaining the details. The weirdest type of move is probably capture promotions, where you store both the piece you captured and what you promoted to. To facilitate this, you can use the fact that if you know the starting square of the pawn capture promotion, you know that it ends on the back rank, so you can use the 3 bits that would normally store the row to which the piece is moving to instead store what piece you promoted to.
[removed]
(I was asking how to add a chess implementation, then I found the guidelines about adding a new game)