20-NOV-2024

1141 - pgn

Having thought about it more overnight, I think my plan is thus:

  1. Get the existing PGN parser to the closest thing to a working state as I can. Hack as needed
  2. Merge
  3. Extract and unify this ‘minilanguage’ thing I have going on into it’s own abstraction (preparing for eventual parser writing for the Witchlang)
  4. Build a better MoveGen system based on the enum-based approach

Ultimately Hazel (the engine bit) is going to have a WitchLang, which compiles to WitchASM, which is an Enum-y language like what I have now. WitchLang will be a small scripting language that can be used to create more complex queries that can then be optimized, similar to how a database query-plans.

Hazel (the engine) will be a small VM with some tools to alter it’s scale, what represnetations are active, etc. It will produce a stream of instructions to configure itself and solve any presented chess problem.

This will also allow for more asynchronous processing, e.g., the movegen can request a bunch of calculations, but the engine can batch and cache these things, reach into existing cache, etc – behind the scenes.

  1. Get perft working for a few positions, matching stockfish

This milestone will be the big ‘I’ve got a system working’ moment; since from here it’s just a matter of adding eval and pruning tools to the results of the movegen. Ideally I’ll be able to express some basic evaluation functions in the WitchLang and then start looking to extend it to NNUE and the like. Ideally it’s something like:

Engine Tune:
    Set parameters here
Search <Some FEN>
    Depth <some plycount>
    Prune With:
        Some subprogram
    Filter Final:
        Some subprogram
    Group By:
        Some subprogram
# etc

This gets compiled down to a series of WitchASM instructions that can be run on the engine, and then ideally the language can express self-retuning as it iterates, etc. Ideally all the chess-related logic ends up in this language and we then attack the problem like a compiler problem, optimizing to intermediate reps and building an engine that can solve the given script optimally.

I think this will make for something very flexible, since most of the chess logic will live in the language and not the engine itself. I suspect I may see some overhead, but I’m hoping the translation layers should mitigate some of that, since the final set of instructions that the thing needs to execute should be somewhat smaller. Translating further down to bytecode (and perhaps SIMD bytecode, since most of these operations should be parallelish) should be doable and hopefully keep the speed sufficient to justify the flexibility on offer.

For Eval, I’m planning to build a bunch of different eval functions, but I’m particularly interested in NNUE and messing around with different architectures using the NNUE concept. More SIMD in my future.

Ideally I’d like to get to the point where I have a suite of integration tests that:

  1. Use WitchLang to load a PGN, do evaluation to it, and report statistics about the results.
  2. Use WitchLang to perft from multiple different positions and compare statically to stockfish
  3. Use WitchLang to generate a random position by playing random moves, then dynamically compare perft results with stockfish to the maximum depth achievable in a reasonable time.

Those three tests should fully exercise any movegen code I’m using; especially if I can set the number of PGNs pretty high.

2136 - pgn

I ticked off #1 of the above and got past the ambiguity with sliding pieces. I even got to use some of the old bitboard implementation.

I need to do some work to get variations parsing and the like, but I think the move generation is probably ‘good enough’ that I shouldn’t run into an ambiguity problem again.

I’m not tempting the gods, you’re tempting the gods!