mirror of
https://github.com/StewBC/cc65-Chess.git
synced 2026-10-25 01:02:25 +00:00
The old engine was weak for one structural reason. cpu_ScorePieceSubTree
looked like minimax but had a branching factor of one: at each level it
followed only the single reply a static heuristic ranked first, so it
evaluated one predicted line per root move and never saw a refutation the
heuristic missed. Two things compounded it - the root considered only one
move per piece, and the scoring functions returned move desirability rather
than position value, which is not a quantity minimax can validly accumulate
across plies.
What replaces it:
engine.c 0x88 board, make/unmake against a per-ply state stack, legal
move generation, and attack queries by ray-cast. The stored
attack database is gone - eng_IsAttacked walks outwards from a
square instead of rebuilding 64 squares' worth of state after
every trial move.
eval.c material and piece-square tables as a pure position value,
kept as a running total updated incrementally by make/unmake.
search.c iterative-deepening negamax with alpha-beta, MVV-LVA and killer
ordering, and a quiescence search over captures.
board.c becomes the adapter between engine and display; plat.h and the 0-63
tile numbering are untouched, so no platform file needed editing - including
the three that cannot be built here.
Verified: perft exact on all five reference positions to depth 5, and to
depth 6 on the two that publish one. Against the engine it replaces, at that
engine's strongest setting: 6 wins, 0 losses.
Smaller than what it replaces despite doing far more - 31129 bytes total on
the c64 at optspeed against 31543 for the two engines' worth of machinery it
supersedes, and 514 bytes less RAM. All five buildable targets fit.
tests/ carries the harness this was developed against: perft, a game fuzzer,
castling scenarios, an internal match runner, on-target C64 benchmarks, and
a UCI adapter for playing external engines. It stops being gitignored here -
the exclusion was scaffolding added during the rework to keep git status
quiet, and the harness is the evidence for everything above.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
1.7 KiB
C
69 lines
1.7 KiB
C
/*
|
|
* genbook.c
|
|
* cc65 Chess - test support
|
|
*
|
|
* Writes an EPD opening book on stdout, for a match runner to start games
|
|
* from. The engine is deterministic, so without a book a match is one game
|
|
* repeated N times - see the note at the top of tests/uci.c.
|
|
*
|
|
* The positions are generated the same way tests/match.c generates its own,
|
|
* on purpose: a few plies of random legal non-capturing moves, one fixed seed
|
|
* per opening. That keeps an external match commensurable with the internal
|
|
* one, and it is reproducible without a page of hand-typed FENs to get wrong.
|
|
*
|
|
* ./genbook [count] [plies] > book.epd
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "types.h"
|
|
#include "globals.h"
|
|
#include "engine.h"
|
|
#include "testutil.h"
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int main(int argc, char **argv)
|
|
{
|
|
int count = (argc > 1) ? atoi(argv[1]) : 256;
|
|
int plies = (argc > 2) ? atoi(argv[2]) : 4;
|
|
int i;
|
|
|
|
for(i = 0; i < count; ++i)
|
|
{
|
|
char side = SIDE_WHITE, fen[90];
|
|
int ply;
|
|
|
|
srand(1000 + i);
|
|
eng_SetStartPosition();
|
|
|
|
for(ply = 0; ply < plies; ++ply)
|
|
{
|
|
t_engMove moves[ENG_MAX_MOVES];
|
|
t_engUndo undo;
|
|
char n = eng_GenMoves(side, moves, ENG_MAX_MOVES);
|
|
char tries, done = 0;
|
|
|
|
// no captures: a book position where one side is already a piece
|
|
// up measures the opening set rather than the engines
|
|
for(tries = 0; tries < n * 2 && !done; ++tries)
|
|
{
|
|
char pick = rand() % n;
|
|
|
|
eng_Make(&moves[pick], &undo);
|
|
if(eng_IsAttacked(geKing[side], 1 - side) ||
|
|
NONE != (undo.m_captured & PIECE_DATA))
|
|
eng_Unmake(&moves[pick], &undo);
|
|
else
|
|
done = 1;
|
|
}
|
|
if(!done)
|
|
break;
|
|
side = 1 - side;
|
|
}
|
|
|
|
test_EngineGetFEN(side, fen);
|
|
printf("%s\n", fen);
|
|
}
|
|
return 0;
|
|
}
|