15-NOV-2024 - pgn
2157
I’m writing the parser, it’s going alright. I’m finding myself in want of a lot of QoL stuff so I’m splitting between them.
In particular, not being able to have a cheap, copy-able board representation like FEN was killing me, so I started
working on BEN, which is a relatively compact binary-encoded FEN equivalent. Insodoing I added Alter to FEN so it
technically counts as a whole Board Representation now. This led me to realize I’ve been using PieceBoard pretty
liberally as a way to make FEN alter-able, and I’ve unwittingly bound it quite tightly to a particular board
representation internally. It occured to me it would be pretty cheap to abstract this to a type alias that only claims
it’s traits and no particular internal representation. So in principle something like:
type Board : impl Alter + Default + Query + Clone + Into<FEN> = PieceBoard;
Then I can use Board everywhere, and if I want to switch to a different representation, I can just change the type to
anything that implements the traits. Later I can add additional traits like:
type MoveGenOptimizedBoard : impl Alter + Default + Query + Clone + Into<FEN> = Bitboard;
type UIOptimized : impl Alter + Default + Query + Clone + Into<FEN> = CharBoard;
I suspect I’ll want to introduce some kind of granularity here, I’m not sure the best way to do it, but I want to rely on no specific board representation interally, but rather on a set of traits that can be implemented by any board representation.
I’m premature in my optimization, but I can see that there will be a point where board representation becomes an optimization path and I want to approach that in a structured way.
I suppose figuring out how to extract the generic Board type is the first step.
2038 - pgn
I’m thinking a bit more about Alteration and what I should encode there. I think ultimately I do want to try to
encode the entire gamestate in the Alteration stream, which means encoding some sense of metadata, as well as game
events, and so on.
Each board representation implementation is going to be good at “something”, it may be optimized for efficient movegen,
or for easy evaluation, etc. I think each Alter type should advertise which subset of the commands it implements.
During ‘compilation’, the ‘compiler’ will check this list and try, where possible, to provide implementations of
whatever keywords are missing. So for instance, if a BoardRep doesn’t implement the ‘Clear’ command, the compiler will
replace it with 64 ‘Remove’ tags, assuming it implements ‘remove’.
As I build up the engine’s abilities, I can add new commands, and so long as I can implement them in terms of the older commands, I should be able to use the new command with any older board representation still, even if a bit slower. This matters for the UI and non-engine-y parts of Hazel. Since the UI is a big part of how I plan to develop Hazel, I want to build the UI to also read along the Log of ChessActions, which ultimately become a list of alterations.
Different consumers of that log stream can maintain a Cursor into the log and then ideally rewind/fastforward to any
state in the log. The composed object will implement Alter as the sum of it’s internal implementations, and dispatch
commands to subcomponents as it pleases. So the UI’s implementation of Alter might update it’s UI oriented internal
state, while the Engine might instead be grabbing many alter’s at once and applying them in batches somehow.