June 16, 2025
Removed the board.isRepetition() and replcaed with board.isRepetition(1), which is recommended for chess engines according to chess-lib
docs
Fixed some little things like still using my crappy self coded logger, etc.
Fixed the github issue about illegal moves in cutechess by modifying the uci function to handle the weird ahh castling representions cutechess uses (e8h8
instead of e8g8
for examepl).
My debugging efforts led to one (frankly unexpected) source for the undefined behavior - the start_uci function, which wasn't parsing the position startpos moves command right for some reason (and still isn't). Hopefully I'll have it fixed soon (in the pic left is stockfish)
Im not sure what I even did ...
Was in a trance-like state of coding flow (NOT VIBE CODING) lol
Well fixed a bug with the sorting that was introducing illegal moves, cleaned up unused #includes, worked more on debugging the original illegal move (with very helpful logging statements trust)
Working on debugging the illegal move
Shouldn't be happening since we delegate all movegen to chess-lib, maybe TT again :(
Did a little cleaning up as i should
got rid of the million pictures bloating my repo
FINALLY got the UCI i need to verify this bug (why i wrote the logger lol)
I realize i have -iq now since i could have just used spdlog or something instead of devoting 5 hours to writing my own inefficient-ahh logger
Maybe that's for later, but now i need to actually study (6 hr coding too much for 2 days lol)
Added, removed, then rewrote better a internal logging system :)
This took way way too long ...
finished with the issue prep phase (writing test code, etc.)
now time to actaully try solve it :D (wont put whole issue to preserve the guy's privacy)
working on transcribing the uci from the cutechess picture to something usable
did some minor readme updates and stuff while waiting for cutechess to run
Trying to deal with someone saying it makes illegal moves when used with cutechess,
using codespaces to get the linux environment. Hopefully the debug logs reveal something useful :)
Just cleaned up a little and trying to improve the drawing in winning positions thing
i have a fix thought out but too tired to implement
Worked on several python scripts to help parse logs (usually >6k lines(no not 6 or 7 get out) ) ...
IT TOOK ME WAY TOO LONG SINCE THE LICHESS-BOT LOGS ARE IN UTF 16 AND I DIDNT SPECIFY THAT CODEC AHHH
I fixed it!!!!!
reason was there were no time checks in place before writing to TT, so nested negamax calls may have been incomplete but we still wrote to TT.
Found another issue -> the minimal time the engine needs to not return bestmove 0000 has quadrypled (10 -> 40 ms), and got the d7d8q thing still happens with depth 1 and 43 nodes, shouldn't be too hard to debug
reorganized and cleaned up the repo mostly, looks way way better now
So found another issue lol
Going from m5 to -2.4
this is signaling something very very wrong
Also what the actual sigma is bestmove d7d8q
YESSSSSSSSSSSSSSSSSSSSSSSSSSS
I FINALLY FIXED IT
i added a mate cut-off in iterative deepening lol
it works on tests but not irl, i think thats an improvement /j
Adding logging to each move within negamax (only for TARGET_FEN)
Increased logging (useful logging only, i learned my lessons), have pinned it down to 1 negamax call, need to keep zooming in ... :( i really want to get to the bottom of this lol
Shaved down the MRE some more and found that it works when using go depth x but not with go depth wtime x btime y, this seems to be linked to some kind of corruption of moves within negamax.
been doing some work in codespaces and laptop, it seems the olden bug (no mate finding in specific position) doesnt happen on linux????????????
at least whatever distro gh codespaces uses
School has started :(, so I can't work on this anymore sadly
Final feature list:
negamax
a/b
qsearch
delta pruning
PSQT tables
king safety
middlegame/endgame eval changes
material (obv)
mobility eval
stalemate/checkmate/draw etc.
not much, but there are some valuable things I have learned along the way:
(1) always always SPRT after a new feature/change
(2) start minimal and write lots of unit tests
(3) read code of classic engines such as Fruit or Crafty
(4) what the stack and heap are lmao
Also I want to say thanks to Hack Club/SoM for helping me build this project, along with the chess programming wiki, disservin's chess-lib and several discords(engine programming, stockfish, lichess, etc.) that really helped me learn the algorithms and good code practices i needed to make my engine at least decent (~1600-1700 lichess)
Still gathering data on when and why it fails to try and fix it. (i know, this is taking a while)
New test harness, does same test 20 times to see if the results are consistent
It has confirmed the worst (randomly fails around 50% of the time ...)
The M1 bug is only happening some of the time (tests flaky somehow???) but in real games also NPS is variable so .... It happens only when time management is on it appears, but at least 20/30 tests at a time are needed because it only fails sometimes. School has started so might have to ship soon, wish me luck :D
(still working on fixing the no finding m1 bug)(yes i know its been a while)It appears even without the TT, although it is finding the correct move (without the TT), the eval is 9999 then changes to 0 for some reason. This is concerning for obvious reasons - its evaluating the m1 pos as drawn??????
yayayay UCI Depth
finally works :D
debugging the right way (1000 breakpoints), still working on that one bug lol
its getting worse...
It find the mate in debug build but not release build
i am considering hiring a priest for exorsion
Seems negamax is storing a bad TT entry (for an NodeType::EXACT node) at move 9, which is impacting the search at move 10 to not return the optimal move d4d3 (checkmate) , instead giving the subpar c2a1 (+4.30).
lots of debugging, still can't find the problem :(. Will sleep on it and work more tmrw
working on ironing out a few more bugs i found by parsing through the lichess-bot logs, first of all it missing pawn/knight checkmates due to the transposition table (MISSING MATES IN ONE WTF) D:. Needs to be fixed, maybe due to incorrect application of lowerbound/upperbound nodes from TT? Just a speculation ofc
finally fixed the bug of the engine falsely thinking the game is over and returning chess::Move::NOMOVE/0000 when its completely winning and then losing on time because of that D:
See https:// github.com/montypylons/mihansolobot/issues/2.
yobeee i fixed it by ~'ing (invert) the sideToMove whenever using it with the TimeManager class (have to investigate where else this may be causing problems)
i think i found the problem ... for some reason Color::WHITE is defined as 0 ?????
ok some kind of black magic is going on here (look at picture, i might be cooked chat)
trying to debug why the timemanager is reserving time for the wrong color
fixed some misc UCI bugs and stuff (still some left as per picture:()
Added evaluation hash table (gets a decent amount of hits, speedup), tried mobility hash table but 0 hits every time idk what i was thinking, changed the Zobrist hash recomputations (zobrist()) to using the incrementally updated one (hash()) (i didn't read the docs until now lol) and did some minor formatting etc. (ik picture is the anathema of chess engine developers but its working lol)
added some documentation cause ill forget this all when i go to school lol
minor optimizations (Well pretty major actually), moved legalmove gen after possible stand pat cutoff in qsearch, etc. Went from 11.24 s (unit test) to 7.31 s with this and other optimizations (MVV-LAA in qsearch for one), and turned off search extensions for now.
i fixed the overflow, there was no limint on extensions but now it takes forever to run :(
(before engine tests ran in like 4 sec)
working on adding passed pawn extensions to fix the weird endgame bugs, but its also crashing the engine now
gods have mercy ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜
YESSS FINALLY REPRODUCED ONE OF THE BUGS I SAW IN ITS LICHESS GAMES
(now i have to figure out how to fix it :O)
trying to track down why it draws completely winning positions
trying to find why it fails in the endgame (maybe delta issue?)
tried out some other hash sizes (largest was 229 = 16 GB around), decreases perf so sticking with the 223 entry hash. (~ 8M entries at 32 bytes per entry)
even bigger hash (8 mil entries)
experimenting with bigger hash
added delta pruning, makes it much faster, and some minor optimizations
tried to make the TT faster but failed
bruhhhh its too slow it seems so the old version is stronger, cause of mobility eval slowing everything down :(
added TT to qsearh
removed threading for mobility since it slows it down, not speed up suspecting overhead in starting the threads, etc
minor optimizations
yay removed the makeNullMove by gettting chess.hpp to expose both
template <MoveGenType mt = MoveGenType::ALL>
void static legalmoves(Movelist &movelist, const Board &board, int pieces)
template <Color::underlying c, MoveGenType mt>
static void legalmoves(Movelist &movelist, const Board &board, int pieces);
publicly so i can use chess::Color::BLACK instead of flipping board state using null moves, also added some minor optimizaions
adding threads
fixed some bugs in mobility and added some profiling to see how to optimize this more, thinking about multithreading this function since its stateless and can easily be made thread-safe
working on adding mobility eval, its not really working rn cause i need to modify the chess.hpp library to make this reasonably fast, since it generates the bitboards of moves for each piece but doesn't make them accessible to the public.
refactoring negamax, making code simpler
removed nmp and readded test (nmp caused -200 Elo)
added null move pruning (idk if it helps yet)
meh refactored a lot
Added butterfly boards/history heuristic
added some new testing
fixed sm bugs and stuff with time management/iterative
True iterative deepening added (searches until time runs out) Before it was just upto depth 5, not good in situation where you have lots of time and want to use it
Adding time management
ADDED ITERATIVE DEEPENING, MASSIVE SPEED GAIN (5x faster from 1550ms to 300 ms)
still unit tests for iter, mvvlva, transpo, and qsearch not here lol
workign on the transposition table
Quiescence search implemented (yay!)
We got MVV_LAA move ordering!!!, around 40%-50% speedup (700 ms down from around 1400 ms)
no ext, king safety works !!!!
trying to add search extensions
FINALLY FIXED THE BUG
std::numeric_limits<int>::min() is one smaller than -max, which causing wraparound, fixed by adding one lol
finding Material bug
Optimized the program by using more const & refs in function arguments but still trying to find why its dropping so much material
Quality of life upgrades -> refactored code, added logging with spdlog, and added unit tests (only for evaluation so far tho)
Bug is in evaluate function, it is actually a piece of work
i am on the verge of an existensial crisis
Moved everything to C++ and ran a basic test, huge improvement in speed. I miss you, Python, but you're just too slow ðŸ˜.
trying to find the PHANTOM ROOK
Tryign to find why C++ SLOWS IT DOWN, while its supposed to be FASTTTT.
Finally got c++ eval working to the bare minimum, not pushed to main lichess bot yet tho
Fixed checkmate bug
SPRT tests on a new heuristic!
added UCI parsing so can be used with SPRT testing and cutechess-cli
got basic functionality
The classic Tower of Hanoi game in terminal, coded in Rust. With autosolve algorithm, see if you can beat the computer!
Quiescence search fleshed out with features reccomended by chess programming wiki [helps calculate long tactics to avoid loss of material/checkmate]
Made the basic negamax, a\b, and eval functions.
[NOTICE: ONLY TAKES 'REAL TIME' GAMES] Mostly built from scratch, except for reliancy on (a) Disservin's chess-lib (b) a Polyglot reader library and (c) magic_enum. May not always be online ... Uses Negamax with alpha/beta pruning, a material/positional eval function, quiescence search, and transposition table. NNUE eval function coming soon!
This was widely regarded as a great move by everyone.