summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-08-24 19:31:36 -0700
committerScott Gasch <[email protected]>2026-08-24 19:31:36 -0700
commit29d73f4dd59554a349aa8e86e5ea65f28c912ec9 (patch)
tree05e8dcbe6eb3c2f6d8bfd7c8065c250b2734254c /src
parentc5ca1a37b0614f5cb55499692a7f61775f81d1eb (diff)
Started doing texel eval tuning.
Diffstat (limited to 'src')
-rw-r--r--src/CLAUDE.md257
-rwxr-xr-xsrc/chess.h2
-rwxr-xr-xsrc/command.c191
-rwxr-xr-xsrc/eval.c970
-rw-r--r--src/fathom/LICENSE24
-rw-r--r--src/fathom/stdendian.h286
-rw-r--r--src/fathom/tbchess.c1050
-rw-r--r--src/fathom/tbconfig.h150
-rw-r--r--src/fathom/tbprobe.c2715
-rw-r--r--src/fathom/tbprobe.h399
-rwxr-xr-xsrc/main.c10
-rw-r--r--src/position.binbin24 -> 0 bytes
-rw-r--r--src/position.lrn5
-rwxr-xr-xsrc/suite_diff.pl2
-rw-r--r--src/trial.ep_3520
-rw-r--r--src/unix.c144
16 files changed, 5622 insertions, 4103 deletions
diff --git a/src/CLAUDE.md b/src/CLAUDE.md
new file mode 100644
index 0000000..881b062
--- /dev/null
+++ b/src/CLAUDE.md
@@ -0,0 +1,257 @@
+# typhoon chess engine
+
+A chess engine by Scott Gasch ([email protected]), originally started 2004.
+Previously named "monsoon" -- any old references to that name mean this same
+codebase. Speaks the xboard/WinBoard protocol. FreeBSD host, 64-bit.
+
+## Building
+
+`build.sh`'s OS detection (`expr $OSTYPE = "darwin"`) is broken in this shell
+environment and falls through to a 32-bit `gcc`-based profile that doesn't
+exist here (no `gcc`, and the resulting `.o` files are architecture-mismatched
+against everything else). **Don't use build.sh as-is.** Build directly with:
+
+```sh
+gmake -j5 GENETIC=1 PERF_COUNTERS=1 MP=1 SIXTYFOUR=1
+```
+
+This uses `clang`/`clang++` (already the GNUmakefile default) and produces a
+64-bit binary matching the historically-built one. After changing any header
+touched by many translation units, `gmake clean` first to avoid 32/64-bit
+object mismatches at link time.
+
+## Running / xboard protocol basics
+
+No command-line flags are required for interactive use; the binary drops into
+an xboard-protocol REPL on stdin/stdout. Key commands used during development:
+
+- `force` -- stop the engine from auto-playing; you control both sides' moves.
+- `setboard <fen>` -- set the position.
+- `eval` -- print `Static eval: <score>` (calls `Eval()` directly, no search).
+- `evaldna dump` / `evaldna read <file>` / `evaldna write <file>` -- the
+ eval-constant import/export system (`g_EvalDNA` in eval.c). `evaldna` alone
+ (no subcommand) just prints usage -- you need `evaldna dump` explicitly.
+- `sd <n>` / `st <n>` -- fixed depth vs. fixed time search limits.
+- `go` -- search and play one move for whichever side is on move, then stop
+ (when paired with `force` after). Repeated `go`/`force` cycles correctly
+ drive a full self-play game -- the engine tracks its own position across
+ calls, no need to feed the opponent's move back manually.
+- `script <file>` -- run a list of commands from a file, used for test suites
+ (see ECM below). Prints solved/unsolved stats at the end.
+- `--dnafile <path>` (startup flag) or `evaldna read <path>` (runtime) load a
+ DNA file produced by tuning; `--egtbpath <path>` or `set EGTBPath <path>`
+ configure Syzygy tablebase lookup.
+
+**Default EGTB path is hardcoded** in `main.c:297` to `/zscratch/egtb`, used
+whenever `--egtbpath` isn't passed. That directory currently has full 5-man
+WDL+DTZ Syzygy coverage but is **missing the WDL half of its 6-man set** (only
+`.rtbz`/DTZ files exist for 6-man combos) -- `init_tb()` in
+`fathom/tbprobe.c:752` requires the WDL file to exist before registering a
+combination at all, so every 6-man entry is silently skipped and the engine
+reports "up to 5 men" even though 6-man `.rtbz` files are sitting right there.
+Not a config issue; the fix is downloading the missing 6-man `.rtbw` files.
+
+## Testing: the ECM tactical suite
+
+`tests/ecm.ep_` is a 3517-line / 881-problem EPD tactical test suite.
+`test.sh <epd-file> <seconds-per-move>` runs it and diffs against
+`lastrun.log` via `suite_diff.pl`. Two things to know:
+
+1. **`suite_diff.pl`'s shebang (`#!/usr/bin/perl`) is wrong on this box** --
+ perl lives at `/usr/local/bin/perl`. Invoke it as `perl ./suite_diff.pl
+ <new.log> <lastrun.log>` rather than `./suite_diff.pl`.
+2. **Prefer `sd <depth>` over `st <seconds>` for before/after eval
+ comparisons.** A time-based limit lets identical positions reach different
+ search depths across runs purely from incidental machine load (this
+ session saw large timing swings from unrelated processes/scrubs) --
+ `sd 10` (or similar) holds search effort constant so a solve-rate
+ difference is actually attributable to the eval change being tested.
+
+Current baseline (`lastrun.log`, `st 1`, unmodified eval constants):
+**606/879 solved.** A first full DNA-tuning pass against 600k TWIC positions
+raised this to **622/879** (see `eval_tune/`).
+
+`Trace()` (used for almost all engine output, including ECM's per-problem
+results) only `fflush()`s stdout, **not** the logfile -- `Log()`/`Bug()` do
+flush the logfile every call, but `Trace()` doesn't. A `--logfile` file can
+lag well behind actual progress while a run is in flight; it catches up fully
+once the process exits. Don't trust a logfile's line count as a live
+progress indicator for a running batch job.
+
+## Eval tuning pipeline (`eval_tune/`)
+
+`tune_eval_dna.py` is a Texel-style tuner: drives `typhoon` as an
+xboard-protocol subprocess, fits `g_EvalDNA`'s ~1870 raw constants (reduced to
+~468 after collapsing cells that share a starting value -- see caveat below)
+against TWIC game outcomes via sigmoid-squared-error + coordinate descent.
+`dna_diff.py` renders a human-readable, per-array diff between two `.dna`
+files (with 8x8 grids for the board-shaped location tables) so you can
+actually see what a tuning run changed. Position pools are cached under
+`position_cache/` keyed on source-file mtime+size+filter args, since a
+500k-600k position PGN scan takes ~20 minutes.
+
+**Two real bugs were found and fixed this session, both in `command.c`, not
+in the Python tooling:**
+
+1. **`EvalCommand` used to malloc + fully zero (`InitializeSearcherContext`,
+ which memsets the whole ~75MB `SEARCHER_THREAD_CONTEXT` -- `rgPawnHash`
+ and `rgEvalHash` are embedded arrays inside that struct, not
+ separately-managed heap buffers) on every single `eval` call, then free
+ it.** Fixed to keep one persistent context and use the cheap
+ `ReInitializeSearcherContext` (just repositions + zeros counters) on
+ subsequent calls -- ~1000x throughput improvement for scripted eval
+ scoring.
+2. **That persistent context's embedded eval hash was never invalidated when
+ new DNA was loaded**, so after the fix above, a position scored once under
+ any DNA would return that *same cached score forever*, silently ignoring
+ every later `evaldna read`. Fixed via a global `g_uDnaGeneration` counter
+ (bumped in `EvalDnaCommand` on successful load, checked in `EvalCommand`)
+ that forces exactly one full re-init per DNA change, not per position.
+ **If this regresses, tuning results will look like it "converged" almost
+ immediately with implausibly little movement -- that's the symptom, not
+ genuine convergence.** Verify by perturbing a few known-live parameters
+ and confirming the reported error actually changes.
+
+**Known limitation, not yet fixed:** the distinct-value grouping used to
+shrink 1870 raw cells to ~468 tunable parameters ties together *any* cells
+that start out numerically equal, for whatever reason -- true mirror
+symmetry, an intentional-but-asymmetric design choice (e.g.
+`KING_INITIAL_COUNTER_BY_LOCATION`'s rank-8 row `1,0,0,0,1,0,0,1` flags
+a1/e1/h1 specifically, not a geometric mirror), or pure incidental coincidence
+(e.g. `PAWN_CENTRALITY_BONUS`'s legitimate "no bonus" squares happening to
+share the value `0` with unrelated off-board padding cells). The padding case
+is harmless (those indices are never read during real eval) but the
+coincidental-equality case is a real, unaddressed source of noise in the
+parameter space, most visible on small/noisy training runs (sentinel `-1`
+placeholder cells in `TRADE_PIECES` drifted to an arbitrary shared value on a
+25k-position smoke test; they stayed put on the full 600k run).
+
+**`Engine`/`EnginePool` in `tune_eval_dna.py` must be used as a context
+manager (`with Engine(...) as e:`) or have `.quit()` called explicitly.**
+Each spawned engine holds a kernel SysV semaphore
+(`semget(IPC_PRIVATE, ...)` in `unix.c`) for its input-dispatch loop, which is
+**only released by a graceful `quit`, not by the OS when the process is
+killed**. `kern.ipc.semmni` (max semaphore sets system-wide) is only 50 on
+this box; a session's worth of force-killed test engines can leak past that
+limit, after which *every new engine* silently falls back to a 100ms-per-
+command polling path (`_WaitUntilTheresInputToRead` in `input.c:63`) instead
+of the fast semaphore wait -- a ~1000x slowdown that looks exactly like "the
+machine is under heavy load" and cost significant debugging time before the
+real cause (`ipcs -s`, then `ipcrm -s <id>` for each leaked one) was found.
+
+## Automated eval-tuning loop (`eval_tune/cycle.sh`)
+
+A later session built a full wash/rinse/repeat pipeline on top of the manual
+tuning tools above, so a cycle goes baseline -> tune -> head-to-head gate ->
+bake-in-if-better, repeatable indefinitely against a growing game pool.
+
+- **`filter_pgn.py <in.pgn> <out.pgn> --min-elo 2400 --min-ply 40`** -- fast
+ text-only pre-filter (no python-chess board replay, so it runs in ~100s
+ over a multi-GB pool) that drops short/low-rated games before they ever
+ reach `tune_eval_dna.py`'s slower, board-replay-based filtering. Confirmed
+ most of a raw TWIC pool's mass is short draws/low-rated games: filtering
+ the full merged `twic.pgn` (4,099,094 games) down to >=2400 Elo / >40 ply
+ kept 642,268 games (556MB) -- that's `twic_filtered.pgn`, the pool actually
+ used for tuning and match play now.
+- **`match_play.py <engine> <baseline.dna> <candidate.dna> --pgn <pool> --games N --sd D`**
+ -- head-to-head gate match, N games (games/2 unique openings, each played
+ twice with colors swapped, so opening luck cancels), fixed search depth
+ (not clock time, same sd-over-st reasoning as ECM below). Prints
+ `CANDIDATE_SCORE=... LOWER95=...` -- **gate on `LOWER95 >= 0.5`, not the raw
+ score.** Search is non-deterministic (MP=1 multithreaded), confirmed live:
+ two engines loaded with *identical* DNA still split games unevenly at
+ small N, so a bare score >=0.5 is not evidence of a real improvement, only
+ a 95%-confidence lower bound that still clears break-even is.
+ Three real bugs were found and fixed getting this to give sane numbers:
+ 1. **The opening book was still live**, so early moves in every game
+ were book lookups that never touched eval at all -- defeats the
+ purpose of a match meant to compare eval quality. Fixed by pointing
+ `book name` at a nonexistent file each game; `root.c`'s
+ `g_uBookProbeFailures >= 3` gate then disables book probing for the
+ rest of that game after 3 cheap failed opens.
+ 2. **Engines were spawned with no `--hash`/`--cpus` at all**, so every
+ game ran on `main.c`'s memset-zero default (a 65536-entry hash table)
+ instead of the 256m used everywhere else in this project's own
+ testing -- worse move ordering, much more re-search in complex
+ positions. Fixed by passing `--hash 256m --cpus 1` explicitly (added
+ an `extra_args` param to `tune_eval_dna.py`'s `Engine` class for
+ this).
+ 3. **Every engine process also defaulted to a *shared* `typhoon.log`**
+ in cwd (same memset-zero default). With `--workers N` running
+ `2*N` concurrent engines, they were all racing on
+ `BackupFile()`-then-`fopen(wb+)` at startup and `fflush()`ing that
+ one file on every `Log()`/`Bug()` call -- real lock contention,
+ observed live as unexplained match slowdown. Fixed with
+ `--logfile -`, which `main.c` special-cases to skip file logging
+ entirely (no rename race, no fopen, no fflush).
+ 4. Separately (not a match_play.py bug but cost real wall-clock time
+ chasing it as one): `sample_openings()`'s original implementation did
+ a sequential `chess.pgn.read_game()` scan from byte 0 of the pool
+ file to pick even a couple of random openings -- minutes of wasted
+ I/O/parsing on a 556MB pool. Rewritten to seek to random byte
+ offsets and parse just the one game found there, cached the same way
+ as `tune_eval_dna.py`'s `position_cache/` (keyed on pool identity +
+ params) under `opening_cache/`.
+ **If a match run seems to hang or take far longer than a lone `sd N`
+ search should:** check for leftover engine processes from a previous
+ killed/interrupted run first (`ps aux | grep typhoon`) before assuming a
+ new bug -- a stray process from an earlier debug session silently eating a
+ full CPU core was mistaken for a pipeline bug for a while before being
+ found and killed.
+- **`bake_dna.py <candidate.dna> --eval-c eval.c --out eval.c`** -- writes a
+ winning candidate's values into `eval.c`'s array initializers *in place*,
+ preserving all formatting/comments/8x8 grid layout (regex-replaces only
+ the numeric literals found outside comments, in `g_EvalDNA[]` order, so a
+ resulting `git diff` shows only the numbers that actually changed).
+ Round-trip verified: dumping the currently-compiled-in DNA and baking it
+ right back produces a byte-identical `eval.c`. **Positional, not
+ name-matched** -- a `.dna` file only works against the exact `eval.c`
+ revision it was tuned against; a line-count mismatch against the current
+ `g_EvalDNA[]` aborts loudly rather than silently misassigning values.
+- **`dna_trend.py cycle1.dna cycle2.dna ... [--cycles-dir eval_tune/cycles]`**
+ -- across a chronological sequence of *kept* candidates, flags whether
+ each raw DNA cell is trending (every step moves it the same direction --
+ real signal) or flip-flopping (moves a lot, nets out near zero -- chasing
+ sampling noise in that cycle's position batch). Worth running every few
+ kept cycles; a consistently flip-flopping cell is a candidate to exclude
+ from future tuning passes rather than let it keep eating budget on noise.
+- **`cycle.sh [pgn] [n_games] [workers] [max_positions] [max_passes] [sd_depth]`**
+ -- wires all of the above into one cycle: dump baseline -> tune -> gate
+ match -> bake-in-and-rebuild if `LOWER95 >= 0.5`, else discard and leave
+ `eval.c` untouched. **Never runs `git commit`** -- a win leaves `eval.c`
+ modified-but-uncommitted for manual review, by design.
+ `sd_depth` defaults to 10; a dry run at that depth was observed still
+ running after 15+ minutes on one game before the bugs above were found --
+ use a shallow depth (4-6) for pipeline-wiring smoke tests, not 10.
+- **`evaldna write <file>` refuses to overwrite an existing file** (silent
+ `Error writing dna file.` with no explanation of why) -- `WriteEvalDNA` in
+ eval.c does `if (SystemDoesFileExist(...)) goto end;` rather than
+ clobbering. Delete the target first when re-dumping a baseline.
+- **Watch for apples-to-oranges ECM comparisons across depths/time
+ controls.** A baseline solved-count recorded at `st 1` is not a fair
+ comparison point against a candidate scored at `sd 20` -- rescoring the
+ baseline at the *same* fixed depth as the candidate revealed a real gap
+ (711 vs 707 at `sd 20`, both far below the apparent 606-vs-711 jump you'd
+ get comparing against the old `st 1` number) that was noise-level, not the
+ large improvement it first looked like. Always diff ECM numbers taken at
+ the same `sd` depth.
+
+## Environment notes
+
+- Shared, multi-user FreeBSD box with genuinely variable load (other Claude
+ Code sessions, a `bhyve` VM, periodic `zpool scrub` on both `zroot` and
+ `zscratch`). Don't trust a single throughput measurement without a
+ back-to-back comparison under the same conditions; this session saw the
+ same benchmark vary by 10x+ run to run for reasons that turned out to be
+ the semaphore leak above, not genuine machine contention.
+- `/zscratch/egtb` and `/usr/home/scott/typhoon/pgn/twic.pgn` are the two
+ large external resources this codebase's tooling depends on. `twic.pgn`
+ was originally 554,135 games (up through TWIC issue 608, fetched by the
+ long-dead `pgn/twic.pl`); a later session fetched all subsequent issues
+ (920-1658) directly from theweekinchess.com (its WAF blocks bare `wget`,
+ needs a real browser `User-Agent` + `Accept` header via `curl`) and merged
+ them in, growing it to 4,099,094 games (3.5GB). Note issues 609-919 are
+ still a gap (fetched range starts at 920) if completeness ever matters.
+ `pgn/twic_filtered.pgn` (642,268 games, 556MB, >=2400 Elo / >40 ply, via
+ `filter_pgn.py`) is the pool actually used for tuning/match-play now, not
+ the raw file.
diff --git a/src/chess.h b/src/chess.h
index 562aca8..245a3b0 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -1498,7 +1498,7 @@ UtilPanic(ULONG uPanicCode,
//
// main.c
//
-#define LOGFILE_NAME "typhoon.log"
+#define LOGFILE_NAME "/usr/local/tmp/typhoon.log"
extern FILE *g_pfLogfile;
void
diff --git a/src/command.c b/src/command.c
index d528994..4f81b10 100755
--- a/src/command.c
+++ b/src/command.c
@@ -32,6 +32,11 @@ Revision History:
#define MAX_ARGS 32
int g_eModeBeforeAnalyze = -1;
+// Bumped by EvalDnaCommand on every successful `evaldna read`/`load`;
+// EvalCommand compares against this to know its persistent eval-hash
+// cache needs clearing (see EvalCommand for details).
+ULONG g_uDnaGeneration = 0;
+
typedef void (COMMAND_PARSER_FUNCTION)(CHAR *szInput,
ULONG argc,
CHAR *argv[],
@@ -497,19 +502,175 @@ Return value:
**/
{
- SEARCHER_THREAD_CONTEXT *ctx;
+ // rgPawnHash/rgEvalHash are embedded arrays inside
+ // SEARCHER_THREAD_CONTEXT (tens of MB), so allocating fresh +
+ // InitializeSearcherContext's full memset on every call here was
+ // paying that cost per invocation. Keep one persistent context
+ // for the life of the process and use the cheap
+ // ReInitializeSearcherContext (memmove position + zero counters
+ // only) on every call after the first, same pattern the real
+ // search path uses across moves.
+ //
+ // CORRECTNESS: ReInitializeSearcherContext does NOT clear
+ // ctx->rgEvalHash, so a stale score cached under previously-loaded
+ // DNA constants would otherwise be returned forever for any
+ // position hit more than once -- silently ignoring every
+ // subsequent `evaldna read`. g_uDnaGeneration (bumped by
+ // EvalDnaCommand on a successful load) is compared here so a DNA
+ // change forces exactly one full re-init (i.e. one eval-hash
+ // clear per reload, not per position) instead of a stale hit.
+ static SEARCHER_THREAD_CONTEXT *ctx = NULL;
+ static ULONG uLastSeenDnaGeneration = (ULONG)-1;
SCORE i;
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- if (NULL != ctx)
+ if (NULL == ctx)
{
+ ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
+ if (NULL == ctx)
+ {
+ Trace("Out of memory.\n");
+ return;
+ }
InitializeSearcherContext(pos, ctx);
- i = Eval(ctx, -INFINITY, +INFINITY);
- Trace("Static eval: %s\n", ScoreToString(i));
- SystemFreeMemory(ctx);
- } else {
- Trace("Out of memory.\n");
+ uLastSeenDnaGeneration = g_uDnaGeneration;
}
+ else if (uLastSeenDnaGeneration != g_uDnaGeneration)
+ {
+ InitializeSearcherContext(pos, ctx);
+ uLastSeenDnaGeneration = g_uDnaGeneration;
+ }
+ else
+ {
+ ReInitializeSearcherContext(pos, ctx);
+ }
+ i = Eval(ctx, -INFINITY, +INFINITY);
+ Trace("Static eval: %s\n", ScoreToString(i));
+}
+
+
+COMMAND(QSearchCommand)
+/**
+
+Routine description:
+
+ This function implements the 'qsearch' engine command.
+
+ Usage:
+
+ qsearch
+
+ This command takes no arguments and causes the engine to run
+ a quiescence search on the current board position and print
+ the resulting score. Unlike `eval` (a static evaluation with
+ no search at all), this resolves captures/checks/promotions
+ first, the same way the real search does immediately before
+ calling Eval() -- so it's a much better proxy for "is this
+ position actually quiet" than comparing SEE-based capture
+ analysis to a static score.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ // Same persistent-context + DNA-generation-invalidation pattern as
+ // EvalCommand (see its comment for the full rationale) -- this
+ // command is meant to be called at corpus scale from the eval
+ // tuner, so paying a fresh ~75MB memset per call would be the
+ // same 1000x throughput hit that command had before it was fixed.
+ static SEARCHER_THREAD_CONTEXT *ctx = NULL;
+ static ULONG uLastSeenDnaGeneration = (ULONG)-1;
+ CUMULATIVE_SEARCH_FLAGS *pf;
+ PLY_INFO *pi;
+ SCORE i;
+
+ if (NULL == ctx)
+ {
+ ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
+ if (NULL == ctx)
+ {
+ Trace("Out of memory.\n");
+ return;
+ }
+ InitializeSearcherContext(pos, ctx);
+ uLastSeenDnaGeneration = g_uDnaGeneration;
+ }
+ else if (uLastSeenDnaGeneration != g_uDnaGeneration)
+ {
+ InitializeSearcherContext(pos, ctx);
+ uLastSeenDnaGeneration = g_uDnaGeneration;
+ }
+ else
+ {
+ ReInitializeSearcherContext(pos, ctx);
+ }
+
+ // QSearch is normally only ever entered from Search() one ply
+ // below the position it's evaluating (see search.c's "the only
+ // place Qsearch is entered" comment) -- it reads (pi-1)->mv to
+ // learn whether the side to move just got checked into this
+ // position, and asserts ctx->uPly > 0. To call it directly on
+ // the root position, synthesize that one piece of ply-0 state:
+ // a fake "previous move" whose only job is to carry the correct
+ // checking-move flag, so QSearch's in-check handling matches the
+ // position's actual, real InCheck() status instead of silently
+ // taking the no-standpat path incorrectly for a position that IS
+ // in check (or vice versa).
+ ctx->uPly = 1;
+ memset(&ctx->sPlyInfo[0].mv, 0, sizeof(MOVE));
+ if (TRUE == InCheck(&ctx->sPosition, ctx->sPosition.uToMove))
+ {
+ ctx->sPlyInfo[0].mv.uMove |= 0x80000000;
+ }
+
+ pf = &ctx->sSearchFlags;
+ pi = &ctx->sPlyInfo[ctx->uPly];
+ pf->fCouldStandPat[BLACK] = pf->fCouldStandPat[WHITE] = FALSE;
+ pf->uQsearchNodes = pf->uQsearchDepth = 0;
+ pf->uQsearchCheckDepth = QPLIES_OF_NON_CAPTURE_CHECKS;
+ pi->fInQsearch = TRUE;
+
+ // QSearch's recursive move loop checks WE_SHOULD_STOP_SEARCHING,
+ // which reads the process-global g_MoveTimer -- normally set up
+ // by SetMoveTimerForSearch() at the start of every real search.
+ // This command is a standalone call outside that path, so without
+ // this g_MoveTimer is whatever state a prior real search left it
+ // in (e.g. an already-expired hard limit). Save/restore around
+ // the call so a `qsearch` invoked between real searches (e.g.
+ // interactive use after `go`) doesn't leave the timer in a
+ // "think forever" state for whatever search comes next.
+ //
+ // g_uHardExtendLimit is a second process-global with the same
+ // problem, and the one actually responsible for a bogus +MATE
+ // score on every call before this fix: CommonSearchInit's
+ // "uQsearchDepth >= g_uHardExtendLimit" too-deep check (see its
+ // comment) fires immediately when this is left at its zero-
+ // initialized default, since it's normally only ever set once
+ // per real search, inside RootSearch (g_uIterateDepth * 4) --
+ // a path this standalone command never runs through. Set it
+ // generously (MAX_PLY_PER_SEARCH; qsearch's own capture-only move
+ // generation makes runaway recursion a non-issue) for the
+ // duration of the call, same save/restore reasoning as the timer.
+ {
+ MOVE_TIMER SavedMoveTimer = g_MoveTimer;
+ ULONG uSavedHardExtendLimit = g_uHardExtendLimit;
+ SetMoveTimerToThinkForever();
+ g_uHardExtendLimit = MAX_PLY_PER_SEARCH;
+ i = QSearch(ctx, -INFINITY, +INFINITY);
+ g_MoveTimer = SavedMoveTimer;
+ g_uHardExtendLimit = uSavedHardExtendLimit;
+ }
+ Trace("Qsearch score: %s\n", ScoreToString(i));
}
@@ -568,10 +729,16 @@ Return value:
Trace("Error (missing argument)\n");
return;
}
- if (!ReadEvalDNA(argv[2]))
+ if (!ReadEvalDNA(argv[2]))
{
Trace("Error reading dna file.\n");
} else {
+ // EvalCommand's persistent SEARCHER_THREAD_CONTEXT keeps
+ // its embedded eval hash alive across calls for speed; a
+ // DNA reload must invalidate stale cached scores from the
+ // old constants, which this generation bump signals it
+ // to do (see EvalCommand for the actual clear).
+ g_uDnaGeneration++;
Trace("Loaded dna file \"%s\"\n", argv[2]);
p = ExportEvalDNA();
Log("(New) dna: %s\n", p);
@@ -2188,6 +2355,12 @@ COMMAND_PARSER_ENTRY g_ParserTable[] =
TRUE,
FALSE,
"Learn a set of PSQT settings from a PGN file" },
+ { "qsearch",
+ QSearchCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run a quiescence search on the current position" },
{ "quit",
QuitCommand,
TRUE,
diff --git a/src/eval.c b/src/eval.c
index 48a21e0..92d1edc 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -17,7 +17,7 @@ Revision History:
$Id: eval.c 357 2008-07-03 16:18:11Z scott $
-**/
+**/
#include "chess.h"
@@ -38,16 +38,16 @@ const int g_iBehind[2] = { -1, +1 };
//
static SCORE TRADE_PIECES[3][17] =
{// 0 1 2 3 4 5 6 7 8 | 9..15 -- down piece count
- { -1, 90, 81, 73, 67, 62, 57, 52, 50, 50,50,50,50,50,50,50,-1},
- { -1, 125, 117, 109, 100, 91, 84, 78, 71, 66,66,66,66,66,66,66,-1},
- { -1, 150, 132, 124, 116, 109, 102, 94, 87, 77,77,77,77,77,77,77,-1},
+ { -1, 90, 89, 89, 59, 46, 25, 4, 50, 50,50,50,50,50,50,50,-1},
+ { -1, 125, 125, 109, 132, 123, 100, 78, 71, 66,66,66,66,66,66,66,-1},
+ { -1, 158, 180, 148, 92, 109, 70, 46, 87, 77,77,77,77,77,77,77,-1},
};
static SCORE DONT_TRADE_PAWNS[3][9] =
{// 0 1 2 3 4 5 6 7 8 -- up pawn count
- { -43, -15, 0, +3, +6, +10, +15, +21, +28 }, // 0
- { -63, -25, 0, +4, +9, +14, +19, +25, +32 }, // 1
- { -10, 0, 0, +7, +15, +20, +24, +29, +36 }, // 2
+ { -59, -63, 0, +3, +14, +18, +-9, +-19, +-20 }, // 0
+ { -31, 7, 0, +52, +41, +14, +19, +41, +32 }, // 1
+ { -58, 0, 0, +47, +-9, +4, +-24, +-19, +44 }, // 2
};
static ULONG REDUCED_MATERIAL_DOWN_SCALER[32] =
@@ -56,7 +56,7 @@ static ULONG REDUCED_MATERIAL_DOWN_SCALER[32] =
0, 0, 0, 0, 0, 0, 0, 0,
// Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
- 0, 1, 1, 1, 1, 1, 2, 3,
+ 0, 1, 1, 1, 1, 1, 10, 11,
// 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
// Q2R Q2Rm
@@ -72,30 +72,30 @@ static ULONG REDUCED_MATERIAL_UP_SCALER[32] =
8, 8, 8, 8, 8, 8, 8, 8,
// Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
- 8, 7, 7, 7, 7, 6, 6, 5,
+ 8, 15, 15, 15, 15, 6, 6, 5,
// 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
// Q2R Q2Rm
- 4, 3, 3, 3, 2, 2, 2, 1,
+ 12, 11, 11, 11, 10, 10, 10, 9,
// na Q2R2m QR4m na Q2R3m na na full
- 1, 1, 0, 0, 0, 0, 0, 0,
+ 9, 9, 0, 0, 0, 0, 0, 0,
};
static ULONG PASSER_MATERIAL_UP_SCALER[32] =
{
// none na na m na R 2m na
- 8, 8, 8, 8, 8, 8, 7, 7,
+ 16, 16, 16, 16, 16, 16, 15, 15,
// Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
- 7, 6, 7, 5, 4, 5, 4, 3,
+ 15, 14, 15, 13, 12, 13, 12, 11,
// 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
// Q2R Q2Rm
- 2, 2, 1, 1, 0, 0, 0, 0,
+ 2, 2, 9, 9, -8, -8, -8, -8,
// na Q2R2m QR4m na Q2R3m na na full
- 0, 0, 0, 0, 0, 0, 0, 0,
+ -8, -8, -8, -8, -8, -8, -8, -8,
};
COOR QUEENING_RANK[2] = { 1, 8 };
@@ -119,42 +119,42 @@ COOR JUMPING_RANK[2] = { 7, 2 };
// --Larry Kaufman, IM
// "Evaluation of Material Imbalance"
//
-static SCORE PAWN_CENTRALITY_BONUS[128] =
+static SCORE PAWN_CENTRALITY_BONUS[128] =
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,
- -8, 0, 0, 0, 0, 0, 0, -8, 0,0,0,0,0,0,0,0,
- -8, 0, 5, 5, 5, 5, 0, -8, 0,0,0,0,0,0,0,0,
- -8, 0, 5, 9, 9, 5, 0, -8, 0,0,0,0,0,0,0,0,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,8,8,8,8,8,8,8,
+ -8, 8, 8, 8, 8, 8, 8, -8, 8,8,8,8,8,8,8,8,
+ -8, 8, -3, -3, -3, -3, 8, -8, 8,8,8,8,8,8,8,8,
+ -8, 8, -3, 17, 17, -3, 8, -8, 8,8,8,8,8,8,8,8,
// -------------------------------------------------------------------
- -8, 0, 5, 9, 9, 5, 0, -8, 0,0,0,0,0,0,0,0,
- -8, 0, 5, 5, 5, 5, 0, -8, 0,0,0,0,0,0,0,0,
- -8, 0, 0, 0, 0, 0, 0, -8, 0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0
+ -8, 8, -3, 17, 17, -3, 8, -8, 8,8,8,8,8,8,8,8,
+ -8, 8, -3, -3, -3, -3, 8, -8, 8,8,8,8,8,8,8,8,
+ -8, 8, 8, 8, 8, 8, 8, -8, 8,8,8,8,8,8,8,8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,8,8,8,8,8,8,8
};
-static SCORE BACKWARD_SHIELDED_BY_LOCATION[128] =
+static SCORE BACKWARD_SHIELDED_BY_LOCATION[128] =
{
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
- -7, -5, -5, -7, -7, -5, -5, -7, 0,0,0,0,0,0,0,0,
- -5, -4, -4, -5, -5, -4, -4, -5, 0,0,0,0,0,0,0,0,
- -4, -3, -3, -4, -4, -3, -3, -4, 0,0,0,0,0,0,0,0,
+ 17, 3, 3, 17, 17, 3, 3, 17, 0,0,0,0,0,0,0,0,
+ 3, 12, 12, 3, 3, 12, 12, 3, 0,0,0,0,0,0,0,0,
+ 12, -3, -3, 12, 12, -3, -3, 12, 0,0,0,0,0,0,0,0,
// -------------------------------------------------------------------
- -4, -3, -3, -4, -4, -3, -3, -4, 0,0,0,0,0,0,0,0,
- -5, -4, -4, -5, -5, -4, -4, -5, 0,0,0,0,0,0,0,0,
- -7, -5, -5, -7, -7, -5, -5, -7, 0,0,0,0,0,0,0,0,
+ 12, -3, -3, 12, 12, -3, -3, 12, 0,0,0,0,0,0,0,0,
+ 3, 12, 12, 3, 3, 12, 12, 3, 0,0,0,0,0,0,0,0,
+ 17, 3, 3, 17, 17, 3, 3, 17, 0,0,0,0,0,0,0,0,
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
};
-static SCORE BACKWARD_EXPOSED_BY_LOCATION[128] =
+static SCORE BACKWARD_EXPOSED_BY_LOCATION[128] =
{
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
- -12, -9, -9, -11, -11, -9, -9, -12, 0,0,0,0,0,0,0,0,
- -9, -7, -7, -9, -9, -7, -7, -9, 0,0,0,0,0,0,0,0,
- -7, -6, -6, -7, -7, -6, -6, -7, 0,0,0,0,0,0,0,0,
+ -12, 7, 7, -27, -27, 7, 7, -12, 0,0,0,0,0,0,0,0,
+ 7, 1, 1, 7, 7, 1, 1, 7, 0,0,0,0,0,0,0,0,
+ 1, -6, -6, 1, 1, -6, -6, 1, 0,0,0,0,0,0,0,0,
// -------------------------------------------------------------------
- -7, -6, -6, -7, -7, -6, -6, -7, 0,0,0,0,0,0,0,0,
- -9, -7, -7, -9, -9, -7, -7, -9, 0,0,0,0,0,0,0,0,
- -12, -9, -9, -11, -11, -9, -9, -12, 0,0,0,0,0,0,0,0,
+ 1, -6, -6, 1, 1, -6, -6, 1, 0,0,0,0,0,0,0,0,
+ 7, 1, 1, 7, 7, 1, 1, 7, 0,0,0,0,0,0,0,0,
+ -12, 7, 7, -27, -27, 7, 7, -12, 0,0,0,0,0,0,0,0,
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
};
@@ -176,99 +176,99 @@ static SCORE BACKWARD_EXPOSED_BY_LOCATION[128] =
// are the one with the doubled pawns."
// --Larry Kaufman, IM
// "All About Doubled Pawns"
-//
+//
// Note: indexed by number of files with 1+ pawn on them.
-static SCORE DOUBLED_PAWN_PENALTY_BY_COUNT[4][9] =
+static SCORE DOUBLED_PAWN_PENALTY_BY_COUNT[4][9] =
{ // ------------ count of doubled+ pawns ------------
{// 0 1 2 3 4 5 6 7 8 : no majors alive
- +0, -32, -65, -99, -134, -170, -207, -222, -250
+ +0, -32, -41, -91, -102, -170, -207, -222, -250
},
{// : 1 rook
- +0, -23, -47, -76, -108, -144, -184, -200, -216
+ +0, -7, 1, -76, -76, -120, -184, -200, -216
},
{// : 2 rooks or 1 queen
- +0, -13, -23, -34, -46, -64, -86, -111, -138
+ +0, -21, -7, -18, -30, -48, -78, -111, -138
},
{// : all majors alive
- +0, -7, -13, -25, -39, -55, -73, -95, -121
+ +0, -7, -21, -25, -31, -47, -57, -95, -121
},
};
-static SCORE ISOLATED_PAWN_PENALTY_BY_COUNT[9] =
+static SCORE ISOLATED_PAWN_PENALTY_BY_COUNT[9] =
{// 0 1 2 3 4 5 6 7 8
- +0, -3, -7, -9, -16, -35, -50, -85, -100
+ +16, 5, -7, -33, -32, -19, -34, -85, -100
};
static SCORE ISOLATED_PAWN_BY_PAWNFILE[9] =
{
- 0, -7, -8, -9, -10, -10, -9, -8, -7
+ 0, 1, -24, -9, -18, -18, -9, -24, 1
};
static SCORE ISOLATED_EXPOSED_PAWN = -5;
-static SCORE ISOLATED_DOUBLED_PAWN = -11;
+static SCORE ISOLATED_DOUBLED_PAWN = 13;
//
// Note: -25% to -33% if the enemy occupies or controls the next sq.
//
-static SCORE PASSER_BY_RANK[2][9] =
+static SCORE PASSER_BY_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0,+162,+111, +62, +36, +18, +13, +0 }, // black
- { +0, +0, +13, +18, +36, +62,+111,+162, +0 } // white
+ { +0, +0,+194,+135, +54, +20, +-6, +-3, +0 }, // black
+ { +0, +0, +-3, +-6, +20, +54,+135,+194, +0 } // white
};
-static SCORE CANDIDATE_PASSER_BY_RANK[2][9] =
+static SCORE CANDIDATE_PASSER_BY_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0, +0, +48, +34, +22, +13, +9, +0 }, // black
- { +0, +0, +9, +13, +22, +34, +48, +0, +0 } // white
+ { +0, +0, +0, +48, +42, +14, +21, +17, +0 }, // black
+ { +0, +0, +17, +21, +14, +42, +48, +0, +0 } // white
};
// Note: x2
-static SCORE CONNECTED_PASSERS_BY_RANK[2][9] =
+static SCORE CONNECTED_PASSERS_BY_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0, +96, +74, +48, +21, +10, +5, +0 }, // black
- { +0, +0, +5, +10, +21, +48, +74, +96, +0 } // white
+ { +0, +0, +80, +58, +56, +29, +10, +21, +0 }, // black
+ { +0, +0, +21, +10, +29, +56, +58, +80, +0 } // white
};
-static SCORE SUPPORTED_PASSER_BY_RANK[2][9] =
+static SCORE SUPPORTED_PASSER_BY_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0, +60, +40, +13, +6, +3, +1, +0 }, // black
- { +0, +0, +1, +3, +6, +13, +40, +60, +0 } // white
+ { +0, +0, +92, +80, +21, +6, +11, +1, +0 }, // black
+ { +0, +0, +1, +11, +6, +21, +80, +92, +0 } // white
};
static SCORE OUTSIDE_PASSER_BY_DISTANCE[9] =
{// 0 1 2 3 4 5 6 7 8
- +0, +0, +7, +14, +21, +28, +34, +41, +55
+ +0, +0, +15, +30, +21, +28, +34, +41, +55
};
-static SCORE PASSER_BONUS_AS_MATERIAL_COMES_OFF[32] =
-{
+static SCORE PASSER_BONUS_AS_MATERIAL_COMES_OFF[32] =
+{
// none na na m na R 2m na
- +60, -1, -1, +37, -1, +43, +19, -1,
+ +92, -1, -1, +53, -1, +3, +19, -1,
// Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
- +14, +9, +20, +4, +3, +3, 0, 0,
+ +6, +9, +12, +-4, +-5, +-5, 8, 8,
// 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
-// Q2R Q2Rm
- 0, 0, 0, 0, 0, 0, 0, 0,
+// Q2R Q2Rm
+ 8, 8, 8, 8, 8, 8, 8, 8,
// na Q2R2m QR4m na Q2R3m na na full
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 8, 8, 8, 8, 8, 8,
};
-SCORE RACER_WINS_RACE = +800;
+SCORE RACER_WINS_RACE = +784;
-static SCORE UNDEVELOPED_MINORS_IN_OPENING[5] =
+static SCORE UNDEVELOPED_MINORS_IN_OPENING[5] =
{// 0 1 2 3 4
- 0, -6, -10, -16, -22
+ -8, -14, -10, -24, -38
};
//
// Bishop eval terms
// ---------------------------------------------------------------------------
//
-static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +33;
+static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +1;
//
// "The bishop pair has an average value of half a pawn (more when the
@@ -277,12 +277,12 @@ static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +33;
// position, and enough to overwhelm most positional considerations.
// Moreover, this substantial bishop pair value holds up in all
// situations tested, regardless of what else is on the board...
-//
+//
// ...One rule which I often teach to students is that if you have the
// bishop pair, and your opponent's single bishop is a bad bishop
// (hemmed in by his own pawns), you already have full compensation
// for a pawn... Kasparov has said something similar...
-//
+//
// As noted before, the bishop pair is worth more with fewer pawns on
// the board. Aside from this factor, the half pawn value of the
// bishop pair is remarkably constant, applying even when there are no
@@ -291,58 +291,58 @@ static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +33;
// "Evaluation of Material Imbalance"
static SCORE BISHOP_PAIR[2][17] =
{
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 53, 52, 51, 50, 49, 48, 47, 45, 43, 41, 40, 40, 40, 40, 40, 40, 40 }
+ { -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16 },
+ { 21, 68, 51, 34, 41, 48, 55, 37, 59, 57, 40, 40, 40, 40, 40, 40, 40 }
};
-static SCORE STATIONARY_PAWN_ON_BISHOP_COLOR[128] =
+static SCORE STATIONARY_PAWN_ON_BISHOP_COLOR[128] =
{
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
- -4, -6, -7, -7, -7, -7, -6, -4, 0,0,0,0,0,0,0,0,
- -6, -7, -9, -8, -8, -9, -7, -6, 0,0,0,0,0,0,0,0,
+ -20, -14, -7, -7, -7, -7, -14, -20, 0,0,0,0,0,0,0,0,
+ -14, -7, -17, -8, -8, -17, -7, -14, 0,0,0,0,0,0,0,0,
-7, -8, -10, -11, -11, -10, -8, -7, 0,0,0,0,0,0,0,0,
// -------------------------------------------------------------------
-7, -8, -10, -11, -11, -10, -8, -7, 0,0,0,0,0,0,0,0,
- -6, -7, -9, -8, -8, -9, -7, -6, 0,0,0,0,0,0,0,0,
- -4, -6, -7, -7, -7, -7, -6, -4, 0,0,0,0,0,0,0,0,
+ -14, -7, -17, -8, -8, -17, -7, -14, 0,0,0,0,0,0,0,0,
+ -20, -14, -7, -7, -7, -7, -14, -20, 0,0,0,0,0,0,0,0,
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
};
-static SCORE TRANSIENT_PAWN_ON_BISHOP_COLOR[128] =
+static SCORE TRANSIENT_PAWN_ON_BISHOP_COLOR[128] =
{
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
-1, -1, -2, -2, -2, -2, -1, -1, 0,0,0,0,0,0,0,0,
- -3, -4, -4, -4, -4, -4, -4, -3, 0,0,0,0,0,0,0,0,
- -4, -5, -7, -8, -8, -7, -5, -4, 0,0,0,0,0,0,0,0,
+ -11, -4, -4, -4, -4, -4, -4, -11, 0,0,0,0,0,0,0,0,
+ -4, -5, 1, -16, -16, 1, -5, -4, 0,0,0,0,0,0,0,0,
// -------------------------------------------------------------------
- -4, -5, -7, -8, -8, -7, -5, -4, 0,0,0,0,0,0,0,0,
- -3, -4, -4, -4, -4, -4, -4, -3, 0,0,0,0,0,0,0,0,
+ -4, -5, 1, -16, -16, 1, -5, -4, 0,0,0,0,0,0,0,0,
+ -11, -4, -4, -4, -4, -4, -4, -11, 0,0,0,0,0,0,0,0,
-1, -1, -2, -2, -2, -2, -1, -1, 0,0,0,0,0,0,0,0,
+0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
};
-//
+//
// A bishop can move to between 0..13 squares.
-//
+//
static SCORE BISHOP_MOBILITY_BY_SQUARES[14] =
{// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
- -22, -14, -10, -5, -1, 0, +1, +3, +4, +5, +6, +7, +8, +9
-};// ^ |
+ -38, -22, -26, -13, -9, 0, +1, +11, +4, +13, +22, +15, +40, +-7
+};// ^ |
static SCORE BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
{// 0 1 2 3 4 5 6 7
- -10, -4, +1, +3, +4, +5, +5, +5
+ -18, 4, +9, +3, +12, +-3, +-3, +-3
};
static SCORE BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING[9] =
{// 0 1 2 3 4 5 6 7 8
- +0, +33, +28, +18, +8, +4, +0, -10, -16
+ +8, +1, +36, +26, +32, +-12, +8, -26, -16
};
static SCORE BISHOP_IN_CLOSED_POSITION[33] =
{// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- 10, 10, 10, 9, 9, 8, 8, 7, 7, 6, 5, 4, 3, 2, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 2, 2, 2, 17, 17, 8, 8, 7, 7, -2, 13, 20, 3, 18, 9, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
// 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
};
@@ -350,34 +350,34 @@ static SCORE BISHOP_IN_CLOSED_POSITION[33] =
// Knight eval terms
// ---------------------------------------------------------------------------
//
-static SCORE KNIGHT_CENTRALITY_BONUS[128] =
+static SCORE KNIGHT_CENTRALITY_BONUS[128] =
{
- -12, -8, -8, -8, -8, -8, -8, -12, 0,0,0,0,0,0,0,0,
- -8, -2, -2, 0, 0, -2, -2, -8, 0,0,0,0,0,0,0,0,
- -8, -2, +4, +5, +5, +4, -2, -8, 0,0,0,0,0,0,0,0,
- -8, -2, +5, +8, +8, +5, -2, -8, 0,0,0,0,0,0,0,0,
+ -60, -16, -16, -16, -16, -16, -16, -60, 0,0,0,0,0,0,0,0,
+ -16, -2, -2, 0, 0, -2, -2, -16, 0,0,0,0,0,0,0,0,
+ -16, -2, +-4, +13, +13, +-4, -2, -16, 0,0,0,0,0,0,0,0,
+ -16, -2, +13, +16, +16, +13, -2, -16, 0,0,0,0,0,0,0,0,
// -------------------------------------------------------------------
- -8, -2, +5, +8, +8, +5, -2, -8, 0,0,0,0,0,0,0,0,
- -8, -2, +4, +5, +5, +4, -2, -8, 0,0,0,0,0,0,0,0,
- -8, -2, -2, 0, 0, -2, -2, -8, 0,0,0,0,0,0,0,0,
- -12, -8, -8, -8, -8, -8, -8, -12, 0,0,0,0,0,0,0,0
+ -16, -2, +13, +16, +16, +13, -2, -16, 0,0,0,0,0,0,0,0,
+ -16, -2, +-4, +13, +13, +-4, -2, -16, 0,0,0,0,0,0,0,0,
+ -16, -2, -2, 0, 0, -2, -2, -16, 0,0,0,0,0,0,0,0,
+ -60, -16, -16, -16, -16, -16, -16, -60, 0,0,0,0,0,0,0,0
};
static SCORE KNIGHT_KING_TROPISM_BONUS[9] =
{// 0 1 2 3 4 5 6 7 8
- 0, +15, +12, +9, +4, +0, +0, +0, +0
+ 8, +-9, +12, +1, +12, +8, +8, +8, +8
};
static SCORE KNIGHT_UNASSAILABLE_BY_DIST_FROM_EKING[9] =
{// 0 1 2 3 4 5 6 7 8
- +0, +25, +19, +14, +6, +0, +0, +0, +0
+ +-24, +9, +11, +38, +14, +-24, +-24, +-24, +-24
};
static SCORE KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +12, +11, +9, +6, +3, +0, +0, +0 }, // black
- { +0, +0, +0, +0, +3, +6, +9, +11, +12 } // white
+ { +-8, +4, +27, +25, +22, +3, +-8, +-8, +-8 }, // black
+ { +-8, +-8, +-8, +-8, +3, +22, +25, +27, +4 } // white
};
//
@@ -387,23 +387,23 @@ static SCORE KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[2][9] =
// 1 = unsupported enemy pawn, friend pawn, enemy B/N
// enemy controlled empty sq.
// 2 = enemy >B, friend controlled empty sq, no one controlled empty sq
-//
+//
// Total: 16 mobility max
-//
+//
static SCORE KNIGHT_MOBILITY_BY_COUNT[9] =
{// 0 1 2 3 4 5 6 7 8
- -17, -10, -6, 0, +3, +5, +7, +8, +8
+ -33, -18, -14, -8, +-5, +5, +15, +8, +8
};// ^ |
-static SCORE KNIGHT_WITH_N_PAWNS_SUPPORTING[3] =
+static SCORE KNIGHT_WITH_N_PAWNS_SUPPORTING[3] =
{
- +0, +4, +8
+ +16, +12, +0
};
static SCORE KNIGHT_IN_CLOSED_POSITION[33] =
{// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 11,
- 12, 13, 15, 17, 19, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 18, 4, 6, 17, -13,
+ 12, 5, -17, 1, 19, -3, -3, 30, 30, 23, 23, 24, 24, 25, 25, 26, 27
// 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
};
@@ -413,44 +413,44 @@ static SCORE KNIGHT_IN_CLOSED_POSITION[33] =
//
static SCORE ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING[8] =
{// 0 1 2 3 4 5 6 7
- +24, +22, +17, +14, +13, +13, +12, +12
+ +48, +38, +41, +38, +29, +29, +20, +20
};
-static SCORE ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[8] =
+static SCORE ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[8] =
{// 0 1 2 3 4 5 6 7
- +12, +11, +9, +9, +8, +8, +8, +7
+ +12, +11, +17, +17, +32, +32, +32, +15
};
static SCORE ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING[8] =
{// 0 1 2 3 4 5 6 7
- +13, +12, +11, +11, +9, +9, +9, +8
+ +-3, +12, +11, +11, +17, +17, +17, +16
};
static SCORE ROOK_BEHIND_PASSER_BY_PASSER_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0, +25, +17, +12, +6, +1, +0, +0 }, // black
- { +0, +0, +0, +1, +6, +12, +17, +25, +0 } // white
+ { +-24, +-24, +41, +17, +4, +-2, +-31, +-24, +-24 }, // black
+ { +-24, +-24, +-24, +-31, +-2, +4, +17, +41, +-24 } // white
};
static SCORE ROOK_LEADS_PASSER_BY_PASSER_RANK[2][9] =
{// 0 1 2 3 4 5 6 7 8
- { +0, +0, -22, -16, -13, -9, -5, -3, +0 }, // black
- { +0, +0, -3, -5, -9, -13, -16, -22, +0 } // white
+ { +0, +0, -54, -16, 11, -9, 19, -3, +0 }, // black
+ { +0, +0, -3, 19, -9, 11, -16, -54, +0 } // white
};
-static SCORE KING_TRAPPING_ROOK = -40;
+static SCORE KING_TRAPPING_ROOK = -48;
-static SCORE ROOK_TRAPPING_EKING = +22;
+static SCORE ROOK_TRAPPING_EKING = +46;
-static SCORE ROOK_VALUE_AS_PAWNS_COME_OFF[17] =
-{// 0 1 2 3 4 5 6 7 8
- +55, +51, +44, +38, +33, +27, +22, +16, +7,
+static SCORE ROOK_VALUE_AS_PAWNS_COME_OFF[17] =
+{// 0 1 2 3 4 5 6 7 8
+ +7, +35, +92, +46, +33, +-5, +-10, +16, +-17,
// 9 10 11 12 13 14 15 16
- +1, -3, -6, -9, -12, -18, -22, -25
+ +-15, -27, -38, -57, -44, -42, -70, -41
};
//
-// Note: these are multiplied by two (one per rook).
+// Note: these are multiplied by two (one per rook).
//
static SCORE ROOK_CONNECTED_VERT = +7; // x2
static SCORE ROOK_CONNECTED_HORIZ = +4; // x2
@@ -461,17 +461,17 @@ static SCORE ROOK_CONNECTED_HORIZ = +4; // x2
// 0 = supported enemy P/N/B, friend piece
// 1 = unsupported enemy piece, enemy controlled empty sq, enemy R
// 2 = enemy >R, friend controlled empty sq, no one controlled empty sq
-//
+//
// Total: 28 mobility max
-//
+//
static SCORE ROOK_MOBILITY_BY_SQUARES[15] =
{// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
- -28, -24, -20, -14, -7, -2, +0, +4, +8, +12, +15, +17, +19, +21, +22
+ -36, -16, -20, -14, -7, -10, +0, +4, +8, +12, +15, +9, +19, +13, +14
};// ^ |
static SCORE ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
{// 0 1 2 3 4 5 6 7
- -15, -6, +0, +4, +8, +8, +8, +8
+ 1, 10, +8, +12, +8, +8, +8, +8
};
//
@@ -486,21 +486,21 @@ static SCORE ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
// 0 = supported enemy P/N/B/R, friend piece
// 1 = unsupported enemy piece, enemy controlled empty sq, enemy Q
// 2 = enemy K, no one controlled empty sq, friend controlled empty sq
-//
+//
// Total: 54 mobility max
-//
+//
static SCORE QUEEN_MOBILITY_BY_SQUARES[28] =
{// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
- -30, -26, -22, -17, -11, -8, -4, -2, -1, +2, +4, +7, +10, +12, +14,
+ -54, -34, -22, -17, -19, -8, -4, -2, 7, +10, +12, +15, +18, +4, +30,
// |
//15 16 17 18 19 20 21 22 23 24 25 26 27
- +15, +16, +17, +18, +19, +20, +20, +21, +21, +22, +22, +23, +23
+ +31, +32, +41, +42, +35, +36, +36, +21, +21, +6, +6, +7, +7
};
-static SCORE QUEEN_OUT_EARLY[5] =
+static SCORE QUEEN_OUT_EARLY[5] =
{// 0 1 2 3 4 : num unmoved minors
- 0, -14, -22, -26, -33
+ 0, -14, -6, -2, -25
};
//
@@ -508,18 +508,18 @@ static SCORE QUEEN_OUT_EARLY[5] =
// point that queens are worth more then the standard nine "points".
// Thus, this scale is biased upwards by about 0.15 pawn.
//
-static SCORE QUEEN_KING_TROPISM[8] =
+static SCORE QUEEN_KING_TROPISM[8] =
{// 0 1 2 3 4 5 6 7
- 0, +34, +28, +22, +19, +17, +16, +15
+ 0, +34, +76, +30, +27, +9, +8, +-1
};
-static SCORE QUEEN_ATTACKS_SQ_NEXT_TO_KING = 8; // x #sq_attacked
+static SCORE QUEEN_ATTACKS_SQ_NEXT_TO_KING = -8; // x #sq_attacked
//
// King eval terms
// ---------------------------------------------------------------------------
//
-static ULONG KING_INITIAL_COUNTER_BY_LOCATION[2][128] =
+static ULONG KING_INITIAL_COUNTER_BY_LOCATION[2][128] =
{
{
1, 0, 0, 0, 1, 0, 0, 1, 0,0,0,0,0,0,0,0,
@@ -545,17 +545,17 @@ static ULONG KING_INITIAL_COUNTER_BY_LOCATION[2][128] =
}
};
-static SCORE KING_TO_CENTER[128] =
+static SCORE KING_TO_CENTER[128] =
{
- +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
- +1, +3, +5, +7, +7, +5, +3, +1, 0,0,0,0,0,0,0,0,
- +3, +5, +13, +15, +15, +13, +5, +3, 0,0,0,0,0,0,0,0,
- +5, +7, +17, +23, +23, +17, +7, +5, 0,0,0,0,0,0,0,0,
+ +-32, +-32, +-32, +-32, +-32, +-32, +-32, +-32, -32,-32,-32,-32,-32,-32,-32,-32,
+ +-23, +3, +5, +-1, +-1, +5, +3, +-23, -32,-32,-32,-32,-32,-32,-32,-32,
+ +3, +5, +13, +15, +15, +13, +5, +3, -32,-32,-32,-32,-32,-32,-32,-32,
+ +5, +-1, +41, +31, +31, +41, +-1, +5, -32,-32,-32,-32,-32,-32,-32,-32,
// ------------------------------------------------------------------
- +5, +7, +17, +23, +23, +17, +7, +5, 0,0,0,0,0,0,0,0,
- +3, +5, +13, +15, +15, +13, +5, +3, 0,0,0,0,0,0,0,0,
- +1, +3, +5, +7, +7, +5, +3, +1, 0,0,0,0,0,0,0,0,
- +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
+ +5, +-1, +41, +31, +31, +41, +-1, +5, -32,-32,-32,-32,-32,-32,-32,-32,
+ +3, +5, +13, +15, +15, +13, +5, +3, -32,-32,-32,-32,-32,-32,-32,-32,
+ +-23, +3, +5, +-1, +-1, +5, +3, +-23, -32,-32,-32,-32,-32,-32,-32,-32,
+ +-32, +-32, +-32, +-32, +-32, +-32, +-32, +-32, -32,-32,-32,-32,-32,-32,-32,-32
};
//
@@ -573,7 +573,7 @@ static SCORE KING_TO_CENTER[128] =
#define KEEP_KING_AT_HOME_THRESHOLD \
(VALUE_ROOK + VALUE_ROOK + VALUE_BISHOP + VALUE_KING + 1)
-static ULONG KING_COUNTER_BY_ATTACK_PATTERN[32] =
+static ULONG KING_COUNTER_BY_ATTACK_PATTERN[32] =
{
//p 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//m 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
@@ -585,13 +585,13 @@ static ULONG KING_COUNTER_BY_ATTACK_PATTERN[32] =
static SCORE KING_SAFETY_BY_COUNTER[42] =
{
- -0, -4, -8, -12, -16, -20, -25, -31, -38, -50, -63, -76, -90,
- -105,-120,-135,-150,-165,-180,-195,-210,-225,-240,-255,-270,-290,
- -310,-330,-350,-370,-390,-410,-440,-470,-500,-500,-500,-500,-500,
- -500,-500,-500
+ 0, -4, -40, -28, -24, -28, -33, -39, -30, -50, -55, -60, -90,
+ -97,-104,-135,-150,-141,-148,-211,-210,-217,-240,-255,-286,-306,
+ -262,-330,-350,-386,-390,-378,-448,-462,-508,-508,-508,-508,-508,
+ -508,-508,-508
};
-static SCORE KING_MISSING_ONE_CASTLE_OPTION = -23;
+static SCORE KING_MISSING_ONE_CASTLE_OPTION = 9;
typedef struct _DNA_BASE_SIZE {
SCORE *pBase;
ULONG uCount;
@@ -659,8 +659,8 @@ static DNA_BASE_SIZE g_EvalDNA[] = {
DNA_VAR(KING_MISSING_ONE_CASTLE_OPTION)
};
-ULONG
-DNABufferSizeBytes()
+ULONG
+DNABufferSizeBytes()
{
ULONG u;
ULONG uSize = 0;
@@ -672,14 +672,14 @@ DNABufferSizeBytes()
char *
-ExportEvalDNA()
+ExportEvalDNA()
{
ULONG uSize = DNABufferSizeBytes();
char *p = malloc(uSize);
ULONG u, v;
SCORE *q;
FLAG fFirst = TRUE;
-
+
memset(p, 0, uSize);
for (u = 0; u < ARRAY_LENGTH(g_EvalDNA); u++) {
q = g_EvalDNA[u].pBase;
@@ -735,7 +735,7 @@ ImportEvalDNA(char *p)
}
FLAG
-ReadEvalDNA(char *szFilename)
+ReadEvalDNA(char *szFilename)
{
FILE *p = NULL;
ULONG uSize = DNABufferSizeBytes();
@@ -795,31 +795,31 @@ BITBOARD BBADJACENT_FILES[8] =
{
// A = 0
BBFILEB,
-
+
// B = 1
BBFILEA | BBFILEC,
-
+
// C = 2
BBFILEB | BBFILED,
-
+
// D = 3
BBFILEC | BBFILEE,
-
+
// E = 4
BBFILED | BBFILEF,
-
+
// F = 5
BBFILEE | BBFILEG,
-
+
// G = 6
BBFILEF | BBFILEH,
-
+
// H = 7
BBFILEG
};
//
-// The ranks preceeding one, indexed by rank/color of pawn (used in
+// The ranks preceeding one, indexed by rank/color of pawn (used in
// eval.c)
//
BITBOARD BBPRECEEDING_RANKS[8][2] =
@@ -853,15 +853,15 @@ BITBOARD BBPRECEEDING_RANKS[8][2] =
};
-static FLAG
-_IsSquareSafeFromEnemyPawn(IN POSITION *pos,
- IN COOR c,
+static FLAG
+_IsSquareSafeFromEnemyPawn(IN POSITION *pos,
+ IN COOR c,
IN BITBOARD bb)
/**
Routine description:
- Determine if a piece in square c is "outposted". A piece is
+ Determine if a piece in square c is "outposted". A piece is
outposted if no enemy pawns can advance to attack it / drive
it away.
@@ -888,16 +888,16 @@ Return value:
ASSERT(p && (IS_BISHOP(p) || IS_KNIGHT(p) || IS_PAWN(p)));
ASSERT(IS_VALID_COLOR(uColor));
#endif
-
+
uFile = FILE(c);
ASSERT(uFile < 8);
bb &= BBADJACENT_FILES[uFile];
-
+
ASSERT(((c & 0x70) >> 4) == (c >> 4));
uRank = c >> 4;
ASSERT(uRank < 8);
bb &= BBPRECEEDING_RANKS[uRank][uColor];
-
+
#ifdef DEBUG
if (bb != 0)
{
@@ -960,8 +960,8 @@ Return value:
}
-static ULONG
-_WhoControlsSquareFast(IN POSITION *pos,
+static ULONG
+_WhoControlsSquareFast(IN POSITION *pos,
IN COOR c)
/**
@@ -979,7 +979,7 @@ Return value:
static ULONG : (ULONG)-1 if neither side controls it or the sides
control it evenly, WHITE if white controls the square, or BLACK if
black controls the square.
-
+
TODO: fix this to use counts / xrays
**/
@@ -991,7 +991,7 @@ Return value:
ULONG u;
PIECE p;
CHAR ch;
-
+
ASSERT((c + 8) == (c | 8));
ASSERT((uWhite & 0xFFFFFF00) == 0);
ASSERT((uBlack & 0xFFFFFF00) == 0);
@@ -999,7 +999,7 @@ Return value:
// TODO: keep these and update the table to use them
uWhite >>= 3;
uBlack >>= 3;
-
+
p = pos->rgSquare[c].pPiece;
// p -= 2;
ch = g_SwapTable[p][uWhite][uBlack];
@@ -1053,7 +1053,7 @@ Return value:
CLEAR_A_SQ; c++; \
CLEAR_A_SQ; c += 10;
-static void
+static void
_ClearAttackTables(IN OUT POSITION *pos)
{
register COOR c = 8;
@@ -1087,8 +1087,8 @@ _ClearAttackTables(IN OUT POSITION *pos)
}
-static INLINE void
-_InitializePawnHashEntry(IN OUT PAWN_HASH_ENTRY *pHash,
+static INLINE void
+_InitializePawnHashEntry(IN OUT PAWN_HASH_ENTRY *pHash,
IN POSITION *pos)
/**
@@ -1149,11 +1149,11 @@ Return value:
ASSERT(IS_PAWN(pHelper));
uColor = GET_COLOR(pHelper);
ASSERT(IS_VALID_COLOR(uColor));
-
+
if (pHash->uCountPerFile[FLIP(uColor)][uPawnFile] != 0)
{
ASSERT((pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[FILE(c)]) != 0);
-
+
//
// The only way a pawn can be a passer/candidate if the other
// side has a pawn on its same file is if that enemy pawn is
@@ -1182,12 +1182,12 @@ Return value:
break;
}
}
-
+
//
// Count FLIP(uColor)'s sentries and determine the location of the
- // critical square. Note if there are no sentries then this
+ // critical square. Note if there are no sentries then this
// pawn (on square c) is a passer already, not a candidate.
- //
+ //
bb = pHash->bbPawnLocations[FLIP(uColor)] & BBADJACENT_FILES[FILE(c)];
bb &= BBPRECEEDING_RANKS[(c & 0x70) >> 4][uColor];
if (!bb)
@@ -1206,11 +1206,11 @@ Return value:
pHash->iScore[uColor],
PASSER_BY_RANK[uColor][RANK(c)],
"passed pawn");
-
+
//
// However, don't give doubled passers such a big bonus.
//
- if (IS_PAWN(pos->rgSquare[c - 16 * g_iAhead[uColor]].pPiece))
+ if (IS_PAWN(pos->rgSquare[c - 16 * g_iAhead[uColor]].pPiece))
{
EVAL_TERM(uColor,
PAWN,
@@ -1256,7 +1256,7 @@ Return value:
if (pos->rgSquare[c1 - 1].pPiece == pSentry)
{
uVerifySentries++;
- if (0 == cVerifySquare)
+ if (0 == cVerifySquare)
{
cVerifySquare = c1 - d1;
ASSERT(cVerifySquare == cSquare);
@@ -1308,7 +1308,7 @@ Return value:
uHelpers = 1;
goto do_left;
}
-
+
//
// There is no helper pawn in the support position yet.
// See if one can get there.
@@ -1331,7 +1331,7 @@ Return value:
}
}
}
-
+
do_left:
c1 = cSquare - 1 - d1;
if ((IS_ON_BOARD(c1)) && (pHash->uCountPerFile[uColor][FILE(c1) + 1]))
@@ -1350,7 +1350,7 @@ Return value:
uHelpers++;
goto done_helpers;
}
-
+
//
// There is no pawn in the left support position yet. See
// if one can get there.
@@ -1373,7 +1373,7 @@ Return value:
}
}
}
-
+
done_helpers:
if ((uHelpers >= uSentries) ||
((pHash->uCountPerFile[uColor][uPawnFile + 1] +
@@ -1405,7 +1405,7 @@ Return value:
}
}
-static void
+static void
_EvaluateConnectedSupportedOutsidePassers(IN POSITION *pos,
IN OUT PAWN_HASH_ENTRY *pHash)
/**
@@ -1430,15 +1430,15 @@ Return value:
PIECE pFriend;
COOR cSupport;
BITBOARD bb;
- static const INT iDelta[5] =
+ static const INT iDelta[5] =
{
-1, +1, +17, +15, 0
};
-
+
FOREACH_COLOR(uColor)
{
ASSERT(IS_VALID_COLOR(uColor));
-
+
if (pHash->bbPasserLocations[uColor])
{
ASSERT(pos->uPawnCount[uColor] > 0);
@@ -1464,14 +1464,14 @@ Return value:
cLeftmostPasser = c;
}
cRightmostPasser = c;
-
+
v = 0;
while(iDelta[v] != 0)
{
cSupport = c + iDelta[v] * g_iBehind[uColor];
if (IS_ON_BOARD(cSupport))
{
- if (pHash->bbPasserLocations[uColor] &
+ if (pHash->bbPasserLocations[uColor] &
COOR_TO_BB(cSupport))
{
ASSERT(CONNECTED_PASSERS_BY_RANK[uColor]
@@ -1489,7 +1489,7 @@ Return value:
// strong.
//
}
- else if (pos->rgSquare[cSupport].pPiece ==
+ else if (pos->rgSquare[cSupport].pPiece ==
pFriend)
{
ASSERT(SUPPORTED_PASSER_BY_RANK[uColor]
@@ -1508,7 +1508,7 @@ Return value:
}
}
}
-
+
#ifdef DEBUG
ASSERT(IS_ON_BOARD(cLeftmostPasser));
ASSERT(IS_ON_BOARD(cRightmostPasser));
@@ -1565,12 +1565,12 @@ Return value:
}
}
}
-
+
#define PAWN_ATTACK_BLACK_DELTA (+15)
#define PAWN_ATTACK_WHITE_DELTA (-17)
-static void
+static void
_PopulatePawnAttackBits(IN OUT POSITION *pos)
/**
@@ -1607,7 +1607,7 @@ Return value:
ASSERT(pos->uPawnCount[BLACK] <= 8);
for (u = 0;
- u < pos->uPawnCount[BLACK];
+ u < pos->uPawnCount[BLACK];
u++)
{
c = pos->cPawns[BLACK][u];
@@ -1615,10 +1615,10 @@ Return value:
ASSERT(pos->rgSquare[c].pPiece);
ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == BLACK);
-
+
//
// IDEA: These IS_ON_BOARD checks can be removed by a lookup table.
- //
+ //
cAttack = c + PAWN_ATTACK_BLACK_DELTA;
if (IS_ON_BOARD(cAttack))
{
@@ -1638,7 +1638,7 @@ Return value:
ASSERT(pos->uPawnCount[WHITE] <= 8);
for (u = 0;
- u < pos->uPawnCount[WHITE];
+ u < pos->uPawnCount[WHITE];
u++)
{
c = pos->cPawns[WHITE][u];
@@ -1646,7 +1646,7 @@ Return value:
ASSERT(pos->rgSquare[c].pPiece);
ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == WHITE);
-
+
cAttack = c + PAWN_ATTACK_WHITE_DELTA;
if (IS_ON_BOARD(cAttack))
{
@@ -1664,10 +1664,10 @@ Return value:
}
}
}
-
+
static PAWN_HASH_ENTRY *
-_EvalPawns(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
+_EvalPawns(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
OUT FLAG *pfDeferred)
/**
@@ -1698,7 +1698,7 @@ Return value:
ULONG uUnsupportable;
BITBOARD bb;
int d1;
-#ifdef DEBUG
+#ifdef DEBUG
SCORE t;
#endif
@@ -1734,10 +1734,10 @@ Return value:
{
ASSERT(IS_VALID_COLOR(uColor));
ASSERT(pos->uPawnCount[uColor] <= 8);
-
+
d1 = 16 * g_iAhead[uColor];
- for (u = 0;
- u < pos->uPawnCount[uColor];
+ for (u = 0;
+ u < pos->uPawnCount[uColor];
u++)
{
c = pos->cPawns[uColor][u];
@@ -1746,17 +1746,17 @@ Return value:
ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
uPawnFile = FILE(c) + 1;
ASSERT((1 <= uPawnFile) && (uPawnFile <= 8));
-
+
//
// Update files counter
//
ASSERT(pHash->uCountPerFile[uColor][uPawnFile] < 6);
pHash->uCountPerFile[uColor][uPawnFile]++;
-
+
//
// Update bitboard bit
//
- ASSERT(CountBits(pHash->bbPawnLocations[uColor] &
+ ASSERT(CountBits(pHash->bbPawnLocations[uColor] &
BBFILE[uPawnFile-1]) < 6);
ASSERT((pHash->bbPawnLocations[uColor] & COOR_TO_BB(c)) == 0);
pHash->bbPawnLocations[uColor] |= COOR_TO_BB(c);
@@ -1767,16 +1767,16 @@ Return value:
//
// Count unmoved pawns
//
- pHash->uNumUnmovedPawns[uColor] +=
+ pHash->uNumUnmovedPawns[uColor] +=
((c & 0xF0) == uUnmovedRank[uColor]);
ASSERT(pHash->uNumUnmovedPawns[uColor] <= 8);
-
+
//
// Detect rammed and other stationary pawns.
//
cSquare = c + d1;
ASSERT(IS_ON_BOARD(cSquare));
- p = pos->rgSquare[cSquare].pPiece;
+ p = pos->rgSquare[cSquare].pPiece;
if (IS_PAWN(p))
{
pHash->bbStationaryPawns[uColor] |= COOR_TO_BB(c);
@@ -1806,15 +1806,15 @@ Return value:
//
// Second pass
- //
+ //
FOREACH_COLOR(uColor)
{
ASSERT(IS_VALID_COLOR(uColor));
ASSERT(pos->uPawnCount[uColor] <= 8);
ASSERT(CountBits(pHash->bbPawnLocations[uColor]) <= 8);
-
+
d1 = 16 * g_iAhead[uColor];
- for (u = 0;
+ for (u = 0;
u < pos->uPawnCount[uColor];
u++)
{
@@ -1822,7 +1822,7 @@ Return value:
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
ASSERT((1 < RANK(c)) && (RANK(c) < 8));
-
+
//
// Find weak pawns... pawns that are isolated are weak as
// are pawns that have advanced beyond their support.
@@ -1833,14 +1833,14 @@ Return value:
uPawnFile = FILE(c) - 1;
if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
{
- bb = (pHash->bbPawnLocations[uColor] &
+ bb = (pHash->bbPawnLocations[uColor] &
BBFILE[uPawnFile] &
BBADJACENT_RANKS[RANK(c)]);
if (!bb)
{
bb = (pHash->bbPawnLocations[FLIP(uColor)] &
BBFILE[uPawnFile]);
- while(IS_ON_BOARD(cSquare =
+ while(IS_ON_BOARD(cSquare =
CoorFromBitBoardRank8ToRank1(&bb)))
{
ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
@@ -1879,14 +1879,14 @@ Return value:
uPawnFile = FILE(c) + 1;
if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
{
- bb = (pHash->bbPawnLocations[uColor] &
+ bb = (pHash->bbPawnLocations[uColor] &
BBFILE[uPawnFile] &
BBADJACENT_RANKS[RANK(c)]);
if (!bb)
{
bb = (pHash->bbPawnLocations[FLIP(uColor)] &
BBFILE[uPawnFile]);
- while(IS_ON_BOARD(cSquare =
+ while(IS_ON_BOARD(cSquare =
CoorFromBitBoardRank8ToRank1(&bb)))
{
ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
@@ -1916,7 +1916,7 @@ Return value:
{
uUnsupportable = 2;
}
-
+
//
// If this pawn is not supportable from either side then
// it is either isolated or has been pushed too far ahead
@@ -1941,17 +1941,17 @@ Return value:
PAWN,
c,
pHash->iScore[uColor],
- ((pHash->uCountPerFile[FLIP(uColor)][uPawnFile]==0)*
+ ((pHash->uCountPerFile[FLIP(uColor)][uPawnFile]==0)*
ISOLATED_EXPOSED_PAWN),
"exposed target");
-
+
//
// Exponential penalty term
//
uIsolated[uColor] += 1;
ASSERT(uIsolated[uColor] > 0);
ASSERT(uIsolated[uColor] <= 8);
-
+
//
// Isolated + doubled? Extra penalty.
//
@@ -2010,7 +2010,7 @@ Return value:
{
//
// Detect backwards pawns. See "Pawn Power in Chess" pp 25-27
- //
+ //
if (!IS_PAWN(pos->rgSquare[cSquare].pPiece))
{
p = (BLACK_PAWN | uColor);
@@ -2055,19 +2055,19 @@ Return value:
//
// TODO: Think about backward doubled pawns; read Kauffman's
// paper "All About Doubled Pawns".
- //
+ //
}
//
// Handle passers / candidate passers
- //
+ //
_EvaluateCandidatePasser(pos, pHash, c);
}
}
-
+
//
// Reward pawn duos, see "Pawn Power in Chess" pp. 10-16
- //
+ //
ASSERT(iDuos[WHITE] >= 0);
ASSERT(iDuos[WHITE] <= 56);
ASSERT(iDuos[BLACK] >= 0);
@@ -2128,9 +2128,9 @@ Return value:
pHash->iScore[WHITE],
ISOLATED_PAWN_PENALTY_BY_COUNT[uIsolated[WHITE]],
"exponential isolated");
-
+
//
- // Look for connected, supported and outside passed pawns to give
+ // Look for connected, supported and outside passed pawns to give
// extra bonuses.
//
_EvaluateConnectedSupportedOutsidePassers(pos, pHash);
@@ -2142,7 +2142,7 @@ Return value:
}
-ULONG
+ULONG
CountKingSafetyDefects(IN OUT POSITION *pos,
IN ULONG uSide)
/**
@@ -2170,11 +2170,11 @@ Return value:
int i;
PIECE p;
ULONG u;
-
+
//
// Don't count king safety defects if the real eval code in
// _EvalKing would not...
- //
+ //
if (pos->uNonPawnMaterial[xSide] < DO_KING_SAFETY_THRESHOLD) {
return 0;
}
@@ -2185,7 +2185,7 @@ Return value:
ASSERT(pos->rgSquare[cKing].uIndex == 0);
ASSERT(IS_ON_BOARD(cKing));
ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uSide);
-
+
//
// Make sure cKing - 1, cKing and cKing + 1 are on the board
//
@@ -2218,16 +2218,16 @@ Return value:
((CHECK_VECTOR_WITH_INDEX(i + 2, xSide) & p) != 0));
}
ASSERT(uCounter < 15);
-
+
// Save the number of enemy pieces pointing at this king for later use.
- pos->uPiecesPointingAtKing[uSide] =
+ pos->uPiecesPointingAtKing[uSide] =
(uCounter - (KING_INITIAL_COUNTER_BY_LOCATION[uSide][cKing] >> 1));
return uCounter;
}
static void
-_QuicklyEstimateKingSafetyTerm(IN POSITION *pos,
+_QuicklyEstimateKingSafetyTerm(IN POSITION *pos,
IN OUT SCORE *piAlphaMargin,
IN OUT SCORE *piBetaMargin)
/**
@@ -2258,12 +2258,12 @@ Return value:
SCORE iRet;
ASSERT(CountKingSafetyDefects(pos, pos->uToMove) < 15);
- iPenaltyEst[WHITE] =
+ iPenaltyEst[WHITE] =
iScoreByDefectCount[CountKingSafetyDefects(pos, WHITE)];
ASSERT(iPenaltyEst[WHITE] > 0);
ASSERT(CountKingSafetyDefects(pos, BLACK) < 15);
- iPenaltyEst[BLACK] =
+ iPenaltyEst[BLACK] =
iScoreByDefectCount[CountKingSafetyDefects(pos, BLACK)];
ASSERT(iPenaltyEst[BLACK] > 0);
@@ -2293,7 +2293,7 @@ static void
_QuicklyEstimatePasserBonuses(POSITION *pos,
PAWN_HASH_ENTRY *pHash,
SCORE *piAlphaMargin,
- SCORE *piBetaMargin)
+ SCORE *piBetaMargin)
{
SCORE iBonusEst[2] = {0, 0};
SCORE iRet;
@@ -2308,7 +2308,7 @@ _QuicklyEstimatePasserBonuses(POSITION *pos,
u /= VALUE_PAWN;
u = MINU(31, u);
ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
- iBonusEst[WHITE] =
+ iBonusEst[WHITE] =
(CountBits(pHash->bbPasserLocations[WHITE]) *
PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
}
@@ -2318,7 +2318,7 @@ _QuicklyEstimatePasserBonuses(POSITION *pos,
u /= VALUE_PAWN;
u = MINU(31, u);
ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
- iBonusEst[BLACK] =
+ iBonusEst[BLACK] =
(CountBits(pHash->bbPasserLocations[BLACK]) *
PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
}
@@ -2334,7 +2334,7 @@ _QuicklyEstimatePasserBonuses(POSITION *pos,
//
// For the alpha bonus, assume our passer bonus gets doubled and
- // our opponent's is reduced. Net bonus to us / their bonus not
+ // our opponent's is reduced. Net bonus to us / their bonus not
// as high.
//
iRet = iBonusEst[pos->uToMove] - iBonusEst[FLIP(pos->uToMove)] / 2;
@@ -2343,9 +2343,9 @@ _QuicklyEstimatePasserBonuses(POSITION *pos,
}
-static void
-_InvalidEvaluator(UNUSED POSITION *pos,
- UNUSED COOR c,
+static void
+_InvalidEvaluator(UNUSED POSITION *pos,
+ UNUSED COOR c,
UNUSED PAWN_HASH_ENTRY *pHash)
/**
@@ -2374,7 +2374,7 @@ Return value:
// ======================================================================
//
-static FLAG FASTCALL
+static FLAG FASTCALL
_InvalidMobilityHelper(UNUSED POSITION *pos,
UNUSED COOR c,
UNUSED ULONG *puMobility,
@@ -2406,7 +2406,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_BMinorToEnemyLess(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2433,7 +2433,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(!IS_EMPTY(p));
@@ -2449,7 +2449,7 @@ Return value:
return(TRUE); // stop scanning this dir
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WMinorToEnemyLess(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2474,7 +2474,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(!IS_EMPTY(p));
@@ -2490,7 +2490,7 @@ Return value:
return(TRUE); // stop scanning this dir
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WRookToEnemyLess(POSITION *pos,
COOR c,
ULONG *puMobility,
@@ -2515,7 +2515,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ROOK(pRook));
ASSERT(!IS_EMPTY(p));
ASSERT(OPPOSITE_COLORS(p, pRook));
@@ -2527,7 +2527,7 @@ Return value:
return(TRUE); // stop scanning this dir
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_BRookToEnemyLess(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2552,7 +2552,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_ROOK(pRook));
@@ -2566,7 +2566,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_BQueenToEnemyLess(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2591,7 +2591,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_QUEEN(pQueen));
@@ -2605,7 +2605,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WQueenToEnemyLess(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2630,7 +2630,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_QUEEN(pQueen));
@@ -2645,7 +2645,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_EMinorToEnemySame(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2670,13 +2670,13 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(!IS_EMPTY(p));
ASSERT(!IS_EMPTY(pMinor));
ASSERT(OPPOSITE_COLORS(p, pMinor));
-
+
if (IS_BISHOP(pMinor))
{
ASSERT(PIECE_VALUE(p) == VALUE_BISHOP);
@@ -2693,7 +2693,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_ERookToEnemySame(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2718,7 +2718,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_ROOK(pRook));
@@ -2732,7 +2732,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_EQueenToEnemyGreaterEqual(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2757,7 +2757,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_QUEEN(pQueen));
@@ -2772,7 +2772,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_EMinorToEnemyGreater(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2797,7 +2797,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(!IS_EMPTY(p));
@@ -2811,7 +2811,7 @@ Return value:
return(FALSE); // keep scanning this dir
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_ERookToEnemyGreater(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2852,7 +2852,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_AnythingToFriendNoXray(IN POSITION *pos,
IN COOR c,
UNUSED ULONG *puMobility,
@@ -2878,7 +2878,7 @@ Return value:
COOR cMover = pos->cPiece;
PIECE pMover = pos->rgSquare[cMover].pPiece;
PIECE pFriend = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cMover));
ASSERT(!IS_EMPTY(pFriend));
@@ -2906,7 +2906,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_EMinorToFriendXray(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2931,7 +2931,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(!IS_EMPTY(p));
ASSERT(!IS_EMPTY(pMinor));
ASSERT(IS_BISHOP(pMinor));
@@ -2941,7 +2941,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_BRookToFriendRook(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -2968,7 +2968,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[cRook].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cRook));
ASSERT(IS_ROOK(pRook));
@@ -2983,7 +2983,7 @@ Return value:
ROOK,
c,
pos->iScore[BLACK],
- (ROOK_CONNECTED_HORIZ * fHoriz +
+ (ROOK_CONNECTED_HORIZ * fHoriz +
ROOK_CONNECTED_VERT * FLIP(fHoriz)),
"rook connected");
*puBit = ROOK_XRAY_BIT;
@@ -2991,7 +2991,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WRookToFriendRook(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3018,7 +3018,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[cRook].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cRook));
ASSERT(IS_ROOK(pRook));
@@ -3033,7 +3033,7 @@ Return value:
ROOK,
c,
pos->iScore[WHITE],
- (ROOK_CONNECTED_HORIZ * fHoriz +
+ (ROOK_CONNECTED_HORIZ * fHoriz +
ROOK_CONNECTED_VERT * FLIP(fHoriz)),
"rook connected");
*puBit = ROOK_XRAY_BIT;
@@ -3041,7 +3041,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_ERookToFriendQueen(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3066,7 +3066,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_ROOK(pRook));
@@ -3078,7 +3078,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_EQueenToFriendBishop(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3104,7 +3104,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cQueen));
ASSERT(IS_QUEEN(pQueen));
@@ -3117,7 +3117,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_EQueenToFriendRook(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3143,7 +3143,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cQueen));
ASSERT(IS_QUEEN(pQueen));
@@ -3156,7 +3156,7 @@ Return value:
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_EQueenToFriendQueen(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3182,7 +3182,7 @@ Return value:
COOR cQueen = pos->cPiece;
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(cQueen));
ASSERT(IS_QUEEN(pQueen));
@@ -3196,7 +3196,7 @@ Return value:
// ----------------------------------------------------------------------
-static FLAG FASTCALL
+static FLAG FASTCALL
_BMinorToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3221,7 +3221,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_EMPTY(p));
ASSERT(!IS_EMPTY(pMinor));
ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
@@ -3232,7 +3232,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WMinorToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3257,7 +3257,7 @@ Return value:
#ifdef DEBUG
PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
PIECE p = pos->rgSquare[c].pPiece;
-
+
ASSERT(IS_EMPTY(p));
ASSERT(!IS_EMPTY(pMinor));
ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
@@ -3268,7 +3268,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WRookToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3293,7 +3293,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_ROOK(pRook));
@@ -3305,7 +3305,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_BRookToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3330,7 +3330,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_ROOK(pRook));
@@ -3342,7 +3342,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_BQueenToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3367,7 +3367,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_QUEEN(pQueen));
@@ -3379,7 +3379,7 @@ Return value:
return(FALSE);
}
-static FLAG FASTCALL
+static FLAG FASTCALL
_WQueenToEmpty(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3404,7 +3404,7 @@ Return value:
#ifdef DEBUG
PIECE p = pos->rgSquare[c].pPiece;
PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_QUEEN(pQueen));
@@ -3418,7 +3418,7 @@ Return value:
-static FLAG FASTCALL
+static FLAG FASTCALL
_EBishopToFriendPawn(IN POSITION *pos,
IN COOR c,
IN OUT ULONG *puMobility,
@@ -3443,7 +3443,7 @@ Return value:
#ifdef DEBUG
PIECE pPawn = pos->rgSquare[c].pPiece;
PIECE pBishop = pos->rgSquare[pos->cPiece].pPiece;
-
+
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_ON_BOARD(pos->cPiece));
ASSERT(IS_BISHOP(pBishop));
@@ -3464,7 +3464,7 @@ Return value:
static void
_EvalBishop(IN OUT POSITION *pos,
- IN COOR c,
+ IN COOR c,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -3484,7 +3484,7 @@ Return value:
{
static const BITBOARD bbColorSq[2] = { 0x55aa55aa55aa55aaULL,
0xaa55aa55aa55aa55ULL };
- static const PMOBILITY_HELPER BMobJumpTable[2][14] =
+ static const PMOBILITY_HELPER BMobJumpTable[2][14] =
{
{// (black)
_BMinorToEmpty, // EMPTY_SQUARE (0)
@@ -3519,7 +3519,7 @@ Return value:
_AnythingToFriendNoXray, // WHITE_KING (13)
}
};
- static const COOR cBishopAtHome[2][2] =
+ static const COOR cBishopAtHome[2][2] =
{
{ C8, F8 }, // BLACK
{ C1, F1 } // WHITE
@@ -3537,7 +3537,7 @@ Return value:
ULONG uBit;
PIECE p;
PMOBILITY_HELPER pFun;
-
+
ASSERT(IS_ON_BOARD(c));
p = pos->rgSquare[c].pPiece;
ASSERT(p && IS_BISHOP(p));
@@ -3580,7 +3580,7 @@ Return value:
"good/bad stationary pawns ++");
i = 0;
- bbPc = ~(pHash->bbStationaryPawns[WHITE] |
+ bbPc = ~(pHash->bbStationaryPawns[WHITE] |
pHash->bbStationaryPawns[BLACK]);
bbPc &= bbMask;
bb = pHash->bbPawnLocations[uColor] & bbPc;
@@ -3604,7 +3604,7 @@ Return value:
ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[cSquare].pPiece) == FLIP(uColor));
ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & COOR_TO_BB(cSquare));
- i +=
+ i +=
(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].small.uPawn != 0) *
TRANSIENT_PAWN_ON_BISHOP_COLOR[cSquare] / 2;
}
@@ -3625,7 +3625,7 @@ Return value:
pos->iScore[uColor],
BISHOP_IN_CLOSED_POSITION[pos->uClosedScaler],
"in closed/open position");
-
+
//
// Bishop mobility (and update attack table bits)
//
@@ -3637,7 +3637,7 @@ Return value:
uCurrentMobility = 0;
uBit = MINOR_BIT;
cSquare = c + g_iBDeltas[u];
-
+
while(IS_ON_BOARD(cSquare))
{
//
@@ -3694,9 +3694,9 @@ Return value:
uTotalMobility /= 2;
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
- pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
+ pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
-
+
//
// Look for "active bad bishops". See if square c is safe from
// enemy pawns.
@@ -3730,8 +3730,8 @@ Return value:
}
static void
-_EvalKnight(IN OUT POSITION *pos,
- IN COOR c,
+_EvalKnight(IN OUT POSITION *pos,
+ IN COOR c,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -3750,7 +3750,7 @@ Return value:
**/
{
static const int iPawnStart[2] = { -17, +15 };
- static const PMOBILITY_HELPER NMobJumpTable[2][14] =
+ static const PMOBILITY_HELPER NMobJumpTable[2][14] =
{
{// (black)
_BMinorToEmpty, // EMPTY_SQUARE (0)
@@ -3785,7 +3785,7 @@ Return value:
_AnythingToFriendNoXray, // WHITE_KING (13)
}
};
- static const COOR cKnightAtHome[2][2] =
+ static const COOR cKnightAtHome[2][2] =
{
{ B8, G8 }, // BLACK
{ B1, G1 } // WHITE
@@ -3819,8 +3819,8 @@ Return value:
//
// TODO: Don't block unmoved E2/D2 pawns
- //
-
+ //
+
//
// Centrality bonus
//
@@ -3859,13 +3859,13 @@ Return value:
uPawnsSupporting = 0;
p = BLACK_PAWN | uColor;
cSquare = c + iPawnStart[uColor];
- uPawnsSupporting = (IS_ON_BOARD(cSquare) &&
+ uPawnsSupporting = (IS_ON_BOARD(cSquare) &&
(pos->rgSquare[cSquare].pPiece == p));
cSquare += 2;
uPawnsSupporting += (IS_ON_BOARD(cSquare) &&
(pos->rgSquare[cSquare].pPiece == p));
ASSERT(uPawnsSupporting <= 2);
-
+
//
// Give a bonus based on distance from enemy king
//
@@ -3877,7 +3877,7 @@ Return value:
pos->iReducedMaterialDownScaler[uColor],
i,
"[scaled] unassailable/support");
-
+
//
// Now, if there's zero or one supporter see if the enemy has a
// bishop the color of the knight it could capture with.
@@ -3898,7 +3898,7 @@ Return value:
}
else
{
- if (pos->uNonPawnCount[FLIP(uColor)][BISHOP] -
+ if (pos->uNonPawnCount[FLIP(uColor)][BISHOP] -
pos->uWhiteSqBishopCount[FLIP(uColor)])
{
EVAL_TERM(uColor,
@@ -3910,7 +3910,7 @@ Return value:
}
}
}
- }
+ }
else // not outposted
{
//
@@ -3924,7 +3924,7 @@ Return value:
i,
"[scaled] enemy king tropism");
}
-
+
//
// Give a bonus for blockading an enemy backward pawn. Note:
// we also reward pieces for blocking enemy passers in the
@@ -3946,7 +3946,7 @@ Return value:
//
// A knight with an open file behind it is good.
- //
+ //
uPawnFile = FILE(c) + 1;
EVAL_TERM(uColor,
KNIGHT,
@@ -3955,7 +3955,7 @@ Return value:
((pHash->uCountPerFile[uColor][uPawnFile] == 0) *
KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[uColor][RANK(c)]),
"open file behind");
-
+
//
// Do mobilility and piece relevance. Also update attack tables.
//
@@ -4007,13 +4007,13 @@ Return value:
}
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uMobilitySquares & 0x80000000) == 0);
- pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
+ pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uMobilitySquares);
}
static void
-_EvalRook(IN OUT POSITION *pos,
- IN COOR c,
+_EvalRook(IN OUT POSITION *pos,
+ IN COOR c,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -4031,7 +4031,7 @@ Return value:
**/
{
- static const PMOBILITY_HELPER RMobJumpTable[2][14] =
+ static const PMOBILITY_HELPER RMobJumpTable[2][14] =
{
{// (black)
_BRookToEmpty, // EMPTY_SQUARE (0)
@@ -4080,14 +4080,14 @@ Return value:
ULONG uBit;
PMOBILITY_HELPER pFun;
SCORE i;
-
+
ASSERT(IS_ON_BOARD(c));
p = pos->rgSquare[c].pPiece;
ASSERT(p && IS_ROOK(p));
uColor = GET_COLOR(p);
ASSERT(IS_VALID_COLOR(uColor));
pos->cPiece = c;
-
+
//
// Reward being on a half open or full open file.
//
@@ -4117,7 +4117,7 @@ Return value:
pos->iScore[uColor],
ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[u],
"on half open");
-
+
//
// Added bonus if the enemy pawn is a passer.
//
@@ -4126,7 +4126,7 @@ Return value:
{
cSquare = CoorFromBitBoardRank8ToRank1(&bb);
EVAL_TERM(uColor,
- ROOK,
+ ROOK,
c,
pos->iScore[uColor],
PASSER_BY_RANK[FLIP(uColor)][RANK(cSquare)] / 4,
@@ -4160,7 +4160,7 @@ Return value:
//
while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
{
- if (uColor == WHITE)
+ if (uColor == WHITE)
{
if (cSquare < c)
{
@@ -4208,22 +4208,22 @@ Return value:
}
}
}
-
+
//
// Look for rooks that are trapping enemy kings.
- //
- if (uColor == WHITE)
+ //
+ if (uColor == WHITE)
{
pFriendRook = WHITE_ROOK;
//
// Rook on 7th/8th rank with an enemy king back there.
- //
+ //
if ((c < A6) && (pos->cNonPawns[BLACK][0] < A6))
{
ASSERT(RANK(c) > 6);
ASSERT(RANK(pos->cNonPawns[BLACK][0]) > 6);
-
+
EVAL_TERM(WHITE,
ROOK,
c,
@@ -4232,13 +4232,13 @@ Return value:
"rook trapping enemy king");
}
}
- else
+ else
{
pFriendRook = BLACK_ROOK;
//
// Rook on 7th/8th rank with an enemy king back there.
- //
+ //
if ((c > H3) && (pos->cNonPawns[WHITE][0] > H3))
{
ASSERT(RANK(c) < 3);
@@ -4251,17 +4251,17 @@ Return value:
"rook trapping enemy king");
}
}
-
+
//
// Rooks increase in value as pawns come off:
- //
+ //
// "A further refinement would be to raise the knight's value by
// 1/16 and lower the rook's value by 1/8 for each pawn above five
// of the side being valued, with the opposite adjustment for each
// pawn short of five."
// --Larry Kaufman, IM
// "Evaluation of Material Imbalance"
- //
+ //
EVAL_TERM(uColor,
ROOK,
c,
@@ -4269,7 +4269,7 @@ Return value:
ROOK_VALUE_AS_PAWNS_COME_OFF[pos->uPawnCount[uColor] +
pos->uPawnCount[FLIP(uColor)]],
"increase in value/pawns");
-
+
//
// Rook mobility
//
@@ -4280,7 +4280,7 @@ Return value:
uCurrentMobility = 0;
uBit = ROOK_BIT;
cSquare = c + g_iRDeltas[u];
-
+
while(IS_ON_BOARD(cSquare))
{
//
@@ -4334,7 +4334,7 @@ Return value:
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
- pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
+ pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
if (uTotalMobility < 3)
{
@@ -4349,7 +4349,7 @@ Return value:
//
// Rook trapped in the corner by a stupid friendly king?
- //
+ //
ASSERT(IS_VALID_COLOR(uColor));
if (uColor == WHITE)
{
@@ -4373,7 +4373,7 @@ Return value:
}
}
}
- else
+ else
{
ASSERT(uColor == BLACK);
ASSERT(IS_ON_BOARD(c));
@@ -4381,7 +4381,7 @@ Return value:
{
cSquare = pos->cNonPawns[BLACK][0];
ASSERT(IS_ON_BOARD(cSquare));
-
+
if (RANK8(cSquare))
{
if (((cSquare > E8) && (c > cSquare)) ||
@@ -4402,8 +4402,8 @@ Return value:
static void
-_EvalQueen(IN OUT POSITION *pos,
- IN COOR c,
+_EvalQueen(IN OUT POSITION *pos,
+ IN COOR c,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -4419,7 +4419,7 @@ Return value:
**/
{
- static const PMOBILITY_HELPER QMobJumpTable[2][14] =
+ static const PMOBILITY_HELPER QMobJumpTable[2][14] =
{
{
_BQueenToEmpty, // EMPTY_SQUARE (0)
@@ -4473,12 +4473,12 @@ Return value:
cKing = pos->cNonPawns[FLIP(uColor)][0];
ASSERT(IS_ON_BOARD(cKing));
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
-
+
if ((FALSE == pos->fCastled[uColor]) && (pos->uMinorsAtHome[uColor] > 1))
{
//
// Discourage queen being out too early
- //
+ //
if (!RANK1(c) && !RANK8(c))
{
ASSERT(QUEEN_OUT_EARLY[pos->uMinorsAtHome[uColor]] < 0);
@@ -4522,7 +4522,7 @@ Return value:
// Toggle attack table bits.
//
pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
-
+
//
// What did we hit?
//
@@ -4560,7 +4560,7 @@ Return value:
}
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
- pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
+ pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
//
@@ -4576,8 +4576,8 @@ Return value:
}
static void
-_EvalKing(IN OUT POSITION *pos,
- IN const COOR c,
+_EvalKing(IN OUT POSITION *pos,
+ IN const COOR c,
IN const PAWN_HASH_ENTRY *pHash)
/**
@@ -4613,27 +4613,27 @@ Return value:
{
+4, +2, +1, 0, 0, 0, 0, 0, 0
};
-
+
static ULONG KingStormingPawnDefects[8] =
{
+0, +4, +3, +1, +0, +0, +0, +0
};
- static ULONG KingFileDefects[3] =
+ static ULONG KingFileDefects[3] =
{
+2, +1, +0
};
- static INT KingSafetyDeltas[11] =
+ static INT KingSafetyDeltas[11] =
{
-17, -16, -15,
-1, +1,
+15, +16, +17, -2, +2, 0
};
-
- static ULONG EmptyAttackedSquare[2][11] =
+
+ static ULONG EmptyAttackedSquare[2][11] =
{
- {
+ {
1, 1, 1,
1, 1,
2, 2, 2, 1, 1, 0
@@ -4645,9 +4645,9 @@ Return value:
},
};
- static ULONG EmptyUnattackedSquare[2][11] =
+ static ULONG EmptyUnattackedSquare[2][11] =
{
- {
+ {
0, 0, 0,
0, 0,
1, 1, 1, 0, 0, 0
@@ -4658,20 +4658,20 @@ Return value:
0, 0, 0, 0, 0, 0
},
};
-
- static ULONG OccupiedAttackedSquare[2] =
+
+ static ULONG OccupiedAttackedSquare[2] =
{
1,
2
};
-
+
ASSERT(IS_ON_BOARD(c));
p = pos->rgSquare[c].pPiece;
ASSERT(p && IS_KING(p));
uColor = GET_COLOR(p);
ufColor = FLIP(uColor);
ASSERT(IS_VALID_COLOR(uColor));
-
+
u = pos->uNonPawnMaterial[ufColor];
ASSERT(u >= VALUE_KING);
if (u < DO_KING_SAFETY_THRESHOLD)
@@ -4692,7 +4692,7 @@ Return value:
}
// Prepare to do king safety
- uCounter = (u >= KEEP_KING_AT_HOME_THRESHOLD) *
+ uCounter = (u >= KEEP_KING_AT_HOME_THRESHOLD) *
KING_INITIAL_COUNTER_BY_LOCATION[uColor][c];
#ifdef EVAL_DUMP
Trace("%s Initial KS Counter: %u\n", COLOR_NAME(uColor), uCounter);
@@ -4700,7 +4700,7 @@ Return value:
uCounter += pos->uPiecesPointingAtKing[uColor] / 2;
#ifdef EVAL_DUMP
- Trace("%s KS Counter after pieces pointing: %u\n",
+ Trace("%s KS Counter after pieces pointing: %u\n",
COLOR_NAME(uColor), uCounter);
#endif
uFlightSquares = 0;
@@ -4712,13 +4712,13 @@ Return value:
if (IS_ON_BOARD(cSquare))
{
p = pos->rgSquare[cSquare].pPiece;
-
+
cSquare |= 8;
bvAttack = pos->rgSquare[cSquare].bvAttacks[ufColor].uSmall;
bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray;
pos->rgSquare[cSquare].bvAttacks[uColor].small.uKing = 1;
bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall;
-
+
if (bvAttack != 0)
{
bvPattern |= (bvAttack | bvXray);
@@ -4733,7 +4733,7 @@ Return value:
}
else
{
- uCounter +=
+ uCounter +=
OccupiedAttackedSquare[OPPOSITE_COLORS(p, uColor)];
}
uCounter += (bvDefend == 0);
@@ -4779,7 +4779,7 @@ Return value:
uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
}
}
-
+
u = FILE(c) + 1;
v = (pHash->uCountPerFile[WHITE][u] > 0) +
(pHash->uCountPerFile[BLACK][u] > 0);
@@ -4809,10 +4809,10 @@ Return value:
v = (pHash->uCountPerFile[WHITE][u] > 0) +
(pHash->uCountPerFile[BLACK][u] > 0);
ASSERT((v >= 0) && (v <= 2));
-
+
// Note: open rook files are worse than open interior files
uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
-
+
bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
if (bb)
{
@@ -4827,9 +4827,9 @@ Return value:
ASSERT(IS_ON_BOARD(cSquare));
uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
}
- }
+ }
#ifdef EVAL_DUMP
- Trace("%s KS Counter post-open file/stormers: %u\n", COLOR_NAME(uColor),
+ Trace("%s KS Counter post-open file/stormers: %u\n", COLOR_NAME(uColor),
uCounter);
#endif
@@ -4839,10 +4839,10 @@ Return value:
v = KING_COUNTER_BY_ATTACK_PATTERN[bvPattern];
uCounter += v;
#ifdef EVAL_DUMP
- Trace("%s KS Counter post-attack pattern: %u\n", COLOR_NAME(uColor),
+ Trace("%s KS Counter post-attack pattern: %u\n", COLOR_NAME(uColor),
uCounter);
#endif
-
+
ASSERT(uFlightSquares <= 8);
uCounter += KingFlightDefects[uFlightSquares] * (v > 1);
#ifdef EVAL_DUMP
@@ -4916,11 +4916,11 @@ Return value:
}
}
}
-
+
skip_safety:
//
// Special code for kings in the endgame
- //
+ //
u = pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0];
if (u < 8)
{
@@ -4937,9 +4937,9 @@ Return value:
//
// Kings in front of passers in the late endgame are strong...
- //
+ //
cSquare = FILE(c);
- bb = pHash->bbPasserLocations[uColor] &
+ bb = pHash->bbPasserLocations[uColor] &
(BBADJACENT_FILES[cSquare] | BBFILE[cSquare]);
if (bb)
{
@@ -4949,7 +4949,7 @@ Return value:
{
ASSERT(abs((INT)FILE(c) - (INT)FILE(cSquare)) <= 1);
ASSERT(abs((INT)RANK(c) - (INT)RANK(cSquare)) <= 1);
-
+
i = 2;
i += SUPPORTED_PASSER_BY_RANK[uColor][RANK(cSquare)];
switch(uColor)
@@ -4957,7 +4957,7 @@ Return value:
case WHITE:
i += 8 * (c < (cSquare - 1));
break;
-
+
case BLACK:
i += 8 * (c > (cSquare + 1));
break;
@@ -4971,12 +4971,12 @@ Return value:
}
}
}
-
+
//
// Detect kings way out of the action in KP endgames:
- //
+ //
// 8/8/1p6/p6k/P3K3/8/1P6/8 w - - 0 11
- //
+ //
if ((u == 2) && (uColor == WHITE))
{
i = 0;
@@ -5001,7 +5001,7 @@ Return value:
FLAG
-EvalPasserRaces(IN OUT POSITION *pos,
+EvalPasserRaces(IN OUT POSITION *pos,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -5074,24 +5074,24 @@ Return value:
uPawnDist--;
}
ASSERT((uPawnDist >= 1) && (uPawnDist <= 6));
-
+
uKingDist = DISTANCE(cKing, cQueen);
- if (uKingDist > 0)
+ if (uKingDist > 0)
{
uKingDist -= (pos->uToMove == FLIP(uColor));
}
ASSERT((uKingDist >= 0) && (uPawnDist <= 7));
-
+
if (uPawnDist < uKingDist)
{
uRacerDist[uColor] = MINU(uRacerDist[uColor],
uPawnDist);
}
-
+
cKing = pos->cNonPawns[uColor][0];
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uColor);
-
+
uFriendDist = DISTANCE(cKing, cQueen);
if ((uFriendDist <= 1) && (DISTANCE(cKing, c) <= 1))
{
@@ -5108,8 +5108,8 @@ Return value:
}
}
fDontCountMeOut[uColor] = TRUE;
-
- //
+
+ //
// TODO: winning connected passers
//
}
@@ -5117,7 +5117,7 @@ Return value:
}
}
- if ((uRacerDist[WHITE] < uRacerDist[BLACK]) &&
+ if ((uRacerDist[WHITE] < uRacerDist[BLACK]) &&
(FALSE == fDontCountMeOut[BLACK]))
{
EVAL_TERM(WHITE,
@@ -5143,8 +5143,8 @@ Return value:
}
-static void
-_EvalPassers(IN OUT POSITION *pos,
+static void
+_EvalPassers(IN OUT POSITION *pos,
IN PAWN_HASH_ENTRY *pHash)
/**
@@ -5173,7 +5173,7 @@ Return value:
ASSERT(pHash->bbPasserLocations[WHITE] |
pHash->bbPasserLocations[BLACK]);
-
+
FOREACH_COLOR(uColor)
{
bb = pHash->bbPasserLocations[uColor];
@@ -5183,7 +5183,7 @@ Return value:
ASSERT(uNumPassers[uColor] > 0);
d1 = 16 * g_iAhead[uColor];
ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
-
+
while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bb)))
{
//
@@ -5222,23 +5222,23 @@ Return value:
ASSERT(u == uColor);
}
#endif
-
+
//
// Consider distance from friend king / enemy king
//
i = (8 - DISTANCE(c, pos->cNonPawns[uColor][0]));
- if (((uColor == WHITE) &&
+ if (((uColor == WHITE) &&
((pos->cNonPawns[BLACK][0] >> 4) <= (c >> 4))) ||
((uColor == BLACK) &&
((pos->cNonPawns[WHITE][0] >> 4) >= (c >> 4)))) {
- //
+ //
// The enemy king is ahead of the passer
//
i += FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
}
else
{
- //
+ //
// The enemy king is behind the passer
//
i += 10 + DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
@@ -5251,12 +5251,12 @@ Return value:
pos->iScore[uColor],
i,
"passer distance to kings");
-
+
//
// If a side is a piece down then the other side's passers
// are even more dangerous.
//
- if (pos->uNonPawnCount[uColor][0] >
+ if (pos->uNonPawnCount[uColor][0] >
pos->uNonPawnCount[FLIP(uColor)][0])
{
i = (PASSER_BY_RANK[uColor][RANK(c)] / 2);
@@ -5274,10 +5274,10 @@ Return value:
}
}
}
-
+
//
// Game stage bonus
- //
+ //
u = pos->uArmyScaler[BLACK];
EVAL_TERM(WHITE,
PAWN,
@@ -5297,7 +5297,7 @@ Return value:
}
-static void
+static void
_EvalBadTrades(IN OUT POSITION *pos)
/**
@@ -5315,7 +5315,7 @@ Return value:
{
ULONG uAhead, uBehind;
ULONG uMagnitude;
-
+
//
// See who is ahead
//
@@ -5335,7 +5335,7 @@ Return value:
ASSERT(uBehind == WHITE);
}
#endif
- uMagnitude = ((pos->uNonPawnMaterial[uAhead] +
+ uMagnitude = ((pos->uNonPawnMaterial[uAhead] +
pos->uNonPawnCount[uAhead][0] * 128) -
(pos->uNonPawnMaterial[uBehind] +
pos->uNonPawnCount[uBehind][0] * 128));
@@ -5384,9 +5384,9 @@ Routine description:
which the attack table was generated, we will have missed
situations where a piece is undefended (or underdefended) and
attacked by an enemy piece that is the same (or greater) value.
-
+
Note: This routine only considers side to move.
-
+
Also Note: this routine does not find pawns that are en prise, only
pieces.
@@ -5397,7 +5397,7 @@ Parameters:
Return value:
void
-
+
**/
{
COOR c;
@@ -5428,7 +5428,7 @@ Return value:
}
-static void
+static void
_EvalTrappedPieces(IN OUT SEARCHER_THREAD_CONTEXT *ctx)
/**
@@ -5530,9 +5530,9 @@ Return value:
-SCORE
-Eval(IN SEARCHER_THREAD_CONTEXT *ctx,
- IN SCORE iAlpha,
+SCORE
+Eval(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN SCORE iAlpha,
IN SCORE iBeta)
/**
@@ -5585,28 +5585,28 @@ Return value:
ASSERT(IS_VALID_SCORE(iAlpha));
ASSERT(IS_VALID_SCORE(iBeta));
ASSERT(iAlpha < iBeta);
- ASSERT((pos->iMaterialBalance[WHITE] * -1) ==
+ ASSERT((pos->iMaterialBalance[WHITE] * -1) ==
pos->iMaterialBalance[BLACK]);
// ASSERT(!InCheck(pos, pos->uToMove));
pos->uMinMobility[BLACK] = pos->uMinMobility[WHITE] = 100;
pos->cTrapped[BLACK] = pos->cTrapped[WHITE] = ILLEGAL_COOR;
-
+
#ifdef EVAL_HASH
//
// Check the eval hash
- //
+ //
iScoreForSideToMove = ProbeEvalHash(ctx, iAlpha, iBeta);
- if (iScoreForSideToMove != INVALID_SCORE)
+ if (iScoreForSideToMove != INVALID_SCORE)
{
INC(ctx->sCounters.tree.u64EvalHashHits);
goto end;
}
#endif
- pos->iScore[BLACK] =
+ pos->iScore[BLACK] =
(pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]);
- pos->iScore[WHITE] =
+ pos->iScore[WHITE] =
(pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]);
#ifdef EVAL_DUMP
EvalTraceClear();
@@ -5629,21 +5629,21 @@ Return value:
#ifdef EVAL_DUMP
Trace("After pawns:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
-
+
//
// Look for won passers races. Note: This code cannot trust the
// state of the attack tables yet!
//
- if ((pos->uNonPawnCount[WHITE][0] == 1) ||
+ if ((pos->uNonPawnCount[WHITE][0] == 1) ||
(pos->uNonPawnCount[BLACK][0] == 1))
{
(void)EvalPasserRaces(pos, pHash);
#ifdef EVAL_DUMP
- Trace("After passer races:\n%d\t\t%d\n", pos->iScore[WHITE],
+ Trace("After passer races:\n%d\t\t%d\n", pos->iScore[WHITE],
pos->iScore[BLACK]);
#endif
}
-
+
//
// Bad trade code. Right. Note: this code cannot trust the state
// of the attack tables...
@@ -5652,7 +5652,7 @@ Return value:
{
_EvalBadTrades(pos);
#ifdef EVAL_DUMP
- Trace("After bad trades:\n%d\t\t%d\n", pos->iScore[WHITE],
+ Trace("After bad trades:\n%d\t\t%d\n", pos->iScore[WHITE],
pos->iScore[BLACK]);
#endif
}
@@ -5663,7 +5663,7 @@ Return value:
//
_EvalBishopPairs(pos);
#ifdef EVAL_DUMP
- Trace("After bishop pair bonus:\n%d\t\t%d\n", pos->iScore[WHITE],
+ Trace("After bishop pair bonus:\n%d\t\t%d\n", pos->iScore[WHITE],
pos->iScore[BLACK]);
#endif
@@ -5671,7 +5671,7 @@ Return value:
//
// Compute an estimate of the score for the side to move based on the
// eval terms we have already considered:
- //
+ //
// 1. Material balance
// 2. Pawn structure bonuses/penalties (incl passers/candidates)
// 3. Passer races are detected already
@@ -5679,30 +5679,30 @@ Return value:
// 5. We've already detected unwinnable endgames
// 6. Bishop pairs
//
- iScoreForSideToMove = (pos->iScore[pos->uToMove] -
+ iScoreForSideToMove = (pos->iScore[pos->uToMove] -
pos->iScore[FLIP(pos->uToMove)]);
ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
//
// Eval has not considered several potentially large terms:
- //
+ //
// 1. Piece positional components (such as mobility, trapped)
// 2. King safety penalties
// 3. Other miscellaneous bonuses/penalties
//
// We build two "margins" to account for these components of the
// score.
- //
+ //
iAlphaMargin = iBetaMargin = (50 + (SCORE)ctx->uPositional);
-
+
//
// If (score + alpha_margin) is already > alpha -OR-
- // (score - beta_margin) is already < beta
- //
+ // (score - beta_margin) is already < beta
+ //
// ...then we can stop thinking about lazy eval; the rest of the
// computation only increases the margin so we know LE will fail
// and can save some work here.
- //
+ //
if ((iScoreForSideToMove + iAlphaMargin < iAlpha) ||
(iScoreForSideToMove - iBetaMargin > iBeta))
{
@@ -5711,7 +5711,7 @@ Return value:
// yet. So do the expensive part of lazy eval estimation and
// widen the margin further for king safety issues and passed
// pawns.
- //
+ //
_QuicklyEstimateKingSafetyTerm(pos, &iAlphaMargin, &iBetaMargin);
_QuicklyEstimatePasserBonuses(pos, pHash, &iAlphaMargin, &iBetaMargin);
@@ -5753,7 +5753,7 @@ Return value:
{
_PopulatePawnAttackBits(pos);
}
-
+
//
// Pre-compute some common terms used in per-piece evals:
//
@@ -5771,7 +5771,7 @@ Return value:
ASSERT(pos->uArmyScaler[BLACK] <= 31);
ASSERT(pos->uArmyScaler[WHITE] >= 0);
ASSERT(pos->uArmyScaler[WHITE] <= 31);
- pos->iReducedMaterialDownScaler[BLACK] =
+ pos->iReducedMaterialDownScaler[BLACK] =
pos->iReducedMaterialDownScaler[WHITE] = 0;
//
@@ -5804,7 +5804,7 @@ Return value:
if (p & 0x4)
{
ASSERT(IS_BISHOP(p) || IS_KNIGHT(p));
-
+
//
// Note: The side on move's pieces of value X are
// evaluated and have their mobility counted and added to
@@ -5826,7 +5826,7 @@ Return value:
cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
}
}
-
+
uColor = FLIP(uColor);
ASSERT(uColor != pos->uToMove);
for (u = 1;
@@ -5862,10 +5862,10 @@ Return value:
cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
}
}
-
+
//
// Evaluate any rook(s) for side on move then for side not on move.
- //
+ //
uColor = FLIP(uColor);
for (u = 0;
u < uDefer[uColor][0];
@@ -5882,7 +5882,7 @@ Return value:
pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
}
-
+
uColor = FLIP(uColor);
for (u = 0;
u < uDefer[uColor][0];
@@ -5902,7 +5902,7 @@ Return value:
//
// Evaluate any queen(s) for side on move then for side not on move.
- //
+ //
uColor = FLIP(uColor);
for (u = 0;
u < uDefer[uColor][1];
@@ -5919,7 +5919,7 @@ Return value:
pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
}
-
+
uColor = FLIP(uColor);
for (u = 0;
u < uDefer[uColor][1];
@@ -5936,7 +5936,7 @@ Return value:
pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
}
-
+
//
// Evaluate the two kings last.
//
@@ -5954,7 +5954,7 @@ Return value:
#ifdef EVAL_DUMP
Trace("After *k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
-
+
c = pos->cNonPawns[WHITE][0];
#ifdef DEBUG
ASSERT(IS_ON_BOARD(c));
@@ -5969,7 +5969,7 @@ Return value:
#ifdef EVAL_DUMP
Trace("After .k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
-
+
//
// Now that we have the whole attack table generated, think about
// passed pawns identified by the pawn eval routine again. Also
@@ -5980,7 +5980,7 @@ Return value:
{
_EvalPassers(pos, pHash);
#ifdef EVAL_DUMP
- Trace("After passers:\n%d\t\t%d\n", pos->iScore[WHITE],
+ Trace("After passers:\n%d\t\t%d\n", pos->iScore[WHITE],
pos->iScore[BLACK]);
#endif
}
@@ -5998,7 +5998,7 @@ Return value:
//
// B over N in the endgame with 2 pawn wings.
- //
+ //
if ((pos->uNonPawnCount[WHITE][0] <= 2) &&
(pos->uNonPawnCount[BLACK][0] <= 2))
{
@@ -6016,7 +6016,7 @@ Return value:
pos->iScore[WHITE] /= 2;
pos->iScore[BLACK] /= 2;
}
- }
+ }
}
else
{
@@ -6025,11 +6025,11 @@ Return value:
// with two pawn wings where having a bishop is an
// advantage.
//
- bb = (pHash->bbPawnLocations[WHITE] |
+ bb = (pHash->bbPawnLocations[WHITE] |
pHash->bbPawnLocations[BLACK]);
- ASSERT((BBFILE[A] | BBFILE[B] | BBFILE[C]) ==
+ ASSERT((BBFILE[A] | BBFILE[B] | BBFILE[C]) ==
0x0707070707070707ULL);
- ASSERT((BBFILE[F] | BBFILE[G] | BBFILE[H]) ==
+ ASSERT((BBFILE[F] | BBFILE[G] | BBFILE[H]) ==
0xe0e0e0e0e0e0e0e0ULL);
if ((bb & 0x0707070707070707ULL) &&
(bb & 0xe0e0e0e0e0e0e0e0ULL))
@@ -6059,7 +6059,7 @@ Return value:
}
}
#ifdef EVAL_DUMP
- Trace("After BOOC / BvsN:\n%d\t\t%d\n",
+ Trace("After BOOC / BvsN:\n%d\t\t%d\n",
pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
}
@@ -6068,12 +6068,12 @@ Return value:
// Roll in the reduced material down scaler terms.
//
ASSERT(pos->iReducedMaterialDownScaler[BLACK] > -200);
- ASSERT(pos->iReducedMaterialDownScaler[BLACK] < +200);
+ ASSERT(pos->iReducedMaterialDownScaler[BLACK] < +200);
iAlphaMargin = (pos->iReducedMaterialDownScaler[BLACK] *
(SCORE)REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[BLACK]]) / 8;
pos->iScore[BLACK] += iAlphaMargin;
ASSERT(pos->iReducedMaterialDownScaler[WHITE] > -200);
- ASSERT(pos->iReducedMaterialDownScaler[WHITE] < +200);
+ ASSERT(pos->iReducedMaterialDownScaler[WHITE] < +200);
iAlphaMargin = (pos->iReducedMaterialDownScaler[WHITE] *
(SCORE)REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[WHITE]]) / 8;
pos->iScore[WHITE] += iAlphaMargin;
@@ -6081,13 +6081,13 @@ Return value:
//
// Almost done
//
- iScoreForSideToMove = (pos->iScore[pos->uToMove] -
+ iScoreForSideToMove = (pos->iScore[pos->uToMove] -
pos->iScore[FLIP(pos->uToMove)]);
#ifdef EVAL_DUMP
- Trace("At the end:\n%d\t\t%d\n", pos->iScore[WHITE],
+ Trace("At the end:\n%d\t\t%d\n", pos->iScore[WHITE],
pos->iScore[BLACK]);
#endif
-
+
//
// TODO: detect and discourage blocked positions?
//
@@ -6111,9 +6111,9 @@ Return value:
ctx->uPositional = MAXU(ctx->uPositional, VALUE_PAWN);
}
g_Options.iLastEvalScore = iScoreForSideToMove;
-
+
#ifdef EVAL_TIME
- ctx->sCounters.tree.u64CyclesInEval += (SystemReadTimeStampCounter() -
+ ctx->sCounters.tree.u64CyclesInEval += (SystemReadTimeStampCounter() -
uTimer);
#endif
INC(ctx->sCounters.tree.u64FullEvals);
@@ -6127,7 +6127,7 @@ Return value:
end:
ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
- ASSERT((iScoreForSideToMove > -NMATE) &&
+ ASSERT((iScoreForSideToMove > -NMATE) &&
(iScoreForSideToMove < +NMATE));
ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[BLACK]) < 700);
ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[WHITE]) < 700);
diff --git a/src/fathom/LICENSE b/src/fathom/LICENSE
new file mode 100644
index 0000000..274394e
--- /dev/null
+++ b/src/fathom/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2018 Ronald de Man
+Copyright (c) 2015 basil00
+Copyright (c) 2016-2025 by Jon Dart
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/src/fathom/stdendian.h b/src/fathom/stdendian.h
new file mode 100644
index 0000000..9f598b5
--- /dev/null
+++ b/src/fathom/stdendian.h
@@ -0,0 +1,286 @@
+#ifndef _STDENDIAN_H_
+#define _STDENDIAN_H_
+/* from https://gist.github.com/michaeljclark/3b4fd912f6fa8bb598b3 */
+/* modified to use functions not macros for bswap */
+/* and added a fix for Cygwin */
+/*
+ * stdendian.h
+ *
+ * This header defines the following endian macros as defined here:
+ * http://austingroupbugs.net/view.php?id=162
+ *
+ * BYTE_ORDER this macro shall have a value equal to one
+ * of the *_ENDIAN macros in this header.
+ * LITTLE_ENDIAN if BYTE_ORDER == LITTLE_ENDIAN, the host
+ * byte order is from least significant to
+ * most significant.
+ * BIG_ENDIAN if BYTE_ORDER == BIG_ENDIAN, the host byte
+ * order is from most significant to least
+ * significant.
+ *
+ * The following are defined as macros:
+ *
+ * uint16_t bswap16(uint16_t x);
+ * uint32_t bswap32(uint32_t x);
+ * uint64_t bswap64(uint64_t x);
+
+ * uint16_t htobe16(uint16_t x);
+ * uint16_t htole16(uint16_t x);
+ * uint16_t be16toh(uint16_t x);
+ * uint16_t le16toh(uint16_t x);
+ *
+ * uint32_t htobe32(uint32_t x);
+ * uint32_t htole32(uint32_t x);
+ * uint32_t be32toh(uint32_t x);
+ * uint32_t le32toh(uint32_t x);
+ *
+ * uint64_t htobe64(uint64_t x);
+ * uint64_t htole64(uint64_t x);
+ * uint64_t be64toh(uint64_t x);
+ * uint64_t le64toh(uint64_t x);
+ *
+ * The header defines the following macro for OpenCL compatibility
+ * https://www.khronos.org/registry/cl/sdk/2.0/docs/man/xhtml/preprocessorDirectives.html
+ *
+ * __ENDIAN_LITTLE__ if BYTE_ORDER == LITTLE_ENDIAN then this
+ * macro is present for OpenCL compatibility
+ *
+ * The implementation provides a uniform interface to endian macros using only
+ * system headers on recent Linux, Darwin, FreeBSD, Solaris and Windows systems.
+ *
+ * This approach is intended to avoid the need for preflight configure scripts.
+ * An alternative approach would be to test compiler CPU architecture marcros.
+ *
+ * This header has had *limited* testing on recent C11/C++11 compilers and is
+ * based on the austin bug tracker interface, manpages, and headers present in
+ * Linux, FreeBSD, Windows, Solaris and Darwin.
+ *
+ * The header uses __builtin_bswapXX intrinsic with GCC/Clang (__GNUC__) on
+ * platforms that do not provide bswap16, bswap32, bswap64 (Darwin)
+ *
+ * Public Domain.
+ */
+
+/* requires C11 or C++11 */
+#if defined (__cplusplus)
+#include <cstdint>
+#elif !defined (__OPENCL_VERSION__)
+#include <stdint.h>
+#endif
+
+/* Linux / GLIBC */
+#if defined(__linux__) || defined(__GLIBC__) || defined(__CYGWIN__)
+#include <endian.h>
+#include <byteswap.h>
+#define __ENDIAN_DEFINED 1
+#define __BSWAP_DEFINED 1
+#define __HOSTSWAP_DEFINED 1
+// NDK defines _BYTE_ORDER etc
+#ifndef _BYTE_ORDER
+#define _BYTE_ORDER __BYTE_ORDER
+#define _LITTLE_ENDIAN __LITTLE_ENDIAN
+#define _BIG_ENDIAN __BIG_ENDIAN
+#endif
+#define bswap16(x) bswap_16(x)
+#define bswap32(x) bswap_32(x)
+#define bswap64(x) bswap_64(x)
+#endif /* __linux__ || __GLIBC__ */
+
+/* BSD */
+#if defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__DragonFly__) || defined(__OpenBSD__)
+#include <sys/endian.h>
+#define __ENDIAN_DEFINED 1
+#define __BSWAP_DEFINED 1
+#define __HOSTSWAP_DEFINED 1
+#endif /* BSD */
+
+/* Solaris */
+#if defined (sun)
+#include <sys/isa_defs.h>
+/* sun headers don't set a value for _LITTLE_ENDIAN or _BIG_ENDIAN */
+#if defined(_LITTLE_ENDIAN)
+#undef _LITTLE_ENDIAN
+#define _LITTLE_ENDIAN 1234
+#define _BIG_ENDIAN 4321
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#elif defined(_BIG_ENDIAN)
+#undef _BIG_ENDIAN
+#define _LITTLE_ENDIAN 1234
+#define _BIG_ENDIAN 4321
+#define _BYTE_ORDER _BIG_ENDIAN
+#endif
+#define __ENDIAN_DEFINED 1
+#endif /* sun */
+
+/* Windows */
+/* assumes all Microsoft targets are little endian. */
+/* Emscripten (emcc) also currently assumes little endian. */
+#if defined(_WIN32) || defined(_MSC_VER) || defined(__EMSCRIPTEN__)
+#define _LITTLE_ENDIAN 1234
+#define _BIG_ENDIAN 4321
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#define __ENDIAN_DEFINED 1
+#endif /* _MSC_VER */
+
+/* OS X */
+#if defined(__APPLE__)
+#include <machine/endian.h>
+#define _BYTE_ORDER BYTE_ORDER
+#define _LITTLE_ENDIAN LITTLE_ENDIAN
+#define _BIG_ENDIAN BIG_ENDIAN
+#define __ENDIAN_DEFINED 1
+#endif /* __APPLE__ */
+
+/* OpenCL */
+#if defined (__OPENCL_VERSION__)
+#define _LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#if defined (__ENDIAN_LITTLE__)
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#else
+#define _BYTE_ORDER _BIG_ENDIAN
+#endif
+#define bswap16(x) as_ushort(as_uchar2(ushort(x)).s1s0)
+#define bswap32(x) as_uint(as_uchar4(uint(x)).s3s2s1s0)
+#define bswap64(x) as_ulong(as_uchar8(ulong(x)).s7s6s5s4s3s2s1s0)
+#define __ENDIAN_DEFINED 1
+#define __BSWAP_DEFINED 1
+#endif
+
+/* Unknown */
+#if !__ENDIAN_DEFINED
+#error Could not determine CPU byte order
+#endif
+
+/* POSIX - http://austingroupbugs.net/view.php?id=162 */
+#ifndef BYTE_ORDER
+#define BYTE_ORDER _BYTE_ORDER
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN _LITTLE_ENDIAN
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN _BIG_ENDIAN
+#endif
+
+/* OpenCL compatibility - define __ENDIAN_LITTLE__ on little endian systems */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#if !defined (__ENDIAN_LITTLE__)
+#define __ENDIAN_LITTLE__ 1
+#endif
+#endif
+
+/* Byte swap macros */
+#if !__BSWAP_DEFINED
+
+#ifndef bswap16
+/* handle missing __builtin_bswap16 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52624 */
+#if defined __GNUC__
+#define bswap16(x) __builtin_bswap16(x)
+#else
+inline uint16_t bswap16(uint16_t x) {
+ return (uint16_t)((((uint16_t) (x) & 0xff00) >> 8) | \
+ (((uint16_t) (x) & 0x00ff) << 8));
+}
+#endif
+#endif
+
+#ifndef bswap32
+#if defined __GNUC__
+#define bswap32(x) __builtin_bswap32(x)
+#else
+inline uint32_t bswap32(uint32_t x) {
+ return (( x & 0xff000000) >> 24) | \
+ (( x & 0x00ff0000) >> 8) | \
+ (( x & 0x0000ff00) << 8) | \
+ (( x & 0x000000ff) << 24);
+}
+#endif
+#endif
+
+#ifndef bswap64
+#if defined __GNUC__
+#define bswap64(x) __builtin_bswap64(x)
+#else
+inline uint64_t bswap64(uint64_t x) {
+ return (( x & 0xff00000000000000ull) >> 56) | \
+ (( x & 0x00ff000000000000ull) >> 40) | \
+ (( x & 0x0000ff0000000000ull) >> 24) | \
+ (( x & 0x000000ff00000000ull) >> 8) | \
+ (( x & 0x00000000ff000000ull) << 8) | \
+ (( x & 0x0000000000ff0000ull) << 24) | \
+ (( x & 0x000000000000ff00ull) << 40) | \
+ (( x & 0x00000000000000ffull) << 56);
+}
+#endif
+#endif
+
+#endif
+
+/* Host swap macros */
+#ifndef __HOSTSWAP_DEFINED
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htobe16(x) bswap16((x))
+#define htole16(x) ((uint16_t)(x))
+#define be16toh(x) bswap16((x))
+#define le16toh(x) ((uint16_t)(x))
+
+#define htobe32(x) bswap32((x))
+#define htole32(x) ((uint32_t)(x))
+#define be32toh(x) bswap32((x))
+#define le32toh(x) ((uint32_t)(x))
+
+#define htobe64(x) bswap64((x))
+#define htole64(x) ((uint64_t)(x))
+#define be64toh(x) bswap64((x))
+#define le64toh(x) ((uint64_t)(x))
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define htobe16(x) ((uint16_t)(x))
+#define htole16(x) bswap16((x))
+#define be16toh(x) ((uint16_t)(x))
+#define le16toh(x) bswap16((x))
+
+#define htobe32(x) ((uint32_t)(x))
+#define htole32(x) bswap32((x))
+#define be32toh(x) ((uint32_t)(x))
+#define le64toh(x) bswap64((x))
+
+#define htobe64(x) ((uint64_t)(x))
+#define htole64(x) bswap64((x))
+#define be64toh(x) ((uint64_t)(x))
+#define le32toh(x) bswap32((x))
+#endif
+#endif
+
+/*
+
+#include <stdio.h>
+#include <stdendian.h>
+
+int main()
+{
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+printf("little endian\n");
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+printf("big endian\n");
+#endif
+
+printf("bswap16(%04x) %04x\n", 0xf0e0, bswap16(0xf0e0));
+printf("htobe16(%04x) %04x\n", 0xf0e0, htobe16(0xf0e0));
+printf("htole16(%04x) %04x\n", 0xf0e0, htole16(0xf0e0));
+
+printf("bswap32(%08x) %08x\n", 0xf0e0d0c0, bswap32(0xf0e0d0c0));
+printf("htobe32(%08x) %08x\n", 0xf0e0d0c0, htobe32(0xf0e0d0c0));
+printf("htole32(%08x) %08x\n", 0xf0e0d0c0, htole32(0xf0e0d0c0));
+
+printf("bswap64(%016llx) %016llx\n", 0xf0e0d0c0b0a09080ULL, bswap64(0xf0e0d0c0b0a09080ULL));
+printf("htobe64(%016llx) %016llx\n", 0xf0e0d0c0b0a09080ULL, htobe64(0xf0e0d0c0b0a09080ULL));
+printf("htole64(%016llx) %016llx\n", 0xf0e0d0c0b0a09080ULL, htole64(0xf0e0d0c0b0a09080ULL));
+}
+
+*/
+#endif
diff --git a/src/fathom/tbchess.c b/src/fathom/tbchess.c
new file mode 100644
index 0000000..bca4d1a
--- /dev/null
+++ b/src/fathom/tbchess.c
@@ -0,0 +1,1050 @@
+/*
+Copyright (c) 2015 basil00
+Modifications Copyright (c) 2016-2020 by Jon Dart
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define TB_PAWN 1
+#define TB_KNIGHT 2
+#define TB_BISHOP 3
+#define TB_ROOK 4
+#define TB_QUEEN 5
+#define TB_KING 6
+
+#define TB_WPAWN TB_PAWN
+#define TB_BPAWN (TB_PAWN | 8)
+
+#define WHITE_KING (TB_WPAWN + 5)
+#define WHITE_QUEEN (TB_WPAWN + 4)
+#define WHITE_ROOK (TB_WPAWN + 3)
+#define WHITE_BISHOP (TB_WPAWN + 2)
+#define WHITE_KNIGHT (TB_WPAWN + 1)
+#define WHITE_PAWN TB_WPAWN
+#define BLACK_KING (TB_BPAWN + 5)
+#define BLACK_QUEEN (TB_BPAWN + 4)
+#define BLACK_ROOK (TB_BPAWN + 3)
+#define BLACK_BISHOP (TB_BPAWN + 2)
+#define BLACK_KNIGHT (TB_BPAWN + 1)
+#define BLACK_PAWN TB_BPAWN
+
+#define PRIME_WHITE_QUEEN 11811845319353239651ull
+#define PRIME_WHITE_ROOK 10979190538029446137ull
+#define PRIME_WHITE_BISHOP 12311744257139811149ull
+#define PRIME_WHITE_KNIGHT 15202887380319082783ull
+#define PRIME_WHITE_PAWN 17008651141875982339ull
+#define PRIME_BLACK_QUEEN 15484752644942473553ull
+#define PRIME_BLACK_ROOK 18264461213049635989ull
+#define PRIME_BLACK_BISHOP 15394650811035483107ull
+#define PRIME_BLACK_KNIGHT 13469005675588064321ull
+#define PRIME_BLACK_PAWN 11695583624105689831ull
+
+#define BOARD_RANK_EDGE 0x8181818181818181ull
+#define BOARD_FILE_EDGE 0xFF000000000000FFull
+#define BOARD_EDGE (BOARD_RANK_EDGE | BOARD_FILE_EDGE)
+#define BOARD_RANK_1 0x00000000000000FFull
+#define BOARD_FILE_A 0x8080808080808080ull
+
+#define KEY_KvK 0
+
+#define BEST_NONE 0xFFFF
+#define SCORE_ILLEGAL 0x7FFF
+
+// Note: WHITE, BLACK values are reverse of Stockfish
+#ifdef __cplusplus
+namespace {
+enum Color { BLACK, WHITE };
+enum PieceType { PAWN=1, KNIGHT, BISHOP, ROOK, QUEEN, KING };
+enum Piece {
+ W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
+ B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
+#else
+typedef enum Color { BLACK, WHITE } Color;
+typedef enum PieceType { PAWN=1, KNIGHT, BISHOP, ROOK, QUEEN, KING } PieceType;
+typedef enum Piece {
+ W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
+ B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING
+} Piece;
+#endif
+
+static inline Color ColorOfPiece(int piece) {
+ return (Color)(!(piece >> 3));
+}
+
+static inline PieceType TypeOfPiece(int piece) {
+ return (PieceType)(piece & 7);
+}
+
+typedef int32_t Value;
+
+typedef struct Pos
+{
+ uint64_t white;
+ uint64_t black;
+ uint64_t kings;
+ uint64_t queens;
+ uint64_t rooks;
+ uint64_t bishops;
+ uint64_t knights;
+ uint64_t pawns;
+ uint8_t rule50;
+ uint8_t ep;
+ bool turn;
+} Pos;
+
+static inline uint64_t pieces_by_type(const Pos *pos, Color c, PieceType p) {
+ uint64_t mask = (c == WHITE) ? pos->white : pos->black;
+ switch(p) {
+ case PAWN:
+ return pos->pawns & mask;
+ case KNIGHT:
+ return pos->knights & mask;
+ case BISHOP:
+ return pos->bishops & mask;
+ case ROOK:
+ return pos->rooks & mask;
+ case QUEEN:
+ return pos->queens & mask;
+ case KING:
+ return pos->kings & mask;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+static const char piece_to_char[] = " PNBRQK pnbrqk";
+
+// map upper-case characters to piece types
+static PieceType char_to_piece_type(char c) {
+ for (int i = PAWN; i <= KING; i++)
+ if (c == piece_to_char[i]) {
+ return (PieceType)i;
+ }
+ return (PieceType)0;
+}
+
+#define rank(s) ((s) >> 3)
+#define file(s) ((s) & 0x07)
+#define board(s) ((uint64_t)1 << (s))
+#define square(r, f) (8 * (r) + (f))
+
+#ifdef TB_KING_ATTACKS
+#define king_attacks(s) TB_KING_ATTACKS(s)
+#define king_attacks_init() /* NOP */
+#else /* TB_KING_ATTACKS */
+
+static uint64_t king_attacks_table[64];
+
+#define king_attacks(s) king_attacks_table[(s)]
+
+static void king_attacks_init(void)
+{
+ for (unsigned s = 0; s < 64; s++)
+ {
+ unsigned r = rank(s);
+ unsigned f = file(s);
+ uint64_t b = 0;
+ if (r != 0 && f != 0)
+ b |= board(square(r-1, f-1));
+ if (r != 0)
+ b |= board(square(r-1, f));
+ if (r != 0 && f != 7)
+ b |= board(square(r-1, f+1));
+ if (f != 7)
+ b |= board(square(r, f+1));
+ if (r != 7 && f != 7)
+ b |= board(square(r+1, f+1));
+ if (r != 7)
+ b |= board(square(r+1, f));
+ if (r != 7 && f != 0)
+ b |= board(square(r+1, f-1));
+ if (f != 0)
+ b |= board(square(r, f-1));
+ king_attacks_table[s] = b;
+ }
+}
+
+#endif /* TB_KING_ATTACKS */
+
+#ifdef TB_KNIGHT_ATTACKS
+#define knight_attacks(s) TB_KNIGHT_ATTACKS(s)
+#define knight_attacks_init() /* NOP */
+#else /* TB_KNIGHT_ATTACKS */
+
+static uint64_t knight_attacks_table[64];
+
+#define knight_attacks(s) knight_attacks_table[(s)]
+
+static void knight_attacks_init(void)
+{
+ for (unsigned s = 0; s < 64; s++)
+ {
+ int r1, r = rank(s);
+ int f1, f = file(s);
+ uint64_t b = 0;
+ r1 = r-1; f1 = f-2;
+ if (r1 >= 0 && f1 >= 0)
+ b |= board(square(r1, f1));
+ r1 = r-1; f1 = f+2;
+ if (r1 >= 0 && f1 <= 7)
+ b |= board(square(r1, f1));
+ r1 = r-2; f1 = f-1;
+ if (r1 >= 0 && f1 >= 0)
+ b |= board(square(r1, f1));
+ r1 = r-2; f1 = f+1;
+ if (r1 >= 0 && f1 <= 7)
+ b |= board(square(r1, f1));
+ r1 = r+1; f1 = f-2;
+ if (r1 <= 7 && f1 >= 0)
+ b |= board(square(r1, f1));
+ r1 = r+1; f1 = f+2;
+ if (r1 <= 7 && f1 <= 7)
+ b |= board(square(r1, f1));
+ r1 = r+2; f1 = f-1;
+ if (r1 <= 7 && f1 >= 0)
+ b |= board(square(r1, f1));
+ r1 = r+2; f1 = f+1;
+ if (r1 <= 7 && f1 <= 7)
+ b |= board(square(r1, f1));
+ knight_attacks_table[s] = b;
+ }
+}
+
+#endif /* TB_KNIGHT_ATTACKS */
+
+#ifdef TB_BISHOP_ATTACKS
+#define bishop_attacks(s, occ) TB_BISHOP_ATTACKS(s, occ)
+#define bishop_attacks_init() /* NOP */
+#else /* TB_BISHOP_ATTACKS */
+
+static uint64_t diag_attacks_table[64][64];
+static uint64_t anti_attacks_table[64][64];
+
+static const unsigned square2diag_table[64] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 14, 0, 1, 2, 3, 4, 5, 6,
+ 13, 14, 0, 1, 2, 3, 4, 5,
+ 12, 13, 14, 0, 1, 2, 3, 4,
+ 11, 12, 13, 14, 0, 1, 2, 3,
+ 10, 11, 12, 13, 14, 0, 1, 2,
+ 9, 10, 11, 12, 13, 14, 0, 1,
+ 8, 9, 10, 11, 12, 13, 14, 0
+};
+
+static const unsigned square2anti_table[64] =
+{
+ 8, 9, 10, 11, 12, 13, 14, 0,
+ 9, 10, 11, 12, 13, 14, 0, 1,
+ 10, 11, 12, 13, 14, 0, 1, 2,
+ 11, 12, 13, 14, 0, 1, 2, 3,
+ 12, 13, 14, 0, 1, 2, 3, 4,
+ 13, 14, 0, 1, 2, 3, 4, 5,
+ 14, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+static const uint64_t diag2board_table[15] =
+{
+ 0x8040201008040201ull,
+ 0x0080402010080402ull,
+ 0x0000804020100804ull,
+ 0x0000008040201008ull,
+ 0x0000000080402010ull,
+ 0x0000000000804020ull,
+ 0x0000000000008040ull,
+ 0x0000000000000080ull,
+ 0x0100000000000000ull,
+ 0x0201000000000000ull,
+ 0x0402010000000000ull,
+ 0x0804020100000000ull,
+ 0x1008040201000000ull,
+ 0x2010080402010000ull,
+ 0x4020100804020100ull,
+};
+
+static const uint64_t anti2board_table[15] =
+{
+ 0x0102040810204080ull,
+ 0x0204081020408000ull,
+ 0x0408102040800000ull,
+ 0x0810204080000000ull,
+ 0x1020408000000000ull,
+ 0x2040800000000000ull,
+ 0x4080000000000000ull,
+ 0x8000000000000000ull,
+ 0x0000000000000001ull,
+ 0x0000000000000102ull,
+ 0x0000000000010204ull,
+ 0x0000000001020408ull,
+ 0x0000000102040810ull,
+ 0x0000010204081020ull,
+ 0x0001020408102040ull,
+};
+
+static inline size_t diag2index(uint64_t b)
+{
+ b *= 0x0101010101010101ull;
+ b >>= 56;
+ b >>= 1;
+ return (size_t)b;
+}
+
+static inline size_t anti2index(uint64_t b)
+{
+ return diag2index(b);
+}
+
+#define diag(s) square2diag_table[(s)]
+#define anti(s) square2anti_table[(s)]
+#define diag2board(d) diag2board_table[(d)]
+#define anti2board(a) anti2board_table[(a)]
+
+static uint64_t bishop_attacks(unsigned sq, uint64_t occ)
+{
+ occ &= ~board(sq);
+ unsigned d = diag(sq), a = anti(sq);
+ uint64_t d_occ = occ & (diag2board(d) & ~BOARD_EDGE);
+ uint64_t a_occ = occ & (anti2board(a) & ~BOARD_EDGE);
+ size_t d_idx = diag2index(d_occ);
+ size_t a_idx = anti2index(a_occ);
+ uint64_t d_attacks = diag_attacks_table[sq][d_idx];
+ uint64_t a_attacks = anti_attacks_table[sq][a_idx];
+ return d_attacks | a_attacks;
+}
+
+static void bishop_attacks_init(void)
+{
+ for (unsigned idx = 0; idx < 64; idx++)
+ {
+ unsigned idx1 = idx << 1;
+ for (unsigned s = 0; s < 64; s++)
+ {
+ int r = rank(s);
+ int f = file(s);
+ uint64_t b = 0;
+ for (int i = -1; f + i >= 0 && r + i >= 0; i--)
+ {
+ unsigned occ = (1 << (f + i));
+ b |= board(square(r + i, f + i));
+ if (idx1 & occ)
+ break;
+ }
+ for (int i = 1; f + i <= 7 && r + i <= 7; i++)
+ {
+ unsigned occ = (1 << (f + i));
+ b |= board(square(r + i, f + i));
+ if (idx1 & occ)
+ break;
+ }
+ diag_attacks_table[s][idx] = b;
+ }
+ }
+
+ for (unsigned idx = 0; idx < 64; idx++)
+ {
+ unsigned idx1 = idx << 1;
+ for (unsigned s = 0; s < 64; s++)
+ {
+ int r = rank(s);
+ int f = file(s);
+ uint64_t b = 0;
+ for (int i = -1; f + i >= 0 && r - i <= 7; i--)
+ {
+ unsigned occ = (1 << (f + i));
+ b |= board(square(r - i, f + i));
+ if (idx1 & occ)
+ break;
+ }
+ for (int i = 1; f + i <= 7 && r - i >= 0; i++)
+ {
+ unsigned occ = (1 << (f + i));
+ b |= board(square(r - i, f + i));
+ if (idx1 & occ)
+ break;
+ }
+ anti_attacks_table[s][idx] = b;
+ }
+ }
+}
+
+#endif /* TB_BISHOP_ATTACKS */
+
+#ifdef TB_ROOK_ATTACKS
+#define rook_attacks(s, occ) TB_ROOK_ATTACKS(s, occ)
+#define rook_attacks_init() /* NOP */
+#else /* TB_ROOK_ATTACKS */
+
+static uint64_t rank_attacks_table[64][64];
+static uint64_t file_attacks_table[64][64];
+
+static inline size_t rank2index(uint64_t b, unsigned r)
+{
+ b >>= (8 * r);
+ b >>= 1;
+ return (size_t)b;
+}
+
+static inline size_t file2index(uint64_t b, unsigned f)
+{
+ b >>= f;
+ b *= 0x0102040810204080ull;
+ b >>= 56;
+ b >>= 1;
+ return (size_t)b;
+}
+
+#define rank2board(r) (0xFFull << (8 * (r)))
+#define file2board(f) (0x0101010101010101ull << (f))
+
+static uint64_t rook_attacks(unsigned sq, uint64_t occ)
+{
+ occ &= ~board(sq);
+ unsigned r = rank(sq), f = file(sq);
+ uint64_t r_occ = occ & (rank2board(r) & ~BOARD_RANK_EDGE);
+ uint64_t f_occ = occ & (file2board(f) & ~BOARD_FILE_EDGE);
+ size_t r_idx = rank2index(r_occ, r);
+ size_t f_idx = file2index(f_occ, f);
+ uint64_t r_attacks = rank_attacks_table[sq][r_idx];
+ uint64_t f_attacks = file_attacks_table[sq][f_idx];
+ return r_attacks | f_attacks;
+}
+
+static void rook_attacks_init(void)
+{
+ for (unsigned idx = 0; idx < 64; idx++)
+ {
+ unsigned idx1 = idx << 1, occ;
+ for (int f = 0; f <= 7; f++)
+ {
+ uint64_t b = 0;
+ if (f > 0)
+ {
+ int i = f-1;
+ do
+ {
+ occ = (1 << i);
+ b |= board(square(0, i));
+ i--;
+ }
+ while (!(idx1 & occ) && i >= 0);
+ }
+ if (f < 7)
+ {
+ int i = f+1;
+ do
+ {
+ occ = (1 << i);
+ b |= board(square(0, i));
+ i++;
+ }
+ while (!(idx1 & occ) && i <= 7);
+ }
+ for (int r = 0; r <= 7; r++)
+ {
+ rank_attacks_table[square(r, f)][idx] = b;
+ b <<= 8;
+ }
+ }
+ }
+ for (unsigned idx = 0; idx < 64; idx++)
+ {
+ unsigned idx1 = idx << 1, occ;
+ for (int r = 0; r <= 7; r++)
+ {
+ uint64_t b = 0;
+ if (r > 0)
+ {
+ int i = r-1;
+ do
+ {
+ occ = (1 << i);
+ b |= board(square(i, 0));
+ i--;
+ }
+ while (!(idx1 & occ) && i >= 0);
+ }
+ if (r < 7)
+ {
+ int i = r+1;
+ do
+ {
+ occ = (1 << i);
+ b |= board(square(i, 0));
+ i++;
+ }
+ while (!(idx1 & occ) && i <= 7);
+ }
+ for (int f = 0; f <= 7; f++)
+ {
+ file_attacks_table[square(r, f)][idx] = b;
+ b <<= 1;
+ }
+ }
+ }
+}
+
+#endif /* TB_ROOK_ATTACKS */
+
+#ifdef TB_QUEEN_ATTACKS
+#define queen_attacks(s, occ) TB_QUEEN_ATTACKS(s, occ)
+#else /* TB_QUEEN_ATTACKS */
+#define queen_attacks(s, occ) \
+ (rook_attacks((s), (occ)) | bishop_attacks((s), (occ)))
+#endif /* TB_QUEEN_ATTACKS */
+
+#ifdef TB_PAWN_ATTACKS
+#define pawn_attacks(s, c) TB_PAWN_ATTACKS(s, c)
+#define pawn_attacks_init() /* NOP */
+#else /* TB_PAWN_ATTACKS */
+
+static uint64_t pawn_attacks_table[2][64];
+
+#define pawn_attacks(s, c) pawn_attacks_table[(c)][(s)]
+
+static void pawn_attacks_init(void)
+{
+ for (unsigned s = 0; s < 64; s++)
+ {
+ int r = rank(s);
+ int f = file(s);
+
+ uint64_t b = 0;
+ if (r != 7)
+ {
+ if (f != 0)
+ b |= board(square(r+1, f-1));
+ if (f != 7)
+ b |= board(square(r+1, f+1));
+ }
+ pawn_attacks_table[1][s] = b;
+
+ b = 0;
+ if (r != 0)
+ {
+ if (f != 0)
+ b |= board(square(r-1, f-1));
+ if (f != 7)
+ b |= board(square(r-1, f+1));
+ }
+ pawn_attacks_table[0][s] = b;
+ }
+}
+
+#endif /* TB_PAWN_ATTACKS */
+
+/*
+ * Given a position, produce a 64-bit material signature key.
+ */
+static uint64_t calc_key(const Pos *pos, bool mirror)
+{
+ uint64_t white = pos->white, black = pos->black;
+ if (mirror)
+ {
+ uint64_t tmp = white;
+ white = black;
+ black = tmp;
+ }
+ return popcount(white & pos->queens) * PRIME_WHITE_QUEEN +
+ popcount(white & pos->rooks) * PRIME_WHITE_ROOK +
+ popcount(white & pos->bishops) * PRIME_WHITE_BISHOP +
+ popcount(white & pos->knights) * PRIME_WHITE_KNIGHT +
+ popcount(white & pos->pawns) * PRIME_WHITE_PAWN +
+ popcount(black & pos->queens) * PRIME_BLACK_QUEEN +
+ popcount(black & pos->rooks) * PRIME_BLACK_ROOK +
+ popcount(black & pos->bishops) * PRIME_BLACK_BISHOP +
+ popcount(black & pos->knights) * PRIME_BLACK_KNIGHT +
+ popcount(black & pos->pawns) * PRIME_BLACK_PAWN;
+}
+
+// Produce a 64-bit material key corresponding to the material combination
+// defined by pcs[16], where pcs[1], ..., pcs[6] are the number of white
+// pawns, ..., kings and pcs[9], ..., pcs[14] are the number of black
+// pawns, ..., kings.
+static uint64_t calc_key_from_pcs(int *pcs, int mirror)
+{
+ mirror = (mirror? 8: 0);
+ return pcs[WHITE_QUEEN ^ mirror] * PRIME_WHITE_QUEEN +
+ pcs[WHITE_ROOK ^ mirror] * PRIME_WHITE_ROOK +
+ pcs[WHITE_BISHOP ^ mirror] * PRIME_WHITE_BISHOP +
+ pcs[WHITE_KNIGHT ^ mirror] * PRIME_WHITE_KNIGHT +
+ pcs[WHITE_PAWN ^ mirror] * PRIME_WHITE_PAWN +
+ pcs[BLACK_QUEEN ^ mirror] * PRIME_BLACK_QUEEN +
+ pcs[BLACK_ROOK ^ mirror] * PRIME_BLACK_ROOK +
+ pcs[BLACK_BISHOP ^ mirror] * PRIME_BLACK_BISHOP +
+ pcs[BLACK_KNIGHT ^ mirror] * PRIME_BLACK_KNIGHT +
+ pcs[BLACK_PAWN ^ mirror] * PRIME_BLACK_PAWN;
+}
+
+// Produce a 64-bit material key corresponding to the material combination
+// piece[0], ..., piece[num - 1], where each value corresponds to a piece
+// (1-6 for white pawn-king, 9-14 for black pawn-king).
+static uint64_t calc_key_from_pieces(uint8_t *piece, int num)
+{
+ uint64_t key = 0;
+ static const uint64_t keys[16] = {0,PRIME_WHITE_PAWN,PRIME_WHITE_KNIGHT,
+ PRIME_WHITE_BISHOP,PRIME_WHITE_ROOK,
+ PRIME_WHITE_QUEEN,0,0,PRIME_BLACK_PAWN,
+ PRIME_BLACK_KNIGHT,PRIME_BLACK_BISHOP,
+ PRIME_BLACK_ROOK,PRIME_BLACK_QUEEN,0};
+ for (int i = 0; i < num; i++) {
+ assert(piece[i]<16);
+ key += keys[piece[i]];
+ }
+ return key;
+}
+
+#define make_move(promote, from, to) \
+ ((((promote) & 0x7) << 12) | (((from) & 0x3F) << 6) | ((to) & 0x3F))
+#define move_from(move) \
+ (((move) >> 6) & 0x3F)
+#define move_to(move) \
+ ((move) & 0x3F)
+#define move_promotes(move) \
+ (((move) >> 12) & 0x7)
+
+static inline int type_of_piece_moved(Pos *pos, TbMove move) {
+ for (int i = PAWN; i <= KING; i++) {
+ if ((pieces_by_type(pos,(Color)(pos->turn == WHITE),(PieceType)i) & board(move_from(move))) != 0) {
+ return i;
+ }
+ }
+ assert(0);
+ return 0;
+}
+
+#define MAX_MOVES TB_MAX_MOVES
+#define MOVE_STALEMATE 0xFFFF
+#define MOVE_CHECKMATE 0xFFFE
+
+static TbMove *add_move(TbMove *moves, bool promotes, unsigned from,
+ unsigned to)
+{
+ if (!promotes)
+ *moves++ = make_move(TB_PROMOTES_NONE, from, to);
+ else
+ {
+ *moves++ = make_move(TB_PROMOTES_QUEEN, from, to);
+ *moves++ = make_move(TB_PROMOTES_KNIGHT, from, to);
+ *moves++ = make_move(TB_PROMOTES_ROOK, from, to);
+ *moves++ = make_move(TB_PROMOTES_BISHOP, from, to);
+ }
+ return moves;
+}
+
+/*
+ * Generate all captures, including all underpomotions
+ */
+static TbMove *gen_captures(const Pos *pos, TbMove *moves)
+{
+ uint64_t occ = pos->white | pos->black;
+ uint64_t us = (pos->turn? pos->white: pos->black),
+ them = (pos->turn? pos->black: pos->white);
+ uint64_t b, att;
+ {
+ unsigned from = lsb(pos->kings & us);
+ assert(from < 64);
+ for (att = king_attacks(from) & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->queens; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = queen_attacks(from, occ) & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->rooks; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = rook_attacks(from, occ) & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->bishops; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = bishop_attacks(from, occ) & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->knights; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = knight_attacks(from) & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->pawns; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ att = pawn_attacks(from, pos->turn);
+ if (pos->ep != 0 && ((att & board(pos->ep)) != 0))
+ {
+ unsigned to = pos->ep;
+ moves = add_move(moves, false, from, to);
+ }
+ for (att = att & them; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, (rank(to) == 7 || rank(to) == 0), from,
+ to);
+ }
+ }
+ return moves;
+}
+
+/*
+ * Generate all moves.
+ */
+static TbMove *gen_moves(const Pos *pos, TbMove *moves)
+{
+ uint64_t occ = pos->white | pos->black;
+ uint64_t us = (pos->turn? pos->white: pos->black),
+ them = (pos->turn? pos->black: pos->white);
+ uint64_t b, att;
+
+ {
+ unsigned from = lsb(pos->kings & us);
+ for (att = king_attacks(from) & ~us; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->queens; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = queen_attacks(from, occ) & ~us; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->rooks; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = rook_attacks(from, occ) & ~us; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->bishops; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = bishop_attacks(from, occ) & ~us; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->knights; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ for (att = knight_attacks(from) & ~us; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, false, from, to);
+ }
+ }
+ for (b = us & pos->pawns; b; b = poplsb(b))
+ {
+ unsigned from = lsb(b);
+ unsigned next = from + (pos->turn? 8: -8);
+ att = pawn_attacks(from, pos->turn);
+ if (pos->ep != 0 && ((att & board(pos->ep)) != 0))
+ {
+ unsigned to = pos->ep;
+ moves = add_move(moves, false, from, to);
+ }
+ att &= them;
+ if ((board(next) & occ) == 0)
+ {
+ att |= board(next);
+ unsigned next2 = from + (pos->turn? 16: -16);
+ if ((pos->turn? rank(from) == 1: rank(from) == 6) &&
+ ((board(next2) & occ) == 0))
+ att |= board(next2);
+ }
+ for (; att; att = poplsb(att))
+ {
+ unsigned to = lsb(att);
+ moves = add_move(moves, (rank(to) == 7 || rank(to) == 0), from,
+ to);
+ }
+ }
+ return moves;
+}
+
+/*
+ * Test if the given move is an en passant capture.
+ */
+static bool is_en_passant(const Pos *pos, TbMove move)
+{
+ uint16_t from = move_from(move);
+ uint16_t to = move_to(move);
+ uint64_t us = (pos->turn? pos->white: pos->black);
+ if (pos->ep == 0)
+ return false;
+ if (to != pos->ep)
+ return false;
+ if ((board(from) & us & pos->pawns) == 0)
+ return false;
+ return true;
+}
+
+
+/*
+ * Test if the given move is a capture.
+ */
+static bool is_capture(const Pos *pos, TbMove move)
+{
+ uint16_t to = move_to(move);
+ uint64_t them = (pos->turn? pos->black: pos->white);
+ return (them & board(to)) != 0 || is_en_passant(pos,move);
+}
+
+
+/*
+ * Test if the given position is legal.
+ * (Pawns on backrank? Can the king be captured?)
+ */
+static bool is_legal(const Pos *pos)
+{
+ uint64_t occ = pos->white | pos->black;
+ uint64_t us = (pos->turn? pos->black: pos->white),
+ them = (pos->turn? pos->white: pos->black);
+ uint64_t king = pos->kings & us;
+ if (!king)
+ return false;
+ unsigned sq = lsb(king);
+ if (king_attacks(sq) & (pos->kings & them))
+ return false;
+ uint64_t ratt = rook_attacks(sq, occ);
+ uint64_t batt = bishop_attacks(sq, occ);
+ if (ratt & (pos->rooks & them))
+ return false;
+ if (batt & (pos->bishops & them))
+ return false;
+ if ((ratt | batt) & (pos->queens & them))
+ return false;
+ if (knight_attacks(sq) & (pos->knights & them))
+ return false;
+ if (pawn_attacks(sq, !pos->turn) & (pos->pawns & them))
+ return false;
+ return true;
+}
+
+/*
+ * Test if the king is in check.
+ */
+static bool is_check(const Pos *pos)
+{
+ uint64_t occ = pos->white | pos->black;
+ uint64_t us = (pos->turn? pos->white: pos->black),
+ them = (pos->turn? pos->black: pos->white);
+ uint64_t king = pos->kings & us;
+ assert(king != 0);
+ unsigned sq = lsb(king);
+ uint64_t ratt = rook_attacks(sq, occ);
+ uint64_t batt = bishop_attacks(sq, occ);
+ if (ratt & (pos->rooks & them))
+ return true;
+ if (batt & (pos->bishops & them))
+ return true;
+ if ((ratt | batt) & (pos->queens & them))
+ return true;
+ if (knight_attacks(sq) & (pos->knights & them))
+ return true;
+ if (pawn_attacks(sq, pos->turn) & (pos->pawns & them))
+ return true;
+ return false;
+}
+
+/*
+ * Test if the position is valid.
+ */
+static bool is_valid(const Pos *pos)
+{
+ if (popcount(pos->kings) != 2)
+ return false;
+ if (popcount(pos->kings & pos->white) != 1)
+ return false;
+ if (popcount(pos->kings & pos->black) != 1)
+ return false;
+ if ((pos->white & pos->black) != 0)
+ return false;
+ if ((pos->kings & pos->queens) != 0)
+ return false;
+ if ((pos->kings & pos->rooks) != 0)
+ return false;
+ if ((pos->kings & pos->bishops) != 0)
+ return false;
+ if ((pos->kings & pos->knights) != 0)
+ return false;
+ if ((pos->kings & pos->pawns) != 0)
+ return false;
+ if ((pos->queens & pos->rooks) != 0)
+ return false;
+ if ((pos->queens & pos->bishops) != 0)
+ return false;
+ if ((pos->queens & pos->knights) != 0)
+ return false;
+ if ((pos->queens & pos->pawns) != 0)
+ return false;
+ if ((pos->rooks & pos->bishops) != 0)
+ return false;
+ if ((pos->rooks & pos->knights) != 0)
+ return false;
+ if ((pos->rooks & pos->pawns) != 0)
+ return false;
+ if ((pos->bishops & pos->knights) != 0)
+ return false;
+ if ((pos->bishops & pos->pawns) != 0)
+ return false;
+ if ((pos->knights & pos->pawns) != 0)
+ return false;
+ if (pos->pawns & BOARD_FILE_EDGE)
+ return false;
+ if ((pos->white | pos->black) !=
+ (pos->kings | pos->queens | pos->rooks | pos->bishops | pos->knights |
+ pos->pawns))
+ return false;
+ return is_legal(pos);
+}
+
+#define do_bb_move(b, from, to) \
+ (((b) & (~board(to)) & (~board(from))) | \
+ ((((b) >> (from)) & 0x1) << (to)))
+
+static bool do_move(Pos *pos, const Pos *pos0, TbMove move)
+{
+ unsigned from = move_from(move);
+ unsigned to = move_to(move);
+ unsigned promotes = move_promotes(move);
+ pos->turn = !pos0->turn;
+ pos->white = do_bb_move(pos0->white, from, to);
+ pos->black = do_bb_move(pos0->black, from, to);
+ pos->kings = do_bb_move(pos0->kings, from, to);
+ pos->queens = do_bb_move(pos0->queens, from, to);
+ pos->rooks = do_bb_move(pos0->rooks, from, to);
+ pos->bishops = do_bb_move(pos0->bishops, from, to);
+ pos->knights = do_bb_move(pos0->knights, from, to);
+ pos->pawns = do_bb_move(pos0->pawns, from, to);
+ pos->ep = 0;
+ if (promotes != TB_PROMOTES_NONE)
+ {
+ pos->pawns &= ~board(to); // Promotion
+ switch (promotes)
+ {
+ case TB_PROMOTES_QUEEN:
+ pos->queens |= board(to); break;
+ case TB_PROMOTES_ROOK:
+ pos->rooks |= board(to); break;
+ case TB_PROMOTES_BISHOP:
+ pos->bishops |= board(to); break;
+ case TB_PROMOTES_KNIGHT:
+ pos->knights |= board(to); break;
+ }
+ pos->rule50 = 0;
+ }
+ else if ((board(from) & pos0->pawns) != 0)
+ {
+ pos->rule50 = 0; // Pawn move
+ if (rank(from) == 1 && rank(to) == 3 &&
+ (pawn_attacks(from+8, true) & pos0->pawns & pos0->black) != 0)
+ pos->ep = from+8;
+ else if (rank(from) == 6 && rank(to) == 4 &&
+ (pawn_attacks(from-8, false) & pos0->pawns & pos0->white) != 0)
+ pos->ep = from-8;
+ else if (to == pos0->ep)
+ {
+ unsigned ep_to = (pos0->turn? to-8: to+8);
+ uint64_t ep_mask = ~board(ep_to);
+ pos->white &= ep_mask;
+ pos->black &= ep_mask;
+ pos->pawns &= ep_mask;
+ }
+ }
+ else if ((board(to) & (pos0->white | pos0->black)) != 0)
+ pos->rule50 = 0; // Capture
+ else
+ pos->rule50 = pos0->rule50 + 1; // Normal move
+ if (!is_legal(pos))
+ return false;
+ return true;
+}
+
+static bool legal_move(const Pos *pos, TbMove move) {
+ struct Pos pos1;
+ return do_move(&pos1, pos, move);
+}
+
+/*
+ * Test if the king is in checkmate.
+ */
+static bool is_mate(const Pos *pos)
+{
+ if (!is_check(pos))
+ return false;
+ uint16_t moves0[MAX_MOVES];
+ uint16_t *moves = moves0;
+ uint16_t *end = gen_moves(pos, moves);
+ for (; moves < end; moves++)
+ {
+ Pos pos1;
+ if (do_move(&pos1, pos, *moves))
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Generate all legal moves.
+ */
+static TbMove *gen_legal(const Pos *pos, TbMove *moves)
+{
+ TbMove pl_moves[TB_MAX_MOVES];
+ TbMove *end = gen_moves(pos, pl_moves);
+ TbMove *results = moves;
+ for (TbMove *m = pl_moves; m < end; m++) {
+ if (legal_move(pos,*m)) {
+ *results++ = *m;
+ }
+ }
+ return results;
+}
+
+#ifdef __cplusplus
+};
+#endif
+
diff --git a/src/fathom/tbconfig.h b/src/fathom/tbconfig.h
new file mode 100644
index 0000000..5836386
--- /dev/null
+++ b/src/fathom/tbconfig.h
@@ -0,0 +1,150 @@
+/*
+ * tbconfig.h
+ * (C) 2015 basil, all rights reserved,
+ * Modifications Copyright 2016-2017 Jon Dart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TBCONFIG_H
+#define TBCONFIG_H
+
+/****************************************************************************/
+/* BUILD CONFIG: */
+/****************************************************************************/
+
+/*
+ * Define TB_CUSTOM_POP_COUNT to override the internal popcount
+ * implementation. To do this supply a macro or function definition
+ * here:
+ */
+/* #define TB_CUSTOM_POP_COUNT(x) <DEFINITION> */
+
+/*
+ * Define TB_CUSTOM_LSB to override the internal lsb
+ * implementation. To do this supply a macro or function definition
+ * here:
+ */
+/* #define TB_CUSTOM_LSB(x) <DEFINITION> */
+
+/*
+ * Define TB_NO_STDINT if you do not want to use <stdint.h> or it is not
+ * available.
+ */
+/* #define TB_NO_STDINT */
+
+/*
+ * Define TB_NO_STDBOOL if you do not want to use <stdbool.h> or it is not
+ * available or unnecessary (e.g. C++).
+ */
+/* #define TB_NO_STDBOOL */
+
+/*
+ * Define TB_NO_THREADS if your program is not multi-threaded.
+ */
+/* #define TB_NO_THREADS */
+
+/*
+ * Define TB_NO_HELPER_API if you do not need the helper API.
+ */
+/* #define TB_NO_HELPER_API */
+
+/*
+ * Define TB_NO_HW_POP_COUNT if there is no hardware popcount instruction.
+ *
+ * Note: if defined, TB_CUSTOM_POP_COUNT is always used in preference
+ * to any built-in popcount functions.
+ *
+ * If no custom popcount function is defined, and if the following
+ * define is not set, the code will attempt to use an available hardware
+ * popcnt (currently supported on x86_64 architecture only) and otherwise
+ * will fall back to a software implementation.
+ */
+/* #define TB_NO_HW_POP_COUNT */
+
+/***************************************************************************/
+/* SCORING CONSTANTS */
+/***************************************************************************/
+/*
+ * Fathom can produce scores for tablebase moves. These depend on the
+ * value of a pawn, and the magnitude of mate scores. The following
+ * constants are representative values but will likely need
+ * modification to adapt to an engine's own internal score values.
+ */
+#define TB_VALUE_PAWN 100 /* value of pawn in endgame */
+#define TB_VALUE_MATE 32000
+#define TB_VALUE_INFINITE 32767 /* value above all normal score values */
+#define TB_VALUE_DRAW 0
+#define TB_MAX_MATE_PLY 255
+
+/***************************************************************************/
+/* ENGINE INTEGRATION CONFIG */
+/***************************************************************************/
+
+/*
+ * If you are integrating tbprobe into an engine, you can replace some of
+ * tbprobe's built-in functionality with that already provided by the engine.
+ * This is OPTIONAL. If no definition are provided then tbprobe will use its
+ * own internal defaults. That said, for engines it is generally a good idea
+ * to avoid redundancy.
+ */
+
+/*
+ * Define TB_KING_ATTACKS(square) to return the king attacks bitboard for a
+ * king at `square'.
+ */
+/* #define TB_KING_ATTACKS(square) <DEFINITION> */
+
+/*
+ * Define TB_KNIGHT_ATTACKS(square) to return the knight attacks bitboard for
+ * a knight at `square'.
+ */
+/* #define TB_KNIGHT_ATTACKS(square) <DEFINITION> */
+
+/*
+ * Define TB_ROOK_ATTACKS(square, occ) to return the rook attacks bitboard
+ * for a rook at `square' assuming the given `occ' occupancy bitboard.
+ */
+/* #define TB_ROOK_ATTACKS(square, occ) <DEFINITION> */
+
+/*
+ * Define TB_BISHOP_ATTACKS(square, occ) to return the bishop attacks bitboard
+ * for a bishop at `square' assuming the given `occ' occupancy bitboard.
+ */
+/* #define TB_BISHOP_ATTACKS(square, occ) <DEFINITION> */
+
+/*
+ * Define TB_QUEEN_ATTACKS(square, occ) to return the queen attacks bitboard
+ * for a queen at `square' assuming the given `occ' occupancy bitboard.
+ * NOTE: If no definition is provided then tbprobe will use:
+ * TB_ROOK_ATTACKS(square, occ) | TB_BISHOP_ATTACKS(square, occ)
+ */
+/* #define TB_QUEEN_ATTACKS(square, occ) <DEFINITION> */
+
+/*
+ * Define TB_PAWN_ATTACKS(square, color) to return the pawn attacks bitboard
+ * for a `color' pawn at `square'.
+ * NOTE: This definition must work for pawns on ranks 1 and 8. For example,
+ * a white pawn on e1 attacks d2 and f2. A black pawn on e1 attacks
+ * nothing. Etc.
+ * NOTE: This definition must not include en passant captures.
+ */
+/* #define TB_PAWN_ATTACKS(square, color) <DEFINITION> */
+
+#endif
diff --git a/src/fathom/tbprobe.c b/src/fathom/tbprobe.c
new file mode 100644
index 0000000..5eac014
--- /dev/null
+++ b/src/fathom/tbprobe.c
@@ -0,0 +1,2715 @@
+/*
+Copyright (c) 2013-2018 Ronald de Man
+Copyright (c) 2015 basil00
+Modifications Copyright (c) 2016-2024 by Jon Dart
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include <assert.h>
+#ifdef __cplusplus
+#include <atomic>
+#else
+#include <stdatomic.h>
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef TB_NO_STDBOOL
+#typedef uint8 bool
+#else
+#include <stdbool.h>
+#endif
+#include "tbprobe.h"
+
+#define TB_PIECES 7
+#define TB_HASHBITS (TB_PIECES < 7 ? 11 : 12)
+#define TB_MAX_PIECE (TB_PIECES < 7 ? 254 : 650)
+#define TB_MAX_PAWN (TB_PIECES < 7 ? 256 : 861)
+#define TB_MAX_SYMS 4096
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#define SEP_CHAR ':'
+#define FD int
+#define FD_ERR -1
+typedef size_t map_t;
+#else
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+#define SEP_CHAR ';'
+#define FD HANDLE
+#define FD_ERR INVALID_HANDLE_VALUE
+typedef HANDLE map_t;
+#endif
+
+// This must be after the inclusion of Windows headers, because otherwise
+// std::byte conflicts with "byte" in rpcndr.h . The error occurs if C++
+// standard is at lest 17, as std::byte was introduced in C++17.
+#ifdef __cplusplus
+using namespace std;
+#endif
+
+#define DECOMP64
+
+// Threading support
+#ifndef TB_NO_THREADS
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+
+#include <mutex>
+#define LOCK_T std::mutex
+#define LOCK_INIT(x)
+#define LOCK_DESTROY(x)
+#define LOCK(x) x.lock()
+#define UNLOCK(x) x.unlock()
+
+#else
+#ifndef _WIN32
+#define LOCK_T pthread_mutex_t
+#define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
+#define LOCK_DESTROY(x) pthread_mutex_destroy(&(x))
+#define LOCK(x) pthread_mutex_lock(&(x))
+#define UNLOCK(x) pthread_mutex_unlock(&(x))
+#else
+#define LOCK_T HANDLE
+#define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
+#define LOCK_DESTROY(x) CloseHandle(x)
+#define LOCK(x) WaitForSingleObject(x, INFINITE)
+#define UNLOCK(x) ReleaseMutex(x)
+#endif
+
+#endif
+#else /* TB_NO_THREADS */
+#define LOCK_T int
+#define LOCK_INIT(x) /* NOP */
+#define LOCK_DESTROY(x) /* NOP */
+#define LOCK(x) /* NOP */
+#define UNLOCK(x) /* NOP */
+#endif
+
+// population count implementation
+#undef TB_SOFTWARE_POP_COUNT
+
+#if defined(TB_CUSTOM_POP_COUNT)
+#define popcount(x) TB_CUSTOM_POP_COUNT(x)
+#elif defined(TB_NO_HW_POP_COUNT)
+#define TB_SOFTWARE_POP_COUNT
+#elif defined (__GNUC__) && defined(__x86_64__) && defined(__SSE4_2__)
+#include <popcntintrin.h>
+#define popcount(x) (int)_mm_popcnt_u64((x))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1500) && defined(_M_AMD64)
+#include <nmmintrin.h>
+#define popcount(x) (int)_mm_popcnt_u64((x))
+#else
+// try to use a builtin
+#if defined (__has_builtin)
+#if __has_builtin(__builtin_popcountll)
+#define popcount(x) __builtin_popcountll((x))
+#else
+#define TB_SOFTWARE_POP_COUNT
+#endif
+#else
+#define TB_SOFTWARE_POP_COUNT
+#endif
+#endif
+
+#ifdef TB_SOFTWARE_POP_COUNT
+// Not a recognized compiler/architecture that has popcount, and
+// no builtin available: fall back to a software popcount. This one
+// is still reasonably fast.
+static inline unsigned tb_software_popcount(uint64_t x)
+{
+ x = x - ((x >> 1) & 0x5555555555555555ull);
+ x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull);
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full;
+ return (x * 0x0101010101010101ull) >> 56;
+}
+#define popcount(x) tb_software_popcount(x)
+#endif
+
+// LSB (least-significant bit) implementation
+#ifdef TB_CUSTOM_LSB
+#define lsb(b) TB_CUSTOM_LSB(b)
+#else
+#if defined(__GNUC__)
+static inline unsigned lsb(uint64_t b) {
+ assert(b != 0);
+ return __builtin_ffsll(b)-1;
+}
+#elif defined(_MSC_VER)
+static inline unsigned lsb(uint64_t b) {
+ assert(b != 0);
+ DWORD index;
+#ifdef _WIN64
+ _BitScanForward64(&index,b);
+ return (unsigned)index;
+#else
+ if (b & 0xffffffffULL) {
+ _BitScanForward(&index,(unsigned long)(b & 0xffffffffULL));
+ return (unsigned)index;
+ }
+ else {
+ _BitScanForward(&index,(unsigned long)(b >> 32));
+ return 32 + (unsigned)index;
+ }
+#endif
+}
+#else
+/* not a compiler/architecture with recognized builtins */
+static uint32_t get_bit32(uint64_t x) {
+ return (uint32_t)(((int32_t)(x))&-((int32_t)(x)));
+}
+static const unsigned MAGIC32 = 0xe89b2be;
+static const uint32_t MagicTable32[32] = {31,0,9,1,10,20,13,2,7,11,21,23,17,14,3,25,30,8,19,12,6,22,16,24,29,18,5,15,28,4,27,26};
+static unsigned lsb(uint64_t b) {
+ if (b & 0xffffffffULL)
+ return MagicTable32[(get_bit32(b & 0xffffffffULL)*MAGIC32)>>27];
+ else
+ return MagicTable32[(get_bit32(b >> 32)*MAGIC32)>>27]+32;
+}
+#endif
+#endif
+
+#define max(a,b) a > b ? a : b
+#define min(a,b) a < b ? a : b
+
+#include "stdendian.h"
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+
+/* (unused)
+static uint64_t from_le_u64(uint64_t input) {
+ return bswap64(input);
+}
+*/
+
+static uint32_t from_le_u32(uint32_t input) {
+ return bswap32(input);
+}
+
+static uint16_t from_le_u16(uint16_t input) {
+ return bswap16(input);
+}
+
+static uint64_t from_be_u64(uint64_t x) {
+ return x;
+}
+
+static uint32_t from_be_u32(uint32_t x) {
+ return x;
+}
+
+/* (unused)
+ static uint16_t from_be_u16(uint16_t x) {
+ return x;
+ }*/
+
+#else
+
+/* (unused)
+static uint64_t from_le_u64(uint64_t x) {
+ return x;
+}
+*/
+
+static uint32_t from_le_u32(uint32_t x) {
+ return x;
+}
+
+static uint16_t from_le_u16(uint16_t x) {
+ return x;
+}
+
+static uint64_t from_be_u64(uint64_t input) {
+ return bswap64(input);
+}
+
+static uint32_t from_be_u32(uint32_t input) {
+ return bswap32(input);
+}
+
+/* (unused)
+static uint16_t from_be_u16(const uint16_t input) {
+ return bswap16(input);
+}
+*/
+
+#endif
+
+inline static uint32_t read_le_u32(void *p)
+{
+ // input may be unaligned, so read into stack allocated
+ // buffer, which should be aligned
+ // (prevents runtime errors from glibc)
+ unsigned char buffer[4];
+ memcpy(buffer, p, 4);
+ return from_le_u32(*(uint32_t *)buffer);
+}
+
+inline static uint16_t read_le_u16(void *p)
+{
+ // input may be unaligned, so read into stack allocated
+ // buffer, which should be aligned
+ // (prevents runtime errors from glibc)
+ unsigned char buffer[2];
+ buffer[0] = *((unsigned char*)p);
+ buffer[1] = *(((unsigned char*)p)+1);
+ return from_le_u16(*(uint16_t *)buffer);
+}
+
+static size_t file_size(FD fd) {
+#ifdef _WIN32
+ LARGE_INTEGER fileSize;
+ if (GetFileSizeEx(fd, &fileSize)==0) {
+ return 0;
+ }
+ return (size_t)fileSize.QuadPart;
+#else
+ struct stat buf;
+ if (fstat(fd,&buf)) {
+ return 0;
+ } else {
+ return buf.st_size;
+ }
+#endif
+}
+
+#ifndef TB_NO_THREADS
+static LOCK_T tbMutex;
+#endif
+static int initialized = 0;
+static int numPaths = 0;
+static char *pathString = NULL;
+static char **paths = NULL;
+
+static FD open_tb(const char *str, const char *suffix)
+{
+ int i;
+ FD fd;
+ char *file;
+
+ for (i = 0; i < numPaths; i++) {
+ file = (char*)malloc(strlen(paths[i]) + strlen(str) +
+ strlen(suffix) + 2);
+ strcpy(file, paths[i]);
+#ifdef _WIN32
+ strcat(file,"\\");
+#else
+ strcat(file,"/");
+#endif
+ strcat(file, str);
+ strcat(file, suffix);
+#ifndef _WIN32
+ fd = open(file, O_RDONLY);
+#else
+#ifdef _UNICODE
+ wchar_t ucode_name[4096];
+ size_t len;
+ mbstowcs_s(&len, ucode_name, 4096, file, _TRUNCATE);
+ /* use FILE_FLAG_RANDOM_ACCESS because we are likely to access this file
+ randomly, so prefetch is not helpful. See
+ https://github.com/official-stockfish/Stockfish/pull/1829 */
+ fd = CreateFile(ucode_name, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+#else
+ fd = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+#endif
+#endif
+ free(file);
+ if (fd != FD_ERR) {
+ return fd;
+ }
+ }
+ return FD_ERR;
+}
+
+static void close_tb(FD fd)
+{
+#ifndef _WIN32
+ close(fd);
+#else
+ CloseHandle(fd);
+#endif
+}
+
+static void *map_file(FD fd, map_t *mapping)
+{
+#ifndef _WIN32
+ struct stat statbuf;
+ if (fstat(fd, &statbuf)) {
+ perror("fstat");
+ close_tb(fd);
+ return NULL;
+ }
+ *mapping = statbuf.st_size;
+ void *data = mmap(NULL, statbuf.st_size, PROT_READ,
+ MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ perror("mmap");
+ return NULL;
+ }
+#ifdef POSIX_MADV_RANDOM
+ /* Advise the kernel that we are likely to access this data
+ region randomly, so prefetch is not helpful. See
+ https://github.com/official-stockfish/Stockfish/pull/1829 */
+ posix_madvise(data, statbuf.st_size, POSIX_MADV_RANDOM);
+#endif
+#else
+ DWORD size_low, size_high;
+ size_low = GetFileSize(fd, &size_high);
+ HANDLE map = CreateFileMapping(fd, NULL, PAGE_READONLY, size_high, size_low,
+ NULL);
+ if (map == NULL) {
+ fprintf(stderr,"CreateFileMapping() failed, error = %lu.\n", GetLastError());
+ return NULL;
+ }
+ *mapping = (map_t)map;
+ void *data = (void *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+ if (data == NULL) {
+ fprintf(stderr,"MapViewOfFile() failed, error = %lu.\n", GetLastError());
+ }
+#endif
+ return data;
+}
+
+#ifndef _WIN32
+static void unmap_file(void *data, map_t size)
+{
+ if (!data) return;
+ if (munmap(data, size) != 0) {
+ perror("munmap");
+ }
+}
+#else
+static void unmap_file(void *data, map_t mapping)
+{
+ if (!data) return;
+ if (!UnmapViewOfFile(data)) {
+ fprintf(stderr, "unmap failed, error code %lu\n", GetLastError());
+ }
+ if (!CloseHandle((HANDLE)mapping)) {
+ fprintf(stderr, "CloseHandle failed, error code %lu\n", GetLastError());
+ }
+}
+#endif
+
+#define poplsb(x) ((x) & ((x) - 1))
+
+int TB_MaxCardinality = 0, TB_MaxCardinalityDTM = 0;
+unsigned TB_LARGEST = 0;
+//extern int TB_CardinalityDTM;
+
+static const char *tbSuffix[] = { ".rtbw", ".rtbm", ".rtbz" };
+static uint32_t tbMagic[] = { 0x5d23e871, 0x88ac504b, 0xa50c66d7 };
+
+enum { WDL, DTM, DTZ };
+enum { PIECE_ENC, FILE_ENC, RANK_ENC };
+
+// Attack and move generation code
+#include "tbchess.c"
+
+struct PairsData {
+ uint8_t *indexTable;
+ uint16_t *sizeTable;
+ uint8_t *data;
+ uint16_t *offset;
+ uint8_t *symLen;
+ uint8_t *symPat;
+ uint8_t blockSize;
+ uint8_t idxBits;
+ uint8_t minLen;
+ uint8_t constValue[2];
+ uint64_t base[1];
+};
+
+struct EncInfo {
+ struct PairsData *precomp;
+ size_t factor[TB_PIECES];
+ uint8_t pieces[TB_PIECES];
+ uint8_t norm[TB_PIECES];
+};
+
+struct BaseEntry {
+ uint64_t key;
+ uint8_t *data[3];
+ map_t mapping[3];
+#ifdef __cplusplus
+#if __cplusplus >= 202002L
+ atomic<bool> ready[3]{false, false, false};
+#else
+ atomic<bool> ready[3];
+#endif
+#else
+ atomic_bool ready[3];
+#endif
+ uint8_t num;
+ bool symmetric, hasPawns, hasDtm, hasDtz;
+ union {
+ bool kk_enc;
+ uint8_t pawns[2];
+ };
+ bool dtmLossOnly;
+};
+
+struct PieceEntry {
+ struct BaseEntry be;
+ struct EncInfo ei[5]; // 2 + 2 + 1
+ uint16_t *dtmMap;
+ uint16_t dtmMapIdx[2][2];
+ void *dtzMap;
+ uint16_t dtzMapIdx[4];
+ uint8_t dtzFlags;
+};
+
+struct PawnEntry {
+ struct BaseEntry be;
+ struct EncInfo ei[24]; // 4 * 2 + 6 * 2 + 4
+ uint16_t *dtmMap;
+ uint16_t dtmMapIdx[6][2][2];
+ void *dtzMap;
+ uint16_t dtzMapIdx[4][4];
+ uint8_t dtzFlags[4];
+ bool dtmSwitched;
+};
+
+struct TbHashEntry {
+ uint64_t key;
+ struct BaseEntry *ptr;
+#ifdef __cplusplus
+ atomic<bool> error;
+#else
+ atomic_bool error;
+#endif
+};
+
+static int tbNumPiece, tbNumPawn;
+static int numWdl, numDtm, numDtz;
+
+static struct PieceEntry *pieceEntry;
+static struct PawnEntry *pawnEntry;
+static struct TbHashEntry tbHash[1 << TB_HASHBITS];
+
+static void init_indices(void);
+
+// Forward declarations. These functions without the tb_
+// prefix take a pos structure as input.
+static int probe_wdl(Pos *pos, int *success);
+static int probe_dtz(Pos *pos, int *success);
+static int root_probe_wdl(const Pos *pos, bool useRule50, struct TbRootMoves *rm);
+static int root_probe_dtz(const Pos *pos, bool hasRepeated, bool useRule50, struct TbRootMoves *rm);
+static uint16_t probe_root(Pos *pos, int *score, unsigned *results);
+
+unsigned tb_probe_wdl_impl(
+ uint64_t white,
+ uint64_t black,
+ uint64_t kings,
+ uint64_t queens,
+ uint64_t rooks,
+ uint64_t bishops,
+ uint64_t knights,
+ uint64_t pawns,
+ unsigned ep,
+ bool turn)
+{
+ Pos pos =
+ {
+ white,
+ black,
+ kings,
+ queens,
+ rooks,
+ bishops,
+ knights,
+ pawns,
+ 0,
+ (uint8_t)ep,
+ turn
+ };
+ int success;
+ int v = probe_wdl(&pos, &success);
+ if (success == 0)
+ return TB_RESULT_FAILED;
+ return (unsigned)(v + 2);
+}
+
+static unsigned dtz_to_wdl(int cnt50, int dtz)
+{
+ int wdl = 0;
+ if (dtz > 0)
+ wdl = (dtz + cnt50 <= 100? 2: 1);
+ else if (dtz < 0)
+ wdl = (-dtz + cnt50 <= 100? -2: -1);
+ return wdl + 2;
+}
+
+unsigned tb_probe_root_impl(
+ uint64_t white,
+ uint64_t black,
+ uint64_t kings,
+ uint64_t queens,
+ uint64_t rooks,
+ uint64_t bishops,
+ uint64_t knights,
+ uint64_t pawns,
+ unsigned rule50,
+ unsigned ep,
+ bool turn,
+ unsigned *results)
+{
+ Pos pos =
+ {
+ white,
+ black,
+ kings,
+ queens,
+ rooks,
+ bishops,
+ knights,
+ pawns,
+ (uint8_t)rule50,
+ (uint8_t)ep,
+ turn
+ };
+ int dtz;
+ if (!is_valid(&pos))
+ return TB_RESULT_FAILED;
+ TbMove move = probe_root(&pos, &dtz, results);
+ if (move == 0)
+ return TB_RESULT_FAILED;
+ if (move == MOVE_CHECKMATE)
+ return TB_RESULT_CHECKMATE;
+ if (move == MOVE_STALEMATE)
+ return TB_RESULT_STALEMATE;
+ unsigned res = 0;
+ res = TB_SET_WDL(res, dtz_to_wdl(rule50, dtz));
+ res = TB_SET_DTZ(res, (dtz < 0? -dtz: dtz));
+ res = TB_SET_FROM(res, move_from(move));
+ res = TB_SET_TO(res, move_to(move));
+ res = TB_SET_PROMOTES(res, move_promotes(move));
+ res = TB_SET_EP(res, is_en_passant(&pos, move));
+ return res;
+}
+
+int tb_probe_root_dtz(
+ uint64_t white,
+ uint64_t black,
+ uint64_t kings,
+ uint64_t queens,
+ uint64_t rooks,
+ uint64_t bishops,
+ uint64_t knights,
+ uint64_t pawns,
+ unsigned rule50,
+ unsigned castling,
+ unsigned ep,
+ bool turn,
+ bool hasRepeated,
+ bool useRule50,
+ struct TbRootMoves *results) {
+ Pos pos =
+ {
+ white,
+ black,
+ kings,
+ queens,
+ rooks,
+ bishops,
+ knights,
+ pawns,
+ (uint8_t)rule50,
+ (uint8_t)ep,
+ turn
+ };
+ if (castling != 0) return 0;
+ return root_probe_dtz(&pos, hasRepeated, useRule50, results);
+}
+
+int tb_probe_root_wdl(
+ uint64_t white,
+ uint64_t black,
+ uint64_t kings,
+ uint64_t queens,
+ uint64_t rooks,
+ uint64_t bishops,
+ uint64_t knights,
+ uint64_t pawns,
+ unsigned rule50,
+ unsigned castling,
+ unsigned ep,
+ bool turn,
+ bool useRule50,
+ struct TbRootMoves *results) {
+ Pos pos =
+ {
+ white,
+ black,
+ kings,
+ queens,
+ rooks,
+ bishops,
+ knights,
+ pawns,
+ (uint8_t)rule50,
+ (uint8_t)ep,
+ turn
+ };
+ if (castling != 0) return 0;
+ return root_probe_wdl(&pos, useRule50, results);
+}
+
+// Given a position, produce a text string of the form KQPvKRP, where
+// "KQP" represents the white pieces if flip == false and the black pieces
+// if flip == true.
+static void prt_str(const Pos *pos, char *str, bool flip)
+{
+ int color = flip ? BLACK : WHITE;
+
+ for (int pt = KING; pt >= PAWN; pt--)
+ for (int i = popcount(pieces_by_type(pos, (Color)color, (PieceType)pt)); i > 0; i--)
+ *str++ = piece_to_char[pt];
+ *str++ = 'v';
+ color ^= 1;
+ for (int pt = KING; pt >= PAWN; pt--)
+ for (int i = popcount(pieces_by_type(pos, (Color)color, (PieceType)pt)); i > 0; i--)
+ *str++ = piece_to_char[pt];
+ *str++ = 0;
+}
+
+static bool test_tb(const char *str, const char *suffix)
+{
+ FD fd = open_tb(str, suffix);
+ if (fd != FD_ERR) {
+ size_t size = file_size(fd);
+ close_tb(fd);
+ if ((size & 63) != 16) {
+ fprintf(stderr, "Incomplete tablebase file %s.%s\n", str, suffix);
+ printf("info string Incomplete tablebase file %s.%s\n", str, suffix);
+ fd = FD_ERR;
+ }
+ }
+ return fd != FD_ERR;
+}
+
+static void *map_tb(const char *name, const char *suffix, map_t *mapping)
+{
+ FD fd = open_tb(name, suffix);
+ if (fd == FD_ERR)
+ return NULL;
+
+ void *data = map_file(fd, mapping);
+ if (data == NULL) {
+ fprintf(stderr, "Could not map %s%s into memory.\n", name, suffix);
+ exit(EXIT_FAILURE);
+ }
+
+ close_tb(fd);
+
+ return data;
+}
+
+static void add_to_hash(struct BaseEntry *ptr, uint64_t key)
+{
+ int idx;
+
+ idx = key >> (64 - TB_HASHBITS);
+ while (tbHash[idx].ptr)
+ idx = (idx + 1) & ((1 << TB_HASHBITS) - 1);
+
+ tbHash[idx].key = key;
+ tbHash[idx].ptr = ptr;
+ atomic_init(&tbHash[idx].error, false);
+}
+
+#define pchr(i) piece_to_char[QUEEN - (i)]
+#define Swap(a,b) {int tmp=a;a=b;b=tmp;}
+
+static void init_tb(char *str)
+{
+ if (!test_tb(str, tbSuffix[WDL]))
+ return;
+
+ int pcs[16];
+ for (int i = 0; i < 16; i++)
+ pcs[i] = 0;
+ int color = 0;
+ for (char *s = str; *s; s++)
+ if (*s == 'v')
+ color = 8;
+ else {
+ int piece_type = char_to_piece_type(*s);
+ if (piece_type) {
+ assert((piece_type | color) < 16);
+ pcs[piece_type | color]++;
+ }
+ }
+
+ uint64_t key = calc_key_from_pcs(pcs, false);
+ uint64_t key2 = calc_key_from_pcs(pcs, true);
+
+ bool hasPawns = pcs[W_PAWN] || pcs[B_PAWN];
+
+ struct BaseEntry *be = hasPawns ? &pawnEntry[tbNumPawn++].be
+ : &pieceEntry[tbNumPiece++].be;
+ be->hasPawns = hasPawns;
+ be->key = key;
+ be->symmetric = key == key2;
+ be->num = 0;
+ for (int i = 0; i < 16; i++)
+ be->num += pcs[i];
+
+ numWdl++;
+ numDtm += be->hasDtm = test_tb(str, tbSuffix[DTM]);
+ numDtz += be->hasDtz = test_tb(str, tbSuffix[DTZ]);
+
+ if (be->num > TB_MaxCardinality) {
+ TB_MaxCardinality = be->num;
+ }
+ if (be->hasDtm)
+ if (be->num > TB_MaxCardinalityDTM) {
+ TB_MaxCardinalityDTM = be->num;
+ }
+
+#if !defined(__cplusplus) || (__cplusplus < 202002L)
+ for (int type = 0; type < 3; type++)
+ atomic_init(&be->ready[type], false);
+#endif
+
+ if (!be->hasPawns) {
+ int j = 0;
+ for (int i = 0; i < 16; i++)
+ if (pcs[i] == 1) j++;
+ be->kk_enc = j == 2;
+ } else {
+ be->pawns[0] = pcs[W_PAWN];
+ be->pawns[1] = pcs[B_PAWN];
+ if (pcs[B_PAWN] && (!pcs[W_PAWN] || pcs[W_PAWN] > pcs[B_PAWN]))
+ Swap(be->pawns[0], be->pawns[1]);
+ }
+
+ add_to_hash(be, key);
+ if (key != key2)
+ add_to_hash(be, key2);
+}
+
+#define PIECE(x) ((struct PieceEntry *)(x))
+#define PAWN(x) ((struct PawnEntry *)(x))
+
+int num_tables(struct BaseEntry *be, const int type)
+{
+ return be->hasPawns ? type == DTM ? 6 : 4 : 1;
+}
+
+struct EncInfo *first_ei(struct BaseEntry *be, const int type)
+{
+ return be->hasPawns
+ ? &PAWN(be)->ei[type == WDL ? 0 : type == DTM ? 8 : 20]
+ : &PIECE(be)->ei[type == WDL ? 0 : type == DTM ? 2 : 4];
+}
+
+static void free_tb_entry(struct BaseEntry *be)
+{
+ for (int type = 0; type < 3; type++) {
+ if (atomic_load_explicit(&be->ready[type], memory_order_relaxed)) {
+ unmap_file((void*)(be->data[type]), be->mapping[type]);
+ int num = num_tables(be, type);
+ struct EncInfo *ei = first_ei(be, type);
+ for (int t = 0; t < num; t++) {
+ free(ei[t].precomp);
+ if (type != DTZ)
+ free(ei[num + t].precomp);
+ }
+ atomic_store_explicit(&be->ready[type], false, memory_order_relaxed);
+ }
+ }
+}
+
+bool tb_init(const char *path)
+{
+ if (!initialized) {
+ init_indices();
+ king_attacks_init();
+ knight_attacks_init();
+ bishop_attacks_init();
+ rook_attacks_init();
+ pawn_attacks_init();
+ initialized = 1;
+ }
+
+ // if pathString is set, we need to clean up first.
+ if (pathString) {
+ free(pathString);
+ free(paths);
+
+ for (int i = 0; i < tbNumPiece; i++)
+ free_tb_entry((struct BaseEntry *)&pieceEntry[i]);
+ for (int i = 0; i < tbNumPawn; i++)
+ free_tb_entry((struct BaseEntry *)&pawnEntry[i]);
+
+ LOCK_DESTROY(tbMutex);
+
+ pathString = NULL;
+ numWdl = numDtm = numDtz = 0;
+ }
+
+ TB_LARGEST = 0;
+
+ // if path is an empty string or equals "<empty>", we are done.
+ const char *p = path;
+ if (strlen(p) == 0 || !strcmp(p, "<empty>")) {
+ return true;
+ }
+
+ pathString = (char*)malloc(strlen(p) + 1);
+ strcpy(pathString, p);
+ numPaths = 0;
+ for (int i = 0;; i++) {
+ if (pathString[i] != SEP_CHAR)
+ numPaths++;
+ while (pathString[i] && pathString[i] != SEP_CHAR)
+ i++;
+ if (!pathString[i]) break;
+ pathString[i] = 0;
+ }
+ paths = (char**)malloc(numPaths * sizeof(*paths));
+ for (int i = 0, j = 0; i < numPaths; i++) {
+ while (!pathString[j]) j++;
+ paths[i] = &pathString[j];
+ while (pathString[j]) j++;
+ }
+
+ LOCK_INIT(tbMutex);
+
+ tbNumPiece = tbNumPawn = 0;
+ TB_MaxCardinality = TB_MaxCardinalityDTM = 0;
+
+ if (!pieceEntry) {
+#if defined(__cplusplus) && (__cplusplus >= 202002L)
+ /* Fix crash with -std=c++20 by being consistent with BaseEntry initialization:
+
+ #if __cplusplus >= 202002L
+ atomic<bool> ready[3]{false, false, false};
+ #else
+ ...
+
+ C++ initialization does not work with malloc.
+ Also: with new, if the allocation fails we get std::bad_alloc exception,
+ which is better library behavior than just calling exit.
+ */
+
+ pieceEntry = new PieceEntry[TB_MAX_PIECE]();
+ pawnEntry = new PawnEntry[TB_MAX_PAWN]();
+#else
+ pieceEntry = (struct PieceEntry*)malloc(TB_MAX_PIECE * sizeof(*pieceEntry));
+ pawnEntry = (struct PawnEntry*)malloc(TB_MAX_PAWN * sizeof(*pawnEntry));
+#endif
+ if (!pieceEntry || !pawnEntry) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ for (int i = 0; i < (1 << TB_HASHBITS); i++) {
+ tbHash[i].key = 0;
+ tbHash[i].ptr = NULL;
+ }
+
+ char str[16];
+ int i, j, k, l, m;
+
+ for (i = 0; i < 5; i++) {
+ snprintf(str, 16, "K%cvK", pchr(i));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++) {
+ snprintf(str, 16, "K%cvK%c", pchr(i), pchr(j));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++) {
+ snprintf(str, 16, "K%c%cvK", pchr(i), pchr(j));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = 0; k < 5; k++) {
+ snprintf(str, 16, "K%c%cvK%c", pchr(i), pchr(j), pchr(k));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++) {
+ snprintf(str, 16, "K%c%c%cvK", pchr(i), pchr(j), pchr(k));
+ init_tb(str);
+ }
+
+ // 6- and 7-piece TBs make sense only with a 64-bit address space
+ if (sizeof(size_t) < 8 || TB_PIECES < 6)
+ goto finished;
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = i; k < 5; k++)
+ for (l = (i == k) ? j : k; l < 5; l++) {
+ snprintf(str, 16, "K%c%cvK%c%c", pchr(i), pchr(j), pchr(k), pchr(l));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++)
+ for (l = 0; l < 5; l++) {
+ snprintf(str, 16, "K%c%c%cvK%c", pchr(i), pchr(j), pchr(k), pchr(l));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++)
+ for (l = k; l < 5; l++) {
+ snprintf(str, 16, "K%c%c%c%cvK", pchr(i), pchr(j), pchr(k), pchr(l));
+ init_tb(str);
+ }
+
+ if (TB_PIECES < 7)
+ goto finished;
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++)
+ for (l = k; l < 5; l++)
+ for (m = l; m < 5; m++) {
+ snprintf(str, 16, "K%c%c%c%c%cvK", pchr(i), pchr(j), pchr(k), pchr(l), pchr(m));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++)
+ for (l = k; l < 5; l++)
+ for (m = 0; m < 5; m++) {
+ snprintf(str, 16, "K%c%c%c%cvK%c", pchr(i), pchr(j), pchr(k), pchr(l), pchr(m));
+ init_tb(str);
+ }
+
+ for (i = 0; i < 5; i++)
+ for (j = i; j < 5; j++)
+ for (k = j; k < 5; k++)
+ for (l = 0; l < 5; l++)
+ for (m = l; m < 5; m++) {
+ snprintf(str, 16, "K%c%c%cvK%c%c", pchr(i), pchr(j), pchr(k), pchr(l), pchr(m));
+ init_tb(str);
+ }
+
+finished:
+ /* TBD - assumes UCI
+ printf("info string Found %d WDL, %d DTM and %d DTZ tablebase files.\n",
+ numWdl, numDtm, numDtz);
+ fflush(stdout);
+ */
+ // Set TB_LARGEST, for backward compatibility with pre-7-man Fathom
+ TB_LARGEST = (unsigned)TB_MaxCardinality;
+ if ((unsigned)TB_MaxCardinalityDTM > TB_LARGEST) {
+ TB_LARGEST = TB_MaxCardinalityDTM;
+ }
+ return true;
+}
+
+void tb_free(void)
+{
+ tb_init("");
+#if defined __cplusplus && __cplusplus >= 202002L
+ delete[] pieceEntry;
+ delete[] pawnEntry;
+#else
+ free(pieceEntry);
+ free(pawnEntry);
+#endif
+ pieceEntry = NULL;
+ pawnEntry = NULL;
+}
+
+static const int8_t OffDiag[] = {
+ 0,-1,-1,-1,-1,-1,-1,-1,
+ 1, 0,-1,-1,-1,-1,-1,-1,
+ 1, 1, 0,-1,-1,-1,-1,-1,
+ 1, 1, 1, 0,-1,-1,-1,-1,
+ 1, 1, 1, 1, 0,-1,-1,-1,
+ 1, 1, 1, 1, 1, 0,-1,-1,
+ 1, 1, 1, 1, 1, 1, 0,-1,
+ 1, 1, 1, 1, 1, 1, 1, 0
+};
+
+static const uint8_t Triangle[] = {
+ 6, 0, 1, 2, 2, 1, 0, 6,
+ 0, 7, 3, 4, 4, 3, 7, 0,
+ 1, 3, 8, 5, 5, 8, 3, 1,
+ 2, 4, 5, 9, 9, 5, 4, 2,
+ 2, 4, 5, 9, 9, 5, 4, 2,
+ 1, 3, 8, 5, 5, 8, 3, 1,
+ 0, 7, 3, 4, 4, 3, 7, 0,
+ 6, 0, 1, 2, 2, 1, 0, 6
+};
+
+static const uint8_t FlipDiag[] = {
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 7, 15, 23, 31, 39, 47, 55, 63
+};
+
+static const uint8_t Lower[] = {
+ 28, 0, 1, 2, 3, 4, 5, 6,
+ 0, 29, 7, 8, 9, 10, 11, 12,
+ 1, 7, 30, 13, 14, 15, 16, 17,
+ 2, 8, 13, 31, 18, 19, 20, 21,
+ 3, 9, 14, 18, 32, 22, 23, 24,
+ 4, 10, 15, 19, 22, 33, 25, 26,
+ 5, 11, 16, 20, 23, 25, 34, 27,
+ 6, 12, 17, 21, 24, 26, 27, 35
+};
+
+static const uint8_t Diag[] = {
+ 0, 0, 0, 0, 0, 0, 0, 8,
+ 0, 1, 0, 0, 0, 0, 9, 0,
+ 0, 0, 2, 0, 0, 10, 0, 0,
+ 0, 0, 0, 3, 11, 0, 0, 0,
+ 0, 0, 0, 12, 4, 0, 0, 0,
+ 0, 0, 13, 0, 0, 5, 0, 0,
+ 0, 14, 0, 0, 0, 0, 6, 0,
+ 15, 0, 0, 0, 0, 0, 0, 7
+};
+
+static const uint8_t Flap[2][64] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 12, 18, 18, 12, 6, 0,
+ 1, 7, 13, 19, 19, 13, 7, 1,
+ 2, 8, 14, 20, 20, 14, 8, 2,
+ 3, 9, 15, 21, 21, 15, 9, 3,
+ 4, 10, 16, 22, 22, 16, 10, 4,
+ 5, 11, 17, 23, 23, 17, 11, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 3, 2, 1, 0,
+ 4, 5, 6, 7, 7, 6, 5, 4,
+ 8, 9, 10, 11, 11, 10, 9, 8,
+ 12, 13, 14, 15, 15, 14, 13, 12,
+ 16, 17, 18, 19, 19, 18, 17, 16,
+ 20, 21, 22, 23, 23, 22, 21, 20,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const uint8_t PawnTwist[2][64] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 47, 35, 23, 11, 10, 22, 34, 46,
+ 45, 33, 21, 9, 8, 20, 32, 44,
+ 43, 31, 19, 7, 6, 18, 30, 42,
+ 41, 29, 17, 5, 4, 16, 28, 40,
+ 39, 27, 15, 3, 2, 14, 26, 38,
+ 37, 25, 13, 1, 0, 12, 24, 36,
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 47, 45, 43, 41, 40, 42, 44, 46,
+ 39, 37, 35, 33, 32, 34, 36, 38,
+ 31, 29, 27, 25, 24, 26, 28, 30,
+ 23, 21, 19, 17, 16, 18, 20, 22,
+ 15, 13, 11, 9, 8, 10, 12, 14,
+ 7, 5, 3, 1, 0, 2, 4, 6,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const int16_t KKIdx[10][64] = {
+ { -1, -1, -1, 0, 1, 2, 3, 4,
+ -1, -1, -1, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57 },
+ { 58, -1, -1, -1, 59, 60, 61, 62,
+ 63, -1, -1, -1, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99,
+ 100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115},
+ {116,117, -1, -1, -1,118,119,120,
+ 121,122, -1, -1, -1,123,124,125,
+ 126,127,128,129,130,131,132,133,
+ 134,135,136,137,138,139,140,141,
+ 142,143,144,145,146,147,148,149,
+ 150,151,152,153,154,155,156,157,
+ 158,159,160,161,162,163,164,165,
+ 166,167,168,169,170,171,172,173 },
+ {174, -1, -1, -1,175,176,177,178,
+ 179, -1, -1, -1,180,181,182,183,
+ 184, -1, -1, -1,185,186,187,188,
+ 189,190,191,192,193,194,195,196,
+ 197,198,199,200,201,202,203,204,
+ 205,206,207,208,209,210,211,212,
+ 213,214,215,216,217,218,219,220,
+ 221,222,223,224,225,226,227,228 },
+ {229,230, -1, -1, -1,231,232,233,
+ 234,235, -1, -1, -1,236,237,238,
+ 239,240, -1, -1, -1,241,242,243,
+ 244,245,246,247,248,249,250,251,
+ 252,253,254,255,256,257,258,259,
+ 260,261,262,263,264,265,266,267,
+ 268,269,270,271,272,273,274,275,
+ 276,277,278,279,280,281,282,283 },
+ {284,285,286,287,288,289,290,291,
+ 292,293, -1, -1, -1,294,295,296,
+ 297,298, -1, -1, -1,299,300,301,
+ 302,303, -1, -1, -1,304,305,306,
+ 307,308,309,310,311,312,313,314,
+ 315,316,317,318,319,320,321,322,
+ 323,324,325,326,327,328,329,330,
+ 331,332,333,334,335,336,337,338 },
+ { -1, -1,339,340,341,342,343,344,
+ -1, -1,345,346,347,348,349,350,
+ -1, -1,441,351,352,353,354,355,
+ -1, -1, -1,442,356,357,358,359,
+ -1, -1, -1, -1,443,360,361,362,
+ -1, -1, -1, -1, -1,444,363,364,
+ -1, -1, -1, -1, -1, -1,445,365,
+ -1, -1, -1, -1, -1, -1, -1,446 },
+ { -1, -1, -1,366,367,368,369,370,
+ -1, -1, -1,371,372,373,374,375,
+ -1, -1, -1,376,377,378,379,380,
+ -1, -1, -1,447,381,382,383,384,
+ -1, -1, -1, -1,448,385,386,387,
+ -1, -1, -1, -1, -1,449,388,389,
+ -1, -1, -1, -1, -1, -1,450,390,
+ -1, -1, -1, -1, -1, -1, -1,451 },
+ {452,391,392,393,394,395,396,397,
+ -1, -1, -1, -1,398,399,400,401,
+ -1, -1, -1, -1,402,403,404,405,
+ -1, -1, -1, -1,406,407,408,409,
+ -1, -1, -1, -1,453,410,411,412,
+ -1, -1, -1, -1, -1,454,413,414,
+ -1, -1, -1, -1, -1, -1,455,415,
+ -1, -1, -1, -1, -1, -1, -1,456 },
+ {457,416,417,418,419,420,421,422,
+ -1,458,423,424,425,426,427,428,
+ -1, -1, -1, -1, -1,429,430,431,
+ -1, -1, -1, -1, -1,432,433,434,
+ -1, -1, -1, -1, -1,435,436,437,
+ -1, -1, -1, -1, -1,459,438,439,
+ -1, -1, -1, -1, -1, -1,460,440,
+ -1, -1, -1, -1, -1, -1, -1,461 }
+};
+
+static const uint8_t FileToFile[] = { 0, 1, 2, 3, 3, 2, 1, 0 };
+static const int WdlToMap[5] = { 1, 3, 0, 2, 0 };
+static const uint8_t PAFlags[5] = { 8, 0, 0, 0, 4 };
+
+static size_t Binomial[7][64];
+static size_t PawnIdx[2][6][24];
+static size_t PawnFactorFile[6][4];
+static size_t PawnFactorRank[6][6];
+
+static void init_indices(void)
+{
+ int i, j, k;
+
+ // Binomial[k][n] = Bin(n, k)
+ for (i = 0; i < 7; i++)
+ for (j = 0; j < 64; j++) {
+ size_t f = 1;
+ size_t l = 1;
+ for (k = 0; k < i; k++) {
+ f *= (j - k);
+ l *= (k + 1);
+ }
+ Binomial[i][j] = f / l;
+ }
+
+ for (i = 0; i < 6; i++) {
+ size_t s = 0;
+ for (j = 0; j < 24; j++) {
+ PawnIdx[0][i][j] = s;
+ s += Binomial[i][PawnTwist[0][(1 + (j % 6)) * 8 + (j / 6)]];
+ if ((j + 1) % 6 == 0) {
+ PawnFactorFile[i][j / 6] = s;
+ s = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < 6; i++) {
+ size_t s = 0;
+ for (j = 0; j < 24; j++) {
+ PawnIdx[1][i][j] = s;
+ s += Binomial[i][PawnTwist[1][(1 + (j / 4)) * 8 + (j % 4)]];
+ if ((j + 1) % 4 == 0) {
+ PawnFactorRank[i][j / 4] = s;
+ s = 0;
+ }
+ }
+ }
+}
+
+int leading_pawn(int *p, struct BaseEntry *be, const int enc)
+{
+ for (int i = 1; i < be->pawns[0]; i++)
+ if (Flap[enc-1][p[0]] > Flap[enc-1][p[i]])
+ Swap(p[0], p[i]);
+
+ return enc == FILE_ENC ? FileToFile[p[0] & 7] : (p[0] - 8) >> 3;
+}
+
+size_t encode(int *p, struct EncInfo *ei, struct BaseEntry *be,
+ const int enc)
+{
+ int n = be->num;
+ size_t idx;
+ int k;
+
+ if (p[0] & 0x04)
+ for (int i = 0; i < n; i++)
+ p[i] ^= 0x07;
+
+ if (enc == PIECE_ENC) {
+ if (p[0] & 0x20)
+ for (int i = 0; i < n; i++)
+ p[i] ^= 0x38;
+
+ for (int i = 0; i < n; i++)
+ if (OffDiag[p[i]]) {
+ if (OffDiag[p[i]] > 0 && i < (be->kk_enc ? 2 : 3))
+ for (int j = 0; j < n; j++)
+ p[j] = FlipDiag[p[j]];
+ break;
+ }
+
+ if (be->kk_enc) {
+ idx = KKIdx[Triangle[p[0]]][p[1]];
+ k = 2;
+ } else {
+ int s1 = (p[1] > p[0]);
+ int s2 = (p[2] > p[0]) + (p[2] > p[1]);
+
+ if (OffDiag[p[0]])
+ idx = Triangle[p[0]] * 63*62 + (p[1] - s1) * 62 + (p[2] - s2);
+ else if (OffDiag[p[1]])
+ idx = 6*63*62 + Diag[p[0]] * 28*62 + Lower[p[1]] * 62 + p[2] - s2;
+ else if (OffDiag[p[2]])
+ idx = 6*63*62 + 4*28*62 + Diag[p[0]] * 7*28 + (Diag[p[1]] - s1) * 28 + Lower[p[2]];
+ else
+ idx = 6*63*62 + 4*28*62 + 4*7*28 + Diag[p[0]] * 7*6 + (Diag[p[1]] - s1) * 6 + (Diag[p[2]] - s2);
+ k = 3;
+ }
+ idx *= ei->factor[0];
+ } else {
+ for (int i = 1; i < be->pawns[0]; i++)
+ for (int j = i + 1; j < be->pawns[0]; j++)
+ if (PawnTwist[enc-1][p[i]] < PawnTwist[enc-1][p[j]])
+ Swap(p[i], p[j]);
+
+ k = be->pawns[0];
+ idx = PawnIdx[enc-1][k-1][Flap[enc-1][p[0]]];
+ for (int i = 1; i < k; i++)
+ idx += Binomial[k-i][PawnTwist[enc-1][p[i]]];
+ idx *= ei->factor[0];
+
+ // Pawns of other color
+ if (be->pawns[1]) {
+ int t = k + be->pawns[1];
+ for (int i = k; i < t; i++)
+ for (int j = i + 1; j < t; j++)
+ if (p[i] > p[j]) Swap(p[i], p[j]);
+ size_t s = 0;
+ for (int i = k; i < t; i++) {
+ int sq = p[i];
+ int skips = 0;
+ for (int j = 0; j < k; j++)
+ skips += (sq > p[j]);
+ s += Binomial[i - k + 1][sq - skips - 8];
+ }
+ idx += s * ei->factor[k];
+ k = t;
+ }
+ }
+
+ for (; k < n;) {
+ int t = k + ei->norm[k];
+ for (int i = k; i < t; i++)
+ for (int j = i + 1; j < t; j++)
+ if (p[i] > p[j]) Swap(p[i], p[j]);
+ size_t s = 0;
+ for (int i = k; i < t; i++) {
+ int sq = p[i];
+ int skips = 0;
+ for (int j = 0; j < k; j++)
+ skips += (sq > p[j]);
+ s += Binomial[i - k + 1][sq - skips];
+ }
+ idx += s * ei->factor[k];
+ k = t;
+ }
+
+ return idx;
+}
+
+static size_t encode_piece(int *p, struct EncInfo *ei, struct BaseEntry *be)
+{
+ return encode(p, ei, be, PIECE_ENC);
+}
+
+static size_t encode_pawn_f(int *p, struct EncInfo *ei, struct BaseEntry *be)
+{
+ return encode(p, ei, be, FILE_ENC);
+}
+
+static size_t encode_pawn_r(int *p, struct EncInfo *ei, struct BaseEntry *be)
+{
+ return encode(p, ei, be, RANK_ENC);
+}
+
+// Count number of placements of k like pieces on n squares
+static size_t subfactor(size_t k, size_t n)
+{
+ size_t f = n;
+ size_t l = 1;
+ for (size_t i = 1; i < k; i++) {
+ f *= n - i;
+ l *= i + 1;
+ }
+
+ return f / l;
+}
+
+static size_t init_enc_info(struct EncInfo *ei, struct BaseEntry *be,
+ uint8_t *tb, int shift, int t, const int enc)
+{
+ bool morePawns = enc != PIECE_ENC && be->pawns[1] > 0;
+
+ for (int i = 0; i < be->num; i++) {
+ ei->pieces[i] = (tb[i + 1 + morePawns] >> shift) & 0x0f;
+ ei->norm[i] = 0;
+ }
+
+ int order = (tb[0] >> shift) & 0x0f;
+ int order2 = morePawns ? (tb[1] >> shift) & 0x0f : 0x0f;
+
+ int k = ei->norm[0] = enc != PIECE_ENC ? be->pawns[0]
+ : be->kk_enc ? 2 : 3;
+
+ if (morePawns) {
+ ei->norm[k] = be->pawns[1];
+ k += ei->norm[k];
+ }
+
+ for (int i = k; i < be->num; i += ei->norm[i])
+ for (int j = i; j < be->num && ei->pieces[j] == ei->pieces[i]; j++)
+ ei->norm[i]++;
+
+ int n = 64 - k;
+ size_t f = 1;
+
+ for (int i = 0; k < be->num || i == order || i == order2; i++) {
+ if (i == order) {
+ ei->factor[0] = f;
+ f *= enc == FILE_ENC ? PawnFactorFile[ei->norm[0] - 1][t]
+ : enc == RANK_ENC ? PawnFactorRank[ei->norm[0] - 1][t]
+ : be->kk_enc ? 462 : 31332;
+ } else if (i == order2) {
+ ei->factor[ei->norm[0]] = f;
+ f *= subfactor(ei->norm[ei->norm[0]], 48 - ei->norm[0]);
+ } else {
+ ei->factor[k] = f;
+ f *= subfactor(ei->norm[k], n);
+ n -= ei->norm[k];
+ k += ei->norm[k];
+ }
+ }
+
+ return f;
+}
+
+static void calc_symLen(struct PairsData *d, uint32_t s, char *tmp)
+{
+ uint8_t *w = d->symPat + 3 * s;
+ uint32_t s2 = (w[2] << 4) | (w[1] >> 4);
+ if (s2 == 0x0fff)
+ d->symLen[s] = 0;
+ else {
+ uint32_t s1 = ((w[1] & 0xf) << 8) | w[0];
+ if (!tmp[s1]) calc_symLen(d, s1, tmp);
+ if (!tmp[s2]) calc_symLen(d, s2, tmp);
+ d->symLen[s] = d->symLen[s1] + d->symLen[s2] + 1;
+ }
+ tmp[s] = 1;
+}
+
+static struct PairsData *setup_pairs(uint8_t **ptr, size_t tb_size,
+ size_t *size, uint8_t *flags, int type)
+{
+ struct PairsData *d;
+ uint8_t *data = *ptr;
+
+ *flags = data[0];
+ if (data[0] & 0x80) {
+ d = (struct PairsData*)malloc(sizeof(struct PairsData));
+ d->idxBits = 0;
+ d->constValue[0] = type == WDL ? data[1] : 0;
+ d->constValue[1] = 0;
+ *ptr = data + 2;
+ size[0] = size[1] = size[2] = 0;
+ return d;
+ }
+
+ uint8_t blockSize = data[1];
+ uint8_t idxBits = data[2];
+ uint32_t realNumBlocks = read_le_u32(data+4);
+ uint32_t numBlocks = realNumBlocks + data[3];
+ int maxLen = data[8];
+ int minLen = data[9];
+ int h = maxLen - minLen + 1;
+ uint32_t numSyms = (uint32_t)read_le_u16(data + 10 + 2 * h);
+ d = (struct PairsData*)malloc(sizeof(struct PairsData) + h * sizeof(uint64_t) + numSyms);
+ d->blockSize = blockSize;
+ d->idxBits = idxBits;
+ d->offset = (uint16_t *)(&data[10]);
+ d->symLen = (uint8_t *)d + sizeof(struct PairsData) + h * sizeof(uint64_t);
+ d->symPat = &data[12 + 2 * h];
+ d->minLen = minLen;
+ *ptr = &data[12 + 2 * h + 3 * numSyms + (numSyms & 1)];
+
+ size_t num_indices = (tb_size + (1ULL << idxBits) - 1) >> idxBits;
+ size[0] = 6ULL * num_indices;
+ size[1] = 2ULL * numBlocks;
+ size[2] = (size_t)realNumBlocks << blockSize;
+
+ assert(numSyms < TB_MAX_SYMS);
+ char tmp[TB_MAX_SYMS];
+ memset(tmp, 0, numSyms);
+ for (uint32_t s = 0; s < numSyms; s++)
+ if (!tmp[s])
+ calc_symLen(d, s, tmp);
+
+ d->base[h - 1] = 0;
+ for (int i = h - 2; i >= 0; i--)
+ d->base[i] = (d->base[i + 1] + read_le_u16((uint8_t *)(d->offset + i)) - read_le_u16((uint8_t *)(d->offset + i + 1))) / 2;
+#ifdef DECOMP64
+ for (int i = 0; i < h; i++)
+ d->base[i] <<= 64 - (minLen + i);
+#else
+ for (int i = 0; i < h; i++)
+ d->base[i] <<= 32 - (minLen + i);
+#endif
+ d->offset -= d->minLen;
+
+ return d;
+}
+
+static bool init_table(struct BaseEntry *be, const char *str, int type)
+{
+ uint8_t *data = (uint8_t*)map_tb(str, tbSuffix[type], &be->mapping[type]);
+ if (!data) return false;
+
+ if (read_le_u32(data) != tbMagic[type]) {
+ fprintf(stderr, "Corrupted table.\n");
+ unmap_file((void*)data, be->mapping[type]);
+ return false;
+ }
+
+ be->data[type] = data;
+
+ bool split = type != DTZ && (data[4] & 0x01);
+ if (type == DTM)
+ be->dtmLossOnly = data[4] & 0x04;
+
+ data += 5;
+
+ size_t tb_size[6][2];
+ int num = num_tables(be, type);
+ struct EncInfo *ei = first_ei(be, type);
+ int enc = !be->hasPawns ? PIECE_ENC : type != DTM ? FILE_ENC : RANK_ENC;
+
+ for (int t = 0; t < num; t++) {
+ tb_size[t][0] = init_enc_info(&ei[t], be, data, 0, t, enc);
+ if (split)
+ tb_size[t][1] = init_enc_info(&ei[num + t], be, data, 4, t, enc);
+ data += be->num + 1 + (be->hasPawns && be->pawns[1]);
+ }
+ data += (uintptr_t)data & 1;
+
+ size_t size[6][2][3];
+ for (int t = 0; t < num; t++) {
+ uint8_t flags;
+ ei[t].precomp = setup_pairs(&data, tb_size[t][0], size[t][0], &flags, type);
+ if (type == DTZ) {
+ if (!be->hasPawns)
+ PIECE(be)->dtzFlags = flags;
+ else
+ PAWN(be)->dtzFlags[t] = flags;
+ }
+ if (split)
+ ei[num + t].precomp = setup_pairs(&data, tb_size[t][1], size[t][1], &flags, type);
+ else if (type != DTZ)
+ ei[num + t].precomp = NULL;
+ }
+
+ if (type == DTM && !be->dtmLossOnly) {
+ uint16_t *map = (uint16_t *)data;
+ *(be->hasPawns ? &PAWN(be)->dtmMap : &PIECE(be)->dtmMap) = map;
+ uint16_t (*mapIdx)[2][2] = be->hasPawns ? &PAWN(be)->dtmMapIdx[0]
+ : &PIECE(be)->dtmMapIdx;
+ for (int t = 0; t < num; t++) {
+ for (int i = 0; i < 2; i++) {
+ mapIdx[t][0][i] = (uint16_t)(data + 1 - (uint8_t*)map);
+ data += 2 + 2 * read_le_u16(data);
+ }
+ if (split) {
+ for (int i = 0; i < 2; i++) {
+ mapIdx[t][1][i] = (uint16_t)(data + 1 - (uint8_t*)map);
+ data += 2 + 2 * read_le_u16(data);
+ }
+ }
+ }
+ }
+
+ if (type == DTZ) {
+ void *map = data;
+ *(be->hasPawns ? &PAWN(be)->dtzMap : &PIECE(be)->dtzMap) = map;
+ uint16_t (*mapIdx)[4] = be->hasPawns ? &PAWN(be)->dtzMapIdx[0]
+ : &PIECE(be)->dtzMapIdx;
+ uint8_t *flags = be->hasPawns ? &PAWN(be)->dtzFlags[0]
+ : &PIECE(be)->dtzFlags;
+ for (int t = 0; t < num; t++) {
+ if (flags[t] & 2) {
+ if (!(flags[t] & 16)) {
+ for (int i = 0; i < 4; i++) {
+ mapIdx[t][i] = (uint16_t)(data + 1 - (uint8_t *)map);
+ data += 1 + data[0];
+ }
+ } else {
+ data += (uintptr_t)data & 0x01;
+ for (int i = 0; i < 4; i++) {
+ mapIdx[t][i] = (uint16_t)((uint16_t*)data + 1 - (uint16_t *)map);
+ data += 2 + 2 * read_le_u16(data);
+ }
+ }
+ }
+ }
+ data += (uintptr_t)data & 0x01;
+ }
+
+ for (int t = 0; t < num; t++) {
+ ei[t].precomp->indexTable = data;
+ data += size[t][0][0];
+ if (split) {
+ ei[num + t].precomp->indexTable = data;
+ data += size[t][1][0];
+ }
+ }
+
+ for (int t = 0; t < num; t++) {
+ ei[t].precomp->sizeTable = (uint16_t *)data;
+ data += size[t][0][1];
+ if (split) {
+ ei[num + t].precomp->sizeTable = (uint16_t *)data;
+ data += size[t][1][1];
+ }
+ }
+
+ for (int t = 0; t < num; t++) {
+ data = (uint8_t *)(((uintptr_t)data + 0x3f) & ~0x3f);
+ ei[t].precomp->data = data;
+ data += size[t][0][2];
+ if (split) {
+ data = (uint8_t *)(((uintptr_t)data + 0x3f) & ~0x3f);
+ ei[num + t].precomp->data = data;
+ data += size[t][1][2];
+ }
+ }
+
+ if (type == DTM && be->hasPawns)
+ PAWN(be)->dtmSwitched =
+ calc_key_from_pieces(ei[0].pieces, be->num) != be->key;
+
+ return true;
+}
+
+static uint8_t *decompress_pairs(struct PairsData *d, size_t idx)
+{
+ if (!d->idxBits)
+ return d->constValue;
+
+ uint32_t mainIdx = (uint32_t)(idx >> d->idxBits);
+ int litIdx = (idx & (((size_t)1 << d->idxBits) - 1)) - ((size_t)1 << (d->idxBits - 1));
+ uint32_t block;
+ memcpy(&block, d->indexTable + 6 * mainIdx, sizeof(block));
+ block = from_le_u32(block);
+
+ uint16_t idxOffset = *(uint16_t *)(d->indexTable + 6 * mainIdx + 4);
+ litIdx += from_le_u16(idxOffset);
+
+ if (litIdx < 0)
+ while (litIdx < 0)
+ litIdx += d->sizeTable[--block] + 1;
+ else
+ while (litIdx > d->sizeTable[block])
+ litIdx -= d->sizeTable[block++] + 1;
+
+ uint32_t *ptr = (uint32_t *)(d->data + ((size_t)block << d->blockSize));
+
+ int m = d->minLen;
+ uint16_t *offset = d->offset;
+ uint64_t *base = d->base - m;
+ uint8_t *symLen = d->symLen;
+ uint32_t sym, bitCnt;
+
+#ifdef DECOMP64
+ uint64_t code = from_be_u64(*(uint64_t *)ptr);
+
+ ptr += 2;
+ bitCnt = 0; // number of "empty bits" in code
+ for (;;) {
+ int l = m;
+ while (code < base[l]) l++;
+ sym = from_le_u16(offset[l]);
+ sym += (uint32_t)((code - base[l]) >> (64 - l));
+ if (litIdx < (int)symLen[sym] + 1) break;
+ litIdx -= (int)symLen[sym] + 1;
+ code <<= l;
+ bitCnt += l;
+ if (bitCnt >= 32) {
+ bitCnt -= 32;
+ uint32_t tmp = from_be_u32(*ptr++);
+ code |= (uint64_t)tmp << bitCnt;
+ }
+ }
+#else
+ uint32_t next = 0;
+ uint32_t data = *ptr++;
+ uint32_t code = from_be_u32(data);
+ bitCnt = 0; // number of bits in next
+ for (;;) {
+ int l = m;
+ while (code < base[l]) l++;
+ sym = offset[l] + ((code - base[l]) >> (32 - l));
+ if (litIdx < (int)symLen[sym] + 1) break;
+ litIdx -= (int)symLen[sym] + 1;
+ code <<= l;
+ if (bitCnt < l) {
+ if (bitCnt) {
+ code |= (next >> (32 - l));
+ l -= bitCnt;
+ }
+ data = *ptr++;
+ next = from_be_u32(data);
+ bitCnt = 32;
+ }
+ code |= (next >> (32 - l));
+ next <<= l;
+ bitCnt -= l;
+ }
+#endif
+ uint8_t *symPat = d->symPat;
+ while (symLen[sym] != 0) {
+ uint8_t *w = symPat + (3 * sym);
+ int s1 = ((w[1] & 0xf) << 8) | w[0];
+ if (litIdx < (int)symLen[s1] + 1)
+ sym = s1;
+ else {
+ litIdx -= (int)symLen[s1] + 1;
+ sym = (w[2] << 4) | (w[1] >> 4);
+ }
+ }
+
+ return &symPat[3 * sym];
+}
+
+// p[i] is to contain the square 0-63 (A1-H8) for a piece of type
+// pc[i] ^ flip, where 1 = white pawn, ..., 14 = black king and pc ^ flip
+// flips between white and black if flip == true.
+// Pieces of the same type are guaranteed to be consecutive.
+inline static int fill_squares(const Pos *pos, uint8_t *pc, bool flip, int mirror, int *p,
+ int i)
+{
+ Color color = ColorOfPiece(pc[i]);
+ if (flip) color = (Color)(!(int)color);
+ uint64_t bb = pieces_by_type(pos, color, TypeOfPiece(pc[i]));
+ unsigned sq;
+ do {
+ sq = lsb(bb);
+ p[i++] = sq ^ mirror;
+ bb = poplsb(bb);
+ } while (bb);
+ return i;
+}
+
+static int probe_table(const Pos *pos, int s, int *success, const int type)
+{
+ // Obtain the position's material-signature key
+ uint64_t key = calc_key(pos,false);
+
+ // Test for KvK
+ // Note: Cfish has key == 2ULL for KvK but we have 0
+ if (type == WDL && key == 0ULL)
+ return 0;
+
+ int hashIdx = key >> (64 - TB_HASHBITS);
+ while (tbHash[hashIdx].key && tbHash[hashIdx].key != key)
+ hashIdx = (hashIdx + 1) & ((1 << TB_HASHBITS) - 1);
+ if (!tbHash[hashIdx].ptr || atomic_load_explicit(&tbHash[hashIdx].error, memory_order_relaxed)) {
+ *success = 0;
+ return 0;
+ }
+
+ struct BaseEntry *be = tbHash[hashIdx].ptr;
+ if ((type == DTM && !be->hasDtm) || (type == DTZ && !be->hasDtz)) {
+ *success = 0;
+ return 0;
+ }
+
+ // Use double-checked locking to reduce locking overhead
+ if (!atomic_load_explicit(&be->ready[type], memory_order_acquire)) {
+ LOCK(tbMutex);
+ if (atomic_load_explicit(&tbHash[hashIdx].error, memory_order_relaxed)) {
+ *success = 0;
+ UNLOCK(tbMutex);
+ return 0;
+ }
+ if (!atomic_load_explicit(&be->ready[type], memory_order_relaxed)) {
+ char str[16];
+ prt_str(pos, str, be->key != key);
+ if (!init_table(be, str, type)) {
+ atomic_store_explicit(&tbHash[hashIdx].error, true, memory_order_relaxed);
+ *success = 0;
+ UNLOCK(tbMutex);
+ return 0;
+ }
+ atomic_store_explicit(&be->ready[type], true, memory_order_release);
+ }
+ UNLOCK(tbMutex);
+ }
+
+ bool bside, flip;
+ if (!be->symmetric) {
+ flip = key != be->key;
+ bside = (pos->turn == WHITE) == flip;
+ if (type == DTM && be->hasPawns && PAWN(be)->dtmSwitched) {
+ flip = !flip;
+ bside = !bside;
+ }
+ } else {
+ flip = pos->turn != WHITE;
+ bside = false;
+ }
+
+ struct EncInfo *ei = first_ei(be, type);
+ int p[TB_PIECES];
+ size_t idx;
+ int t = 0;
+ uint8_t flags = 0; // initialize to fix GCC warning
+
+ if (!be->hasPawns) {
+ if (type == DTZ) {
+ flags = PIECE(be)->dtzFlags;
+ if ((flags & 1) != bside && !be->symmetric) {
+ *success = -1;
+ return 0;
+ }
+ }
+ ei = type != DTZ ? &ei[bside] : ei;
+ for (int i = 0; i < be->num;)
+ i = fill_squares(pos, ei->pieces, flip, 0, p, i);
+ idx = encode_piece(p, ei, be);
+ } else {
+ int i = fill_squares(pos, ei->pieces, flip, flip ? 0x38 : 0, p, 0);
+ t = leading_pawn(p, be, type != DTM ? FILE_ENC : RANK_ENC);
+ if (type == DTZ) {
+ flags = PAWN(be)->dtzFlags[t];
+ if ((flags & 1) != bside && !be->symmetric) {
+ *success = -1;
+ return 0;
+ }
+ }
+ ei = type == WDL ? &ei[t + 4 * bside]
+ : type == DTM ? &ei[t + 6 * bside] : &ei[t];
+ while (i < be->num)
+ i = fill_squares(pos, ei->pieces, flip, flip ? 0x38 : 0, p, i);
+ idx = type != DTM ? encode_pawn_f(p, ei, be) : encode_pawn_r(p, ei, be);
+ }
+
+ uint8_t *w = decompress_pairs(ei->precomp, idx);
+
+ if (type == WDL)
+ return (int)w[0] - 2;
+
+ int v = w[0] + ((w[1] & 0x0f) << 8);
+
+ if (type == DTM) {
+ if (!be->dtmLossOnly)
+ v = (int)from_le_u16(be->hasPawns
+ ? PAWN(be)->dtmMap[PAWN(be)->dtmMapIdx[t][bside][s] + v]
+ : PIECE(be)->dtmMap[PIECE(be)->dtmMapIdx[bside][s] + v]);
+ } else {
+ if (flags & 2) {
+ int m = WdlToMap[s + 2];
+ if (!(flags & 16))
+ v = be->hasPawns
+ ? ((uint8_t *)PAWN(be)->dtzMap)[PAWN(be)->dtzMapIdx[t][m] + v]
+ : ((uint8_t *)PIECE(be)->dtzMap)[PIECE(be)->dtzMapIdx[m] + v];
+ else
+ v = (int)from_le_u16(be->hasPawns
+ ? ((uint16_t *)PAWN(be)->dtzMap)[PAWN(be)->dtzMapIdx[t][m] + v]
+ : ((uint16_t *)PIECE(be)->dtzMap)[PIECE(be)->dtzMapIdx[m] + v]);
+ }
+ if (!(flags & PAFlags[s + 2]) || (s & 1))
+ v *= 2;
+ }
+
+ return v;
+}
+
+static int probe_wdl_table(const Pos *pos, int *success)
+{
+ return probe_table(pos, 0, success, WDL);
+}
+
+static int probe_dtm_table(const Pos *pos, int won, int *success)
+{
+ return probe_table(pos, won, success, DTM);
+}
+
+static int probe_dtz_table(const Pos *pos, int wdl, int *success)
+{
+ return probe_table(pos, wdl, success, DTZ);
+}
+
+// probe_ab() is not called for positions with en passant captures.
+static int probe_ab(const Pos *pos, int alpha, int beta, int *success)
+{
+ assert(pos->ep == 0);
+
+ TbMove moves0[TB_MAX_CAPTURES];
+ TbMove *m = moves0;
+ // Generate (at least) all legal captures including (under)promotions.
+ // It is OK to generate more, as long as they are filtered out below.
+ TbMove *end = gen_captures(pos, m);
+ for (; m < end; m++) {
+ Pos pos1;
+ TbMove move = *m;
+ if (!is_capture(pos, move))
+ continue;
+ if (!do_move(&pos1, pos, move))
+ continue; // illegal move
+ int v = -probe_ab(&pos1, -beta, -alpha, success);
+ if (*success == 0) return 0;
+ if (v > alpha) {
+ if (v >= beta)
+ return v;
+ alpha = v;
+ }
+ }
+
+ int v = probe_wdl_table(pos, success);
+
+ return alpha >= v ? alpha : v;
+}
+
+// Probe the WDL table for a particular position.
+//
+// If *success != 0, the probe was successful.
+//
+// If *success == 2, the position has a winning capture, or the position
+// is a cursed win and has a cursed winning capture, or the position
+// has an ep capture as only best move.
+// This is used in probe_dtz().
+//
+// The return value is from the point of view of the side to move:
+// -2 : loss
+// -1 : loss, but draw under 50-move rule
+// 0 : draw
+// 1 : win, but draw under 50-move rule
+// 2 : win
+int probe_wdl(Pos *pos, int *success)
+{
+ *success = 1;
+
+ // Generate (at least) all legal captures including (under)promotions.
+ TbMove moves0[TB_MAX_CAPTURES];
+ TbMove *m = moves0;
+ TbMove *end = gen_captures(pos, m);
+ int bestCap = -3, bestEp = -3;
+
+ // We do capture resolution, letting bestCap keep track of the best
+ // capture without ep rights and letting bestEp keep track of still
+ // better ep captures if they exist.
+
+ for (; m < end; m++) {
+ Pos pos1;
+ TbMove move = *m;
+ if (!is_capture(pos, move))
+ continue;
+ if (!do_move(&pos1, pos, move))
+ continue; // illegal move
+ int v = -probe_ab(&pos1, -2, -bestCap, success);
+ if (*success == 0) return 0;
+ if (v > bestCap) {
+ if (v == 2) {
+ *success = 2;
+ return 2;
+ }
+ if (!is_en_passant(pos,move))
+ bestCap = v;
+ else if (v > bestEp)
+ bestEp = v;
+ }
+ }
+
+ int v = probe_wdl_table(pos, success);
+ if (*success == 0) return 0;
+
+ // Now max(v, bestCap) is the WDL value of the position without ep rights.
+ // If the position without ep rights is not stalemate or no ep captures
+ // exist, then the value of the position is max(v, bestCap, bestEp).
+ // If the position without ep rights is stalemate and bestEp > -3,
+ // then the value of the position is bestEp (and we will have v == 0).
+
+ if (bestEp > bestCap) {
+ if (bestEp > v) { // ep capture (possibly cursed losing) is best.
+ *success = 2;
+ return bestEp;
+ }
+ bestCap = bestEp;
+ }
+
+ // Now max(v, bestCap) is the WDL value of the position unless
+ // the position without ep rights is stalemate and bestEp > -3.
+
+ if (bestCap >= v) {
+ // No need to test for the stalemate case here: either there are
+ // non-ep captures, or bestCap == bestEp >= v anyway.
+ *success = 1 + (bestCap > 0);
+ return bestCap;
+ }
+
+ // Now handle the stalemate case.
+ if (bestEp > -3 && v == 0) {
+ TbMove moves[TB_MAX_MOVES];
+ TbMove *end2 = gen_moves(pos, moves);
+ // Check for stalemate in the position with ep captures.
+ for (m = moves; m < end2; m++) {
+ if (!is_en_passant(pos,*m) && legal_move(pos, *m)) break;
+ }
+ if (m == end2 && !is_check(pos)) {
+ // stalemate score from tb (w/o e.p.), but an en-passant capture
+ // is possible.
+ *success = 2;
+ return bestEp;
+ }
+ }
+ // Stalemate / en passant not an issue, so v is the correct value.
+
+ return v;
+}
+
+#if 0
+// This will not be called for positions with en passant captures
+static Value probe_dtm_dc(const Pos *pos, int won, int *success)
+{
+ assert(ep_square() == 0);
+
+ Value v, bestCap = -TB_VALUE_INFINITE;
+
+ TbMove moves0[TB_MAX_CAPTURES];
+ TbMove *end, *m = moves0;
+
+ // Generate at least all legal captures including (under)promotions
+ end = gen_captures(pos, m);
+ Pos pos1;
+ for (; m < end; m++) {
+ TbMove move = m->move;
+ if (!is_capture(pos, move))
+ continue;
+ if (!do_move(&pos1, pos, move))
+ continue;
+ if (!won)
+ v = -probe_dtm_dc(&pos1, 1, success) + 1;
+ else if (probe_ab(&pos1, -1, 0, success) < 0 && *success)
+ v = -probe_dtm_dc(&pos1, 0, success) - 1;
+ else
+ v = -TB_VALUE_INFINITE;
+ bestCap = max(bestCap,v);
+ if (*success == 0) return 0;
+ }
+
+ int dtm = probe_dtm_table(pos, won, success);
+ v = won ? TB_VALUE_MATE - 2 * dtm + 1 : -TB_VALUE_MATE + 2 * dtm;
+
+ return max(bestCap,v);
+}
+#endif
+
+static Value probe_dtm_win(const Pos *pos, int *success);
+
+// Probe a position known to lose by probing the DTM table and looking
+// at captures.
+static Value probe_dtm_loss(const Pos *pos, int *success)
+{
+ Value v, best = -TB_VALUE_INFINITE, numEp = 0;
+
+ TbMove moves0[TB_MAX_CAPTURES];
+ // Generate at least all legal captures including (under)promotions
+ TbMove *end, *m = moves0;
+ end = gen_captures(pos, m);
+
+ Pos pos1;
+ for (; m < end; m++) {
+ TbMove move = *m;
+ if (!is_capture(pos, move) || !legal_move(pos, move))
+ continue;
+ if (is_en_passant(pos, move))
+ numEp++;
+ do_move(&pos1, pos, move);
+ v = -probe_dtm_win(&pos1, success) + 1;
+ if (v > best) {
+ best = v;
+ }
+ if (*success == 0)
+ return 0;
+ }
+
+ // If there are en passant captures, the position without ep rights
+ // may be a stalemate. If it is, we must avoid probing the DTM table.
+ if (numEp != 0 && gen_legal(pos, m) == m + numEp)
+ return best;
+
+ v = -TB_VALUE_MATE + 2 * probe_dtm_table(pos, 0, success);
+ return best > v ? best : v;
+}
+
+static Value probe_dtm_win(const Pos *pos, int *success)
+{
+ Value v, best = -TB_VALUE_INFINITE;
+
+ // Generate all moves
+ TbMove moves0[TB_MAX_CAPTURES];
+ TbMove *m = moves0;
+ TbMove *end = gen_moves(pos, m);
+ // Perform a 1-ply search
+ Pos pos1;
+ for (; m < end; m++) {
+ TbMove move = *m;
+ if (do_move(&pos1, pos, move)) {
+ // not legal
+ continue;
+ }
+ if ((pos1.ep > 0 ? probe_wdl(&pos1, success)
+ : probe_ab(&pos1, -1, 0, success)) < 0
+ && *success)
+ v = -probe_dtm_loss(&pos1, success) - 1;
+ else
+ v = -TB_VALUE_INFINITE;
+ if (v > best) {
+ best = v;
+ }
+ if (*success == 0) return 0;
+ }
+
+ return best;
+}
+
+Value TB_probe_dtm(const Pos *pos, int wdl, int *success)
+{
+ assert(wdl != 0);
+
+ *success = 1;
+
+ return wdl > 0 ? probe_dtm_win(pos, success)
+ : probe_dtm_loss(pos, success);
+}
+
+#if 0
+// To be called only for non-drawn positions.
+Value TB_probe_dtm2(const Pos *pos, int wdl, int *success)
+{
+ assert(wdl != 0);
+
+ *success = 1;
+ Value v, bestCap = -TB_VALUE_INFINITE, bestEp = -TB_VALUE_INFINITE;
+
+ TbMove moves0[TB_MAX_CAPTURES];
+ TbMove *end, *m = moves0;
+
+ // Generate at least all legal captures including (under)promotions
+ end = gen_captures(pos, m);
+ Pos pos0 = *pos;
+
+ // Resolve captures, letting bestCap keep track of the best non-ep
+ // capture and letting bestEp keep track of the best ep capture.
+ Pos pos1;
+ for (; m < end; m++) {
+ TbMove move = *m;
+ if (!is_capture(pos, move))
+ continue;
+ if (!do_move(&pos1, pos, move))
+ continue;
+ if (wdl < 0)
+ v = -probe_dtm_dc(&pos1, 1, success) + 1;
+ else if (probe_ab(&pos1, -1, 0, success) < 0 && *success)
+ v = -probe_dtm_dc(&pos1, 0, success) - 1;
+ else
+ v = -TB_VALUE_MATE;
+ if (is_en_passant(&pos1, move))
+ bestEp = max(bestEp,v);
+ else
+ bestCap = max(bestCap,v);
+ if (*success == 0)
+ return 0;
+ }
+
+ // If there are en passant captures, we have to determine the WDL value
+ // for the position without ep rights if it might be different.
+ if (bestEp > -TB_VALUE_INFINITE && (bestEp < 0 || bestCap < 0)) {
+ assert(ep_square() != 0);
+ uint8_t s = pos->st->epSquare;
+ pos->st->epSquare = 0;
+ wdl = probe_ab(pos, -2, 2, success);
+ pos->st->epSquare = s;
+ if (*success == 0)
+ return 0;
+ if (wdl == 0)
+ return bestEp;
+ }
+
+ bestCap = max(bestCap,v);
+ int dtm = probe_dtm_table(pos, wdl > 0, success);
+ v = wdl > 0 ? TB_VALUE_MATE - 2 * dtm + 1 : -TB_VALUE_MATE + 2 * dtm;
+ return max(bestCap,v);
+}
+#endif
+
+static int WdlToDtz[] = { -1, -101, 0, 101, 1 };
+
+// Probe the DTZ table for a particular position.
+// If *success != 0, the probe was successful.
+// The return value is from the point of view of the side to move:
+// n < -100 : loss, but draw under 50-move rule
+// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
+// 0 : draw
+// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
+// 100 < n : win, but draw under 50-move rule
+//
+// If the position mate, -1 is returned instead of 0.
+//
+// The return value n can be off by 1: a return value -n can mean a loss
+// in n+1 ply and a return value +n can mean a win in n+1 ply. This
+// cannot happen for tables with positions exactly on the "edge" of
+// the 50-move rule.
+//
+// This means that if dtz > 0 is returned, the position is certainly
+// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
+// picks moves that preserve dtz + 50-move-counter <= 99.
+//
+// If n = 100 immediately after a capture or pawn move, then the position
+// is also certainly a win, and during the whole phase until the next
+// capture or pawn move, the inequality to be preserved is
+// dtz + 50-movecounter <= 100.
+//
+// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
+// then do not accept moves leading to dtz + 50-move-counter == 100.
+//
+int probe_dtz(Pos *pos, int *success)
+{
+ int wdl = probe_wdl(pos, success);
+ if (*success == 0) return 0;
+
+ // If draw, then dtz = 0.
+ if (wdl == 0) return 0;
+
+ // Check for winning capture or en passant capture as only best move.
+ if (*success == 2)
+ return WdlToDtz[wdl + 2];
+
+ TbMove moves[TB_MAX_MOVES];
+ TbMove *m = moves, *end = NULL;
+ Pos pos1;
+
+ // If winning, check for a winning pawn move.
+ if (wdl > 0) {
+ // Generate at least all legal non-capturing pawn moves
+ // including non-capturing promotions.
+ // (The following call in fact generates all moves.)
+ end = gen_legal(pos, moves);
+
+ for (m = moves; m < end; m++) {
+ TbMove move = *m;
+ if (type_of_piece_moved(pos,move) != PAWN || is_capture(pos, move))
+ continue;
+ if (!do_move(&pos1, pos, move))
+ continue; // not legal
+ int v = -probe_wdl(&pos1, success);
+ if (*success == 0) return 0;
+ if (v == wdl) {
+ assert(wdl < 3);
+ return WdlToDtz[wdl + 2];
+ }
+ }
+ }
+
+ // If we are here, we know that the best move is not an ep capture.
+ // In other words, the value of wdl corresponds to the WDL value of
+ // the position without ep rights. It is therefore safe to probe the
+ // DTZ table with the current value of wdl.
+
+ int dtz = probe_dtz_table(pos, wdl, success);
+ if (*success >= 0)
+ return WdlToDtz[wdl + 2] + ((wdl > 0) ? dtz : -dtz);
+
+ // *success < 0 means we need to probe DTZ for the other side to move.
+ int best;
+ if (wdl > 0) {
+ best = INT32_MAX;
+ } else {
+ // If (cursed) loss, the worst case is a losing capture or pawn move
+ // as the "best" move, leading to dtz of -1 or -101.
+ // In case of mate, this will cause -1 to be returned.
+ best = WdlToDtz[wdl + 2];
+ // If wdl < 0, we still have to generate all moves.
+ end = gen_moves(pos, m);
+ }
+ assert(end != NULL);
+
+ for (m = moves; m < end; m++) {
+ TbMove move = *m;
+ // We can skip pawn moves and captures.
+ // If wdl > 0, we already caught them. If wdl < 0, the initial value
+ // of best already takes account of them.
+ if (is_capture(pos, move) || type_of_piece_moved(pos, move) == PAWN)
+ continue;
+ if (!do_move(&pos1, pos, move)) {
+ // move was not legal
+ continue;
+ }
+ int v = -probe_dtz(&pos1, success);
+ // Check for the case of mate in 1
+ if (v == 1 && is_mate(&pos1))
+ best = 1;
+ else if (wdl > 0) {
+ if (v > 0 && v + 1 < best)
+ best = v + 1;
+ } else {
+ if (v - 1 < best)
+ best = v - 1;
+ }
+ if (*success == 0) return 0;
+ }
+ return best;
+}
+
+// Use the DTZ tables to rank and score all root moves in the list.
+// A return value of 0 means that not all probes were successful.
+static int root_probe_dtz(const Pos *pos, bool hasRepeated, bool useRule50, struct TbRootMoves *rm)
+{
+ int v, success;
+
+ // Obtain 50-move counter for the root position.
+ int cnt50 = pos->rule50;
+
+ // The border between draw and win lies at rank 1 or rank 900, depending
+ // on whether the 50-move rule is used.
+ int bound = useRule50 ? 900 : 1;
+
+ // Probe, rank and score each move.
+ TbMove rootMoves[TB_MAX_MOVES];
+ TbMove * end = gen_legal(pos,rootMoves);
+ rm->size = (unsigned)(end-rootMoves);
+ Pos pos1;
+ for (unsigned i = 0; i < rm->size; i++) {
+ struct TbRootMove *m = &(rm->moves[i]);
+ m->move = rootMoves[i];
+ do_move(&pos1, pos, m->move);
+
+ // Calculate dtz for the current move counting from the root position.
+ if (pos1.rule50 == 0) {
+ // If the move resets the 50-move counter, dtz is -101/-1/0/1/101.
+ v = -probe_wdl(&pos1, &success);
+ assert(v < 3);
+ v = WdlToDtz[v + 2];
+ } else {
+ // Otherwise, take dtz for the new position and correct by 1 ply.
+ v = -probe_dtz(&pos1, &success);
+ if (v > 0) v++;
+ else if (v < 0) v--;
+ }
+ // Make sure that a mating move gets value 1.
+ if (v == 2 && is_mate(&pos1)) {
+ v = 1;
+ }
+
+ if (!success) return 0;
+
+ // Better moves are ranked higher. Guaranteed wins are ranked equally.
+ // Losing moves are ranked equally unless a 50-move draw is in sight.
+ // Note that moves ranked 900 have dtz + cnt50 == 100, which in rare
+ // cases may be insufficient to win as dtz may be one off (see the
+ // comments before TB_probe_dtz()).
+ int r = v > 0 ? (v + cnt50 <= 99 && !hasRepeated ? 1000 : 1000 - (v + cnt50))
+ : v < 0 ? (-v * 2 + cnt50 < 100 ? -1000 : -1000 + (-v + cnt50))
+ : 0;
+ m->tbRank = r;
+
+ // Determine the score to be displayed for this move. Assign at least
+ // 1 cp to cursed wins and let it grow to 49 cp as the position gets
+ // closer to a real win.
+ m->tbScore = r >= bound ? TB_VALUE_MATE - TB_MAX_MATE_PLY - 1
+ : r > 0 ? max( 3, r - 800) * TB_VALUE_PAWN / 200
+ : r == 0 ? TB_VALUE_DRAW
+ : r > -bound ? min(-3, r + 800) * TB_VALUE_PAWN / 200
+ : -TB_VALUE_MATE + TB_MAX_MATE_PLY + 1;
+ }
+ return 1;
+}
+
+// Use the WDL tables to rank all root moves in the list.
+// This is a fallback for the case that some or all DTZ tables are missing.
+// A return value of 0 means that not all probes were successful.
+int root_probe_wdl(const Pos *pos, bool useRule50, struct TbRootMoves *rm)
+{
+ static int WdlToRank[] = { -1000, -899, 0, 899, 1000 };
+ static Value WdlToValue[] = {
+ -TB_VALUE_MATE + TB_MAX_MATE_PLY + 1,
+ TB_VALUE_DRAW - 2,
+ TB_VALUE_DRAW,
+ TB_VALUE_DRAW + 2,
+ TB_VALUE_MATE - TB_MAX_MATE_PLY - 1
+ };
+
+ int v, success;
+
+ // Probe, rank and score each move.
+ TbMove moves[TB_MAX_MOVES];
+ TbMove *end = gen_legal(pos,moves);
+ rm->size = (unsigned)(end-moves);
+ Pos pos1;
+ for (unsigned i = 0; i < rm->size; i++) {
+ struct TbRootMove *m = &rm->moves[i];
+ m->move = moves[i];
+ do_move(&pos1, pos, m->move);
+ v = -probe_wdl(&pos1, &success);
+ if (!success) return 0;
+ if (!useRule50)
+ v = v > 0 ? 2 : v < 0 ? -2 : 0;
+ m->tbRank = WdlToRank[v + 2];
+ m->tbScore = WdlToValue[v + 2];
+ }
+
+ return 1;
+}
+
+// Use the DTM tables to find mate scores.
+// Either DTZ or WDL must have been probed successfully earlier.
+// A return value of 0 means that not all probes were successful.
+#if defined(__cplusplus) && __cplusplus >= 201703L
+[[maybe_unused]]
+#endif
+int root_probe_dtm(const Pos *pos, struct TbRootMoves *rm)
+{
+ int success;
+ Value tmpScore[TB_MAX_MOVES];
+
+ // Probe each move.
+ for (unsigned i = 0; i < rm->size; i++) {
+ Pos pos1;
+ struct TbRootMove *m = &rm->moves[i];
+
+ // Use tbScore to find out if the position is won or lost.
+ int wdl = m->tbScore > TB_VALUE_PAWN ? 2
+ : m->tbScore < -TB_VALUE_PAWN ? -2 : 0;
+
+ if (wdl == 0)
+ tmpScore[i] = 0;
+ else {
+ // Probe and adjust mate score by 1 ply.
+ do_move(&pos1, pos, m->pv[0]);
+ Value v = -TB_probe_dtm(&pos1, -wdl, &success);
+ tmpScore[i] = wdl > 0 ? v - 1 : v + 1;
+ if (success == 0)
+ return 0;
+ }
+ }
+
+ // All probes were successful. Now adjust TB scores and ranks.
+ for (unsigned i = 0; i < rm->size; i++) {
+ struct TbRootMove *m = &rm->moves[i];
+
+ m->tbScore = tmpScore[i];
+
+ // Let rank correspond to mate score, except for critical moves
+ // ranked 900, which we rank below all other mates for safety.
+ // By ranking mates above 1000 or below -1000, we let the search
+ // know it need not search those moves.
+ m->tbRank = m->tbRank == 900 ? 1001 : m->tbScore;
+ }
+
+ return 1;
+}
+
+// Use the DTM tables to complete a PV with mate score.
+#if defined(__cplusplus) && __cplusplus >= 201703L
+[[maybe_unused]]
+#endif
+void tb_expand_mate(Pos *pos, struct TbRootMove *move, Value moveScore, unsigned cardinalityDTM)
+{
+ int success = 1, chk = 0;
+ Value v = moveScore, w = 0;
+ int wdl = v > 0 ? 2 : -2;
+
+ if (move->pvSize == TB_MAX_PLY)
+ return;
+
+ Pos root = *pos;
+ // First get to the end of the incomplete PV.
+ for (unsigned i = 0; i < move->pvSize; i++) {
+ v = v > 0 ? -v - 1 : -v + 1;
+ wdl = -wdl;
+ Pos pos0 = *pos;
+ do_move(pos, &pos0, move->pv[i]);
+ }
+
+ // Now try to expand until the actual mate.
+ if (popcount(pos->white | pos->black) <= cardinalityDTM) {
+ while (v != -TB_VALUE_MATE && move->pvSize < TB_MAX_PLY) {
+ v = v > 0 ? -v - 1 : -v + 1;
+ wdl = -wdl;
+ TbMove moves[TB_MAX_MOVES];
+ TbMove *end = gen_legal(pos, moves);
+ TbMove *m = moves;
+ for (; m < end; m++) {
+ Pos pos1;
+ do_move(&pos1, pos, *m);
+ if (wdl < 0)
+ chk = probe_wdl(&pos1, &success); // verify that move wins
+ w = success && (wdl > 0 || chk < 0)
+ ? TB_probe_dtm(&pos1, wdl, &success)
+ : 0;
+ if (!success || v == w) break;
+ }
+ if (!success || v != w)
+ break;
+ move->pv[move->pvSize++] = *m;
+ Pos pos0 = *pos;
+ do_move(pos, &pos0, *m);
+ }
+ }
+ // Get back to the root position.
+ *pos = root;
+}
+
+static const int wdl_to_dtz[] =
+{
+ -1, -101, 0, 101, 1
+};
+
+// This supports the original Fathom root probe API
+static uint16_t probe_root(Pos *pos, int *score, unsigned *results)
+{
+ int success;
+ int dtz = probe_dtz(pos, &success);
+ if (!success)
+ return 0;
+
+ int16_t scores[MAX_MOVES];
+ uint16_t moves0[MAX_MOVES];
+ uint16_t *moves = moves0;
+ uint16_t *end = gen_moves(pos, moves);
+ size_t len = end - moves;
+ size_t num_draw = 0;
+ unsigned j = 0;
+ for (unsigned i = 0; i < len; i++)
+ {
+ Pos pos1;
+ if (!do_move(&pos1, pos, moves[i]))
+ {
+ scores[i] = SCORE_ILLEGAL;
+ continue;
+ }
+ int v = 0;
+ // print_move(pos,moves[i]);
+ if (dtz > 0 && is_mate(&pos1))
+ v = 1;
+ else
+ {
+ if (pos1.rule50 != 0)
+ {
+ v = -probe_dtz(&pos1, &success);
+ if (v > 0)
+ v++;
+ else if (v < 0)
+ v--;
+ }
+ else
+ {
+ v = -probe_wdl(&pos1, &success);
+ v = wdl_to_dtz[v + 2];
+ }
+ }
+ num_draw += (v == 0);
+ if (!success)
+ return 0;
+ scores[i] = v;
+ if (results != NULL)
+ {
+ unsigned res = 0;
+ res = TB_SET_WDL(res, dtz_to_wdl(pos->rule50, v));
+ res = TB_SET_FROM(res, move_from(moves[i]));
+ res = TB_SET_TO(res, move_to(moves[i]));
+ res = TB_SET_PROMOTES(res, move_promotes(moves[i]));
+ res = TB_SET_EP(res, is_en_passant(pos, moves[i]));
+ res = TB_SET_DTZ(res, (v < 0? -v: v));
+ results[j++] = res;
+ }
+ }
+ if (results != NULL)
+ results[j++] = TB_RESULT_FAILED;
+ if (score != NULL)
+ *score = dtz;
+
+ // Now be a bit smart about filtering out moves.
+ if (dtz > 0) // winning (or 50-move rule draw)
+ {
+ int best = BEST_NONE;
+ uint16_t best_move = 0;
+ for (unsigned i = 0; i < len; i++)
+ {
+ int v = scores[i];
+ if (v == SCORE_ILLEGAL)
+ continue;
+ if (v > 0 && v < best)
+ {
+ best = v;
+ best_move = moves[i];
+ }
+ }
+ return (best == BEST_NONE? 0: best_move);
+ }
+ else if (dtz < 0) // losing (or 50-move rule draw)
+ {
+ int best = 0;
+ uint16_t best_move = 0;
+ for (unsigned i = 0; i < len; i++)
+ {
+ int v = scores[i];
+ if (v == SCORE_ILLEGAL)
+ continue;
+ if (v < best)
+ {
+ best = v;
+ best_move = moves[i];
+ }
+ }
+ return (best == 0? MOVE_CHECKMATE: best_move);
+ }
+ else // drawing
+ {
+ // Check for stalemate:
+ if (num_draw == 0)
+ return MOVE_STALEMATE;
+
+ // Select a "random" move that preserves the draw.
+ // Uses calc_key as the PRNG.
+ size_t count = calc_key(pos, !pos->turn) % num_draw;
+ for (unsigned i = 0; i < len; i++)
+ {
+ int v = scores[i];
+ if (v == SCORE_ILLEGAL)
+ continue;
+ if (v == 0)
+ {
+ if (count == 0)
+ return moves[i];
+ count--;
+ }
+ }
+ return 0;
+ }
+}
+
+#ifndef TB_NO_HELPER_API
+
+unsigned tb_pop_count(uint64_t bb)
+{
+ return popcount(bb);
+}
+
+unsigned tb_lsb(uint64_t bb)
+{
+ return lsb(bb);
+}
+
+uint64_t tb_pop_lsb(uint64_t bb)
+{
+ return poplsb(bb);
+}
+
+uint64_t tb_king_attacks(unsigned sq)
+{
+ return king_attacks(sq);
+}
+
+uint64_t tb_queen_attacks(unsigned sq, uint64_t occ)
+{
+ return queen_attacks(sq, occ);
+}
+
+uint64_t tb_rook_attacks(unsigned sq, uint64_t occ)
+{
+ return rook_attacks(sq, occ);
+}
+
+uint64_t tb_bishop_attacks(unsigned sq, uint64_t occ)
+{
+ return bishop_attacks(sq, occ);
+}
+
+uint64_t tb_knight_attacks(unsigned sq)
+{
+ return knight_attacks(sq);
+}
+
+uint64_t tb_pawn_attacks(unsigned sq, bool color)
+{
+ return pawn_attacks(sq, color);
+}
+
+#endif /* TB_NO_HELPER_API */
diff --git a/src/fathom/tbprobe.h b/src/fathom/tbprobe.h
new file mode 100644
index 0000000..82850e7
--- /dev/null
+++ b/src/fathom/tbprobe.h
@@ -0,0 +1,399 @@
+/*
+ * tbprobe.h
+ * (C) 2015 basil, all rights reserved,
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TBPROBE_H
+#define TBPROBE_H
+
+#include <tbconfig.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef TB_NO_STDINT
+#include <stdint.h>
+#else
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned uint32_t;
+typedef long long unsigned uint64_t;
+typedef char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+#endif
+
+#ifndef TB_NO_STDBOOL
+#include <stdbool.h>
+#else
+#ifndef __cplusplus
+typedef uint8_t bool;
+#define true 1
+#define false 0
+#endif
+#endif
+
+/*
+ * Internal definitions. Do not call these functions directly.
+ */
+extern bool tb_init_impl(const char *_path);
+extern unsigned tb_probe_wdl_impl(
+ uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _ep,
+ bool _turn);
+extern unsigned tb_probe_root_impl(
+ uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _rule50,
+ unsigned _ep,
+ bool _turn,
+ unsigned *_results);
+
+/****************************************************************************/
+/* MAIN API */
+/****************************************************************************/
+
+#define TB_MAX_MOVES (192+1)
+#define TB_MAX_CAPTURES 64
+#define TB_MAX_PLY 256
+#define TB_CASTLING_K 0x1 /* White king-side. */
+#define TB_CASTLING_Q 0x2 /* White queen-side. */
+#define TB_CASTLING_k 0x4 /* Black king-side. */
+#define TB_CASTLING_q 0x8 /* Black queen-side. */
+
+#define TB_LOSS 0 /* LOSS */
+#define TB_BLESSED_LOSS 1 /* LOSS but 50-move draw */
+#define TB_DRAW 2 /* DRAW */
+#define TB_CURSED_WIN 3 /* WIN but 50-move draw */
+#define TB_WIN 4 /* WIN */
+
+#define TB_PROMOTES_NONE 0
+#define TB_PROMOTES_QUEEN 1
+#define TB_PROMOTES_ROOK 2
+#define TB_PROMOTES_BISHOP 3
+#define TB_PROMOTES_KNIGHT 4
+
+#define TB_RESULT_WDL_MASK 0x0000000F
+#define TB_RESULT_TO_MASK 0x000003F0
+#define TB_RESULT_FROM_MASK 0x0000FC00
+#define TB_RESULT_PROMOTES_MASK 0x00070000
+#define TB_RESULT_EP_MASK 0x00080000
+#define TB_RESULT_DTZ_MASK 0xFFF00000
+#define TB_RESULT_WDL_SHIFT 0
+#define TB_RESULT_TO_SHIFT 4
+#define TB_RESULT_FROM_SHIFT 10
+#define TB_RESULT_PROMOTES_SHIFT 16
+#define TB_RESULT_EP_SHIFT 19
+#define TB_RESULT_DTZ_SHIFT 20
+
+#define TB_GET_WDL(_res) \
+ (((_res) & TB_RESULT_WDL_MASK) >> TB_RESULT_WDL_SHIFT)
+#define TB_GET_TO(_res) \
+ (((_res) & TB_RESULT_TO_MASK) >> TB_RESULT_TO_SHIFT)
+#define TB_GET_FROM(_res) \
+ (((_res) & TB_RESULT_FROM_MASK) >> TB_RESULT_FROM_SHIFT)
+#define TB_GET_PROMOTES(_res) \
+ (((_res) & TB_RESULT_PROMOTES_MASK) >> TB_RESULT_PROMOTES_SHIFT)
+#define TB_GET_EP(_res) \
+ (((_res) & TB_RESULT_EP_MASK) >> TB_RESULT_EP_SHIFT)
+#define TB_GET_DTZ(_res) \
+ (((_res) & TB_RESULT_DTZ_MASK) >> TB_RESULT_DTZ_SHIFT)
+
+#define TB_SET_WDL(_res, _wdl) \
+ (((_res) & ~TB_RESULT_WDL_MASK) | \
+ (((_wdl) << TB_RESULT_WDL_SHIFT) & TB_RESULT_WDL_MASK))
+#define TB_SET_TO(_res, _to) \
+ (((_res) & ~TB_RESULT_TO_MASK) | \
+ (((_to) << TB_RESULT_TO_SHIFT) & TB_RESULT_TO_MASK))
+#define TB_SET_FROM(_res, _from) \
+ (((_res) & ~TB_RESULT_FROM_MASK) | \
+ (((_from) << TB_RESULT_FROM_SHIFT) & TB_RESULT_FROM_MASK))
+#define TB_SET_PROMOTES(_res, _promotes) \
+ (((_res) & ~TB_RESULT_PROMOTES_MASK) | \
+ (((_promotes) << TB_RESULT_PROMOTES_SHIFT) & TB_RESULT_PROMOTES_MASK))
+#define TB_SET_EP(_res, _ep) \
+ (((_res) & ~TB_RESULT_EP_MASK) | \
+ (((_ep) << TB_RESULT_EP_SHIFT) & TB_RESULT_EP_MASK))
+#define TB_SET_DTZ(_res, _dtz) \
+ (((_res) & ~TB_RESULT_DTZ_MASK) | \
+ (((_dtz) << TB_RESULT_DTZ_SHIFT) & TB_RESULT_DTZ_MASK))
+
+#define TB_RESULT_CHECKMATE TB_SET_WDL(0, TB_WIN)
+#define TB_RESULT_STALEMATE TB_SET_WDL(0, TB_DRAW)
+#define TB_RESULT_FAILED 0xFFFFFFFF
+
+/*
+ * The tablebase can be probed for any position where #pieces <= TB_LARGEST.
+ */
+extern unsigned TB_LARGEST;
+
+/*
+ * Initialize the tablebase.
+ *
+ * PARAMETERS:
+ * - path:
+ * The tablebase PATH string.
+ *
+ * RETURN:
+ * - true=success, false=failed. The TB_LARGEST global will also be
+ * initialized. If no tablebase files are found, then `true' is returned
+ * and TB_LARGEST is set to zero.
+ */
+bool tb_init(const char *_path);
+
+/*
+ * Free any resources allocated by tb_init
+ */
+void tb_free(void);
+
+/*
+ * Probe the Win-Draw-Loss (WDL) table.
+ *
+ * PARAMETERS:
+ * - white, black, kings, queens, rooks, bishops, knights, pawns:
+ * The current position (bitboards).
+ * - rule50:
+ * The 50-move half-move clock.
+ * - castling:
+ * Castling rights. Set to zero if no castling is possible.
+ * - ep:
+ * The en passant square (if exists). Set to zero if there is no en passant
+ * square.
+ * - turn:
+ * true=white, false=black
+ *
+ * RETURN:
+ * - One of {TB_LOSS, TB_BLESSED_LOSS, TB_DRAW, TB_CURSED_WIN, TB_WIN}.
+ * Otherwise returns TB_RESULT_FAILED if the probe failed.
+ *
+ * NOTES:
+ * - Engines should use this function during search.
+ * - This function is thread safe assuming TB_NO_THREADS is disabled.
+ */
+static inline unsigned tb_probe_wdl(
+ uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _rule50,
+ unsigned _castling,
+ unsigned _ep,
+ bool _turn)
+{
+ if (_castling != 0)
+ return TB_RESULT_FAILED;
+ if (_rule50 != 0)
+ return TB_RESULT_FAILED;
+ return tb_probe_wdl_impl(_white, _black, _kings, _queens, _rooks,
+ _bishops, _knights, _pawns, _ep, _turn);
+}
+
+/*
+ * Probe the Distance-To-Zero (DTZ) table.
+ *
+ * PARAMETERS:
+ * - white, black, kings, queens, rooks, bishops, knights, pawns:
+ * The current position (bitboards).
+ * - rule50:
+ * The 50-move half-move clock.
+ * - castling:
+ * Castling rights. Set to zero if no castling is possible.
+ * - ep:
+ * The en passant square (if exists). Set to zero if there is no en passant
+ * square.
+ * - turn:
+ * true=white, false=black
+ * - results (OPTIONAL):
+ * Alternative results, one for each possible legal move. The passed array
+ * must be TB_MAX_MOVES in size.
+ * If alternative results are not desired then set results=NULL.
+ *
+ * RETURN:
+ * - A TB_RESULT value comprising:
+ * 1) The WDL value (TB_GET_WDL)
+ * 2) The suggested move (TB_GET_FROM, TB_GET_TO, TB_GET_PROMOTES, TB_GET_EP)
+ * 3) The DTZ value (TB_GET_DTZ)
+ * The suggested move is guaranteed to preserved the WDL value.
+ *
+ * Otherwise:
+ * 1) TB_RESULT_STALEMATE is returned if the position is in stalemate.
+ * 2) TB_RESULT_CHECKMATE is returned if the position is in checkmate.
+ * 3) TB_RESULT_FAILED is returned if the probe failed.
+ *
+ * If results!=NULL, then a TB_RESULT for each legal move will be generated
+ * and stored in the results array. The results array will be terminated
+ * by TB_RESULT_FAILED.
+ *
+ * NOTES:
+ * - Engines can use this function to probe at the root. This function should
+ * not be used during search.
+ * - DTZ tablebases can suggest unnatural moves, especially for losing
+ * positions. Engines may prefer to traditional search combined with WDL
+ * move filtering using the alternative results array.
+ * - This function is NOT thread safe. For engines this function should only
+ * be called once at the root per search.
+ */
+static inline unsigned tb_probe_root(
+ uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _rule50,
+ unsigned _castling,
+ unsigned _ep,
+ bool _turn,
+ unsigned *_results)
+{
+ if (_castling != 0)
+ return TB_RESULT_FAILED;
+ return tb_probe_root_impl(_white, _black, _kings, _queens, _rooks,
+ _bishops, _knights, _pawns, _rule50, _ep, _turn, _results);
+}
+
+typedef uint16_t TbMove;
+
+#define TB_MOVE_FROM(move) \
+ (((move) >> 6) & 0x3F)
+#define TB_MOVE_TO(move) \
+ ((move) & 0x3F)
+#define TB_MOVE_PROMOTES(move) \
+ (((move) >> 12) & 0x7)
+
+struct TbRootMove {
+ TbMove move;
+ TbMove pv[TB_MAX_PLY];
+ unsigned pvSize;
+ int32_t tbScore, tbRank;
+};
+
+struct TbRootMoves {
+ unsigned size;
+ struct TbRootMove moves[TB_MAX_MOVES];
+};
+
+/*
+ * Use the DTZ tables to rank and score all root moves.
+ * INPUT: as for tb_probe_root
+ * OUTPUT: TbRootMoves structure is filled in. This contains
+ * an array of TbRootMove structures.
+ * Each structure instance contains a rank, a score, and a
+ * predicted principal variation.
+ * RETURN VALUE:
+ * non-zero if ok, 0 means not all probes were successful
+ *
+ */
+int tb_probe_root_dtz(
+ uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _rule50,
+ unsigned _castling,
+ unsigned _ep,
+ bool _turn,
+ bool hasRepeated,
+ bool useRule50,
+ struct TbRootMoves *_results);
+
+/*
+// Use the WDL tables to rank and score all root moves.
+// This is a fallback for the case that some or all DTZ tables are missing.
+ * INPUT: as for tb_probe_root
+ * OUTPUT: TbRootMoves structure is filled in. This contains
+ * an array of TbRootMove structures.
+ * Each structure instance contains a rank, a score, and a
+ * predicted principal variation.
+ * RETURN VALUE:
+ * non-zero if ok, 0 means not all probes were successful
+ *
+ */
+int tb_probe_root_wdl(uint64_t _white,
+ uint64_t _black,
+ uint64_t _kings,
+ uint64_t _queens,
+ uint64_t _rooks,
+ uint64_t _bishops,
+ uint64_t _knights,
+ uint64_t _pawns,
+ unsigned _rule50,
+ unsigned _castling,
+ unsigned _ep,
+ bool _turn,
+ bool useRule50,
+ struct TbRootMoves *_results);
+
+/****************************************************************************/
+/* HELPER API */
+/****************************************************************************/
+
+/*
+ * The HELPER API provides some useful additional functions. It is optional
+ * and can be disabled by defining TB_NO_HELPER_API. Engines should disable
+ * the HELPER API.
+ */
+
+#ifndef TB_NO_HELPER_API
+
+extern unsigned tb_pop_count(uint64_t _bb);
+extern unsigned tb_lsb(uint64_t _bb);
+extern uint64_t tb_pop_lsb(uint64_t _bb);
+extern uint64_t tb_king_attacks(unsigned _square);
+extern uint64_t tb_queen_attacks(unsigned _square, uint64_t _occ);
+extern uint64_t tb_rook_attacks(unsigned _square, uint64_t _occ);
+extern uint64_t tb_bishop_attacks(unsigned _square, uint64_t _occ);
+extern uint64_t tb_knight_attacks(unsigned _square);
+extern uint64_t tb_pawn_attacks(unsigned _square, bool _color);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/main.c b/src/main.c
index 1247311..01c8d26 100755
--- a/src/main.c
+++ b/src/main.c
@@ -295,7 +295,7 @@ Return value:
g_Options.fNoInputThread = FALSE;
g_Options.fVerbosePosting = TRUE;
strcpy(g_Options.szEGTBPath, "/zscratch/egtb");
- strcpy(g_Options.szLogfile, "typhoon.log");
+ strcpy(g_Options.szLogfile, "/usr/local/tmp/typhoon.log");
strcpy(g_Options.szBookName, "book.bin");
g_Options.uNumHashTableEntries = 0x10000;
g_Options.uNumProcessors = 1;
@@ -356,9 +356,9 @@ Return value:
{
g_Options.fNoInputThread = TRUE;
}
- else if ((!STRCMPI(argv[i], "--dnafile")) && (argc > i))
+ else if ((!STRCMPI(argv[i], "--dnafile")) && (argc > i))
{
- if (!ReadEvalDNA(argv[i+1]))
+ if (!ReadEvalDNA(argv[i+1]))
{
UtilPanic(INITIALIZATION_FAILURE,
(void *)"Bad DNA file",
@@ -367,6 +367,10 @@ Return value:
NULL,
__FILE__, __LINE__);
}
+ else
+ {
+ Trace("Loaded dna file \"%s\"\n", argv[i+1]);
+ }
i++;
}
else if ((!STRCMPI(argv[i], "--logfile")) && (argc > i))
diff --git a/src/position.bin b/src/position.bin
deleted file mode 100644
index 4216042..0000000
--- a/src/position.bin
+++ /dev/null
Binary files differ
diff --git a/src/position.lrn b/src/position.lrn
deleted file mode 100644
index 6d40222..0000000
--- a/src/position.lrn
+++ /dev/null
@@ -1,5 +0,0 @@
-[White "Crafty 19.13"]
-[Black "unknown"]
-[Date "2007.06.19"]
-setboard r5k/1b1nq1bp/2p2rp/1p1p1pN/p2P3P/P2NP1P/1PQ2P1K/2R1RB/ w
-{-149 6623 660}
diff --git a/src/suite_diff.pl b/src/suite_diff.pl
index 6749f07..2ae8a19 100755
--- a/src/suite_diff.pl
+++ b/src/suite_diff.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
$verbose = 0;
for $arg (@ARGV) {
diff --git a/src/trial.ep_ b/src/trial.ep_
deleted file mode 100644
index a98e32f..0000000
--- a/src/trial.ep_
+++ /dev/null
@@ -1,3520 +0,0 @@
-st 20
-easy
-setboard 2q1r1k1/1ppb4/r2p1Pp1/p4n1p/2P1n3/5NPP/PP3Q1K/2BRRB2 w - -
-solution f7+
-id "ECM.001"
-go
-setboard 7r/1p2k3/2bpp3/p3np2/P1PR4/2N2PP1/1P4K1/3B4 b - -
-solution Bxf3+
-id "ECM.002"
-go
-setboard 4k3/p1P3p1/2q1np1p/3N4/8/1Q3PP1/6KP/8 w - -
-solution Qb5
-id "ECM.003"
-go
-setboard 2r1b1k1/R4pp1/4pb1p/1pBr4/1Pq2P2/3N4/2PQ2PP/5RK1 b - -
-solution Rcxc5
-id "ECM.004"
-go
-setboard 6k1/p1qb1p1p/1p3np1/2b2p2/2B5/2P3N1/PP2QPPP/4N1K1 b - -
-solution Bxf2+
-id "ECM.005"
-go
-setboard 3q4/pp3pkp/5npN/2bpr1B1/4r3/2P2Q2/PP3PPP/R4RK1 w - -
-solution Bxf6+
-id "ECM.006"
-go
-setboard 3rr1k1/pb3pp1/1p1q1b1p/1P2NQ2/3P4/P1NB4/3K1P1P/2R3R1 w - -
-solution Rxg7+
-id "ECM.007"
-go
-setboard r1b1r1k1/p1p3pp/2p2n2/2bp4/5P2/3BBQPq/PPPK3P/R4N1R b - -
-solution Bg4
-id "ECM.008"
-go
-setboard 3r4/1b2k3/1pq1pp2/p3n1pr/2P5/5PPN/PP1N1QP1/R2R2K1 b - -
-solution Rxh3
-id "ECM.009"
-go
-setboard 2r4k/pB4bp/6p1/6q1/1P1n4/2N5/P4PPP/2R1Q1K1 b - -
-solution Qxc1
-id "ECM.010"
-go
-setboard 1r5r/3b1pk1/3p1np1/p1qPp3/p1N1PbP1/2P2PN1/1PB1Q1K1/R3R3 b - -
-solution Nxg4
-id "ECM.011"
-go
-setboard 5rk1/7p/p1N5/3pNp2/2bPnqpQ/P7/1P3PPP/4R1K1 w - -
-solution Ne7+
-id "ECM.012"
-go
-setboard rnb2rk1/pp2np1p/2p2q1b/8/2BPPN2/2P2Q2/PP4PP/R1B2RK1 w - -
-solution Nd5
-id "ECM.013"
-go
-setboard 2k4r/1pp2ppp/p1p1bn2/4N3/1q1rP3/2N1Q3/PPP2PPP/R4RK1 w - -
-solution Nd5
-id "ECM.014"
-go
-setboard r3kb1r/pp2pppp/3q4/3Pn3/6b1/2N1BN2/PP3PPP/R2QKB1R w KQkq -
-solution Nxe5
-id "ECM.015"
-go
-setboard 2rr2k1/1b3p1p/p4qpb/2R1n3/3p4/BP2P3/P3QPPP/3R1BKN b - -
-solution Rxc5
-id "ECM.016"
-go
-setboard r1b1k3/5p1p/p1p5/3np3/1b2N3/4B3/PPP1BPrP/2KR3R w q -
-solution Rxd5
-id "ECM.017"
-go
-setboard r3rbk1/1pq2ppp/2ppbnn1/p3p3/P1PPN3/BP1BPN1P/2Q2PP1/R2R2K1 w - -
-solution Nxd6
-id "ECM.018"
-go
-setboard b7/2q2kp1/p3pbr1/1pPpP2Q/1P1N3P/6P1/P7/5RK1 w - -
-solution Rxf6+
-id "ECM.019"
-go
-setboard 1rr1nbk1/5ppp/3p4/1q1PpN2/np2P3/5Q1P/P1BB1PP1/2R1R1K1 w - -
-solution Bxa4
-id "ECM.020"
-go
-setboard r7/5kp1/2p1p2p/1p1n3P/2rP4/2P3R1/PK2RPP1/2B5 b - -
-solution Rxc3
-id "ECM.021"
-go
-setboard r1r3k1/p3qpp1/b1P4p/3p4/3Nn3/4P3/P1Q2PPP/1BR1K2R b K -
-solution Qb4+
-id "ECM.022"
-go
-setboard rn3rk1/4bppp/1q2p3/p2pP3/8/1PN2B1P/P4PP1/2RQ1RK1 w - -
-solution Bxd5
-id "ECM.023"
-go
-setboard 6rk/1p1br2p/pqp5/3pNP2/3Pp3/P5PR/5PKR/Q7 w - -
-solution Rxh7+
-id "ECM.024"
-go
-setboard 2b3k1/5p1p/7b/p2B3p/3P4/P2Q1N1P/1q3PP1/6K1 w - -
-solution Bxf7+
-id "ECM.025"
-go
-setboard r1b5/4k3/p7/3p1n2/3Bp3/2P2r1P/PPBK1P2/4R2R w - -
-solution Bc5+
-id "ECM.026"
-go
-setboard r4rk1/1b3Npp/p7/1p3Q2/3P4/1B2q3/P5PP/3n1R1K b - -
-solution Bxg2+
-id "ECM.027"
-go
-setboard r1b2rk1/2q2ppp/2pbp3/p7/4Nn2/3B4/PPPBQ1PP/R4R1K w - -
-solution Rxf4
-id "ECM.028"
-go
-setboard 3r2k1/1q1P1ppp/r2R2n1/p4Q2/1ppB2R1/6P1/PP3PP1/6K1 w - -
-solution Rgxg6
-id "ECM.029"
-go
-setboard r2q1rk1/p3b1pp/2p5/1pn5/1n1Bp1b1/1P6/PQ1PPP2/2RNKBNR b K -
-solution Bxe2
-id "ECM.030"
-go
-setboard 3r2k1/p2r1p1p/1p2p1p1/q4n2/3P4/PQ1R3P/1P2NPP1/3R2K1 b - -
-solution Nxd4
-id "ECM.031"
-go
-setboard 2bnr1k1/2q2ppp/p7/2p1b3/2N1B3/R7/1P2QPPP/2B3K1 w - -
-solution Nxe5
-id "ECM.032"
-go
-setboard r1b2r1k/3nN2p/p2Q1p2/8/4PP2/1R6/q1PK2PP/4R3 w - -
-solution Qd5
-id "ECM.033"
-go
-setboard 1nk1r1r1/pp2n1pp/4p3/q2pPp1N/b1pP1P2/B1P2R2/2P1B1PP/R2Q2K1 w - -
-solution Nf6
-id "ECM.034"
-go
-setboard 2r2bk1/4qp2/3n2p1/2R1p1Np/2p1N3/r6P/1Q3PP1/3R2K1 w - -
-solution Rxc8
-id "ECM.035"
-go
-setboard br1r2k1/1q4p1/p2ppb1p/2p2p2/2P1n3/Pn2P2P/QPR2PPB/2NRNBK1 b - -
-solution Nxc1
-id "ECM.036"
-go
-setboard 2k4r/ppp1n1p1/2n2qb1/2N5/Q1P3p1/P2r3P/1P3PB1/R1B2RK1 w - -
-solution Qb5
-id "ECM.037"
-go
-setboard 8/6bk/1B1R4/6p1/2bNP3/4KP2/1r6/8 b - -
-solution Be5
-id "ECM.038"
-go
-setboard r1b1rnk1/1p3pb1/1qpp2p1/2n5/2PNP2p/1PN3PP/3R1PBK/BR1Q4 b - -
-solution Rxa1
-id "ECM.039"
-go
-setboard r1b2rk1/pp2b3/2pn1n1p/3pNppq/3P4/BP1N2P1/P3PPBP/R1Q2RK1 w - -
-solution Nxc6
-id "ECM.040"
-go
-setboard 5rk1/1b3ppp/p3p3/1p1q2N1/4n3/6P1/PP2PPBP/2Q2RK1 b - -
-solution Nxg3
-id "ECM.041"
-go
-setboard 2kr3r/pppq2p1/1bn1R3/6N1/1P6/1QN1B1p1/P4PP1/R5K1 b - -
-solution gxf2+
-id "ECM.042"
-go
-setboard 2rr4/5pk1/p1q3p1/3bpP1p/1p4nR/1N4Q1/PPP3PP/3NR2K b - -
-solution Bxg2+
-id "ECM.043"
-go
-setboard r4rk1/pp4pp/2nqb3/3p4/8/2NB4/PP1Q1PPP/4RRK1 w - -
-solution Bxh7+
-id "ECM.044"
-go
-setboard 3rk1r1/3b1p1p/p2BpQ2/8/2q5/2P5/PP3PPP/3R2K1 b - -
-solution Rxg2+
-id "ECM.045"
-go
-setboard 3r1rk1/4pp1p/p1Q1b1p1/3N4/3b4/5B2/Pq3PPP/R4RK1 b - -
-solution Bxd5
-id "ECM.046"
-go
-setboard 5bk1/1bqn1r1p/p3Q1p1/4p3/1PN1Pp2/P1N4P/5PP1/R1BR2K1 w - -
-solution Qxf7+
-id "ECM.047"
-go
-setboard 3rkb1r/1p3p2/p1n1p3/q5pp/2PpP3/1P4P1/P1Q1BPKP/R2N3R b k -
-solution d3
-id "ECM.048"
-go
-setboard 5rk1/1r1qbnnp/R2p2p1/1p1Pp3/1Pp1P1N1/2P1B1NP/5QP1/5R1K w - -
-solution Qxf7+
-id "ECM.049"
-go
-setboard 2kr1b1R/1b3pp1/p2pp3/1pq3P1/2nQPP2/P1N5/1PP1BB2/1K6 w - -
-solution Rxf8
-id "ECM.050"
-go
-setboard 1k1r1b1r/p1p1q3/2p1p3/4Ppp1/4nP2/P2BQ3/1PP3PB/2KR3R b - -
-solution Rxh2
-id "ECM.051"
-go
-setboard r3nb1Q/p1q2kr1/2p3p1/2ppnpP1/1P3N2/4P3/PB1P4/1R2KB1R w K -
-solution Qxf8+
-id "ECM.052"
-go
-setboard r1bq1rk1/pp3pbp/2pp1np1/2n3B1/2PNP3/2N2P2/PP1QB1PP/R4RK1 b - -
-solution Nfxe4
-id "ECM.053"
-go
-setboard 1rb1qn2/1p2nrbk/p2p2p1/P2Pp1Pp/NP2P2P/2RNB3/2QKB3/1R6 w - -
-solution Ba7
-id "ECM.054"
-go
-setboard 5r2/1b2k2p/3bp3/5PP1/Bn1Q3P/1N6/1Pr5/1K3R2 b - -
-solution Rxb2+
-id "ECM.055"
-go
-setboard r1b1r1k1/pp4bp/5np1/2qPB3/8/6NP/PPP1Q1B1/R4R1K w - -
-solution Rxf6
-id "ECM.056"
-go
-setboard r1b2r1k/1pq3bp/8/3Qp2n/1P1n1pp1/2NP2P1/3BPPBP/1R2NRK1 b - -
-solution Qxc3
-id "ECM.057"
-go
-setboard 4qk2/pp3pp1/1nbr3p/2p5/5N2/2P1Q3/PPB2PPP/2K1R3 w - -
-solution Ng6+
-id "ECM.058"
-go
-setboard 3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - -
-solution Rd5
-id "ECM.059"
-go
-setboard r4rk1/pp1b2pp/3bpq2/3p1p2/2PPn3/PP1B4/1BQN1PPP/R4RK1 b - -
-solution Bxh2+
-id "ECM.060"
-go
-setboard r4rk1/1b3ppp/p2q1n2/1p2N3/3P4/1B6/P1Q2PPP/2R1R1K1 w - -
-solution Nxf7
-id "ECM.061"
-go
-setboard 2rq1r2/pp3pnk/2n1b1pp/3pQ3/3P1N2/P1N5/1P3PPP/1BR2RK1 w - -
-solution Bxg6+
-id "ECM.062"
-go
-setboard 4nk2/r1r1bppp/pN2p3/2np4/8/BPN3PP/P3PPK1/2RR4 w - -
-solution Ncxd5
-id "ECM.063"
-go
-setboard r4r1k/2pqn1b1/p1bp2pp/1p2pn2/4N3/2PP1PPQ/PPB4P/R1B1RNK1 b - -
-solution Nd4
-id "ECM.064"
-go
-setboard r1bQ1nk1/bp3ppp/p7/3B4/1P6/P3P1P1/2P4P/q1B2RK1 b - -
-solution Bxe3+
-id "ECM.065"
-go
-setboard 3r1rk1/1b2bppp/2q1pn2/pp4Q1/3B1P2/PBN5/1PP3PP/R2R3K b - -
-solution Rxd4
-id "ECM.066"
-go
-setboard 2nq2k1/2r3pp/p1p1rp2/PpQ1N3/1P1PR3/8/5PPP/2R3K1 w - -
-solution Nf7
-id "ECM.067"
-go
-setboard r1b2rk1/1p2bppp/p3pn2/4B3/1qBR4/2N5/P3QPPP/R5K1 w - -
-solution Bd3
-id "ECM.068"
-go
-setboard 3r4/p2nrpkp/2B1p3/2P2pP1/3R3Q/q7/6PP/6RK w - -
-solution g6
-id "ECM.069"
-go
-setboard 5r1k/p6p/1p1p1qp1/2pQpr2/8/2PP2P1/PP2RPKP/5R2 b - -
-solution e4
-id "ECM.070"
-go
-setboard b1n1r1k1/2q2p1p/p4Pp1/1pBP4/4B1P1/2P1Q3/P4K1P/4R3 w - -
-solution Qh6
-id "ECM.071"
-go
-setboard 2r2rk1/5pbp/p5p1/3P2q1/1QbN4/5P2/P4BPP/2RR2K1 b - -
-solution Bf1
-id "ECM.072"
-go
-setboard r1bqnrk1/pp2ppb1/1np3pp/4P1N1/5P2/2NBB3/PPP3PP/R2Q1RK1 w - -
-solution Nh7
-id "ECM.073"
-go
-setboard 3nk3/3q1p2/1B3pr1/4p3/bP2P2p/r2B4/2Q2RPP/3R2K1 w - -
-solution Bb5
-id "ECM.074"
-go
-setboard 3rnr1k/pp3ppp/4b3/2p1qNP1/P2pPR2/1P1P2Q1/2P3BP/5RK1 w - -
-solution Nh6
-id "ECM.075"
-go
-setboard r1b2kr1/1p1p1pNp/p1n1p1p1/5P2/3QP3/2N5/PqP1B1PP/R4RK1 w - -
-solution fxg6
-id "ECM.076"
-go
-setboard 5rk1/3r1p1p/3b2pQ/8/4q3/4B2P/3R1PP1/4R1K1 w - -
-solution Rxd6
-id "ECM.077"
-go
-setboard 4rrk1/1bp2ppp/p1q2b1B/1pn2B2/4N1Q1/2P4P/PP3PP1/3RR1K1 w - -
-solution Nxc5
-id "ECM.078"
-go
-setboard 2rnrbnk/3q1ppp/p1p5/3p1P2/1p1PPN2/4BQ1R/PP1N2PP/3R2K1 w - -
-solution Ng6+
-id "ECM.079"
-go
-setboard 5r1k/pb2r1bp/1p2B1p1/n7/4qNQ1/4B3/P4PPP/2RR2K1 w - -
-solution Rd4
-id "ECM.080"
-go
-setboard Q7/p1r1ppk1/1qP4p/2Rb2p1/8/3N2P1/4PP1P/6K1 b - -
-solution Qb1+
-id "ECM.081"
-go
-setboard 1r3rk1/5pp1/1n2qn1p/1p1pPNb1/2pP2QP/2P5/1PB3P1/R1B1R1K1 w - -
-solution exf6
-id "ECM.082"
-go
-setboard r2qr1k1/pp3pbp/3p1np1/2pP1bB1/2P1N3/3Q1PN1/PP4PP/R4RK1 b - -
-solution Nxe4
-id "ECM.083"
-go
-setboard 4r1k1/1b4pp/p7/1prP3q/2P1B3/5P2/P3Q2P/3RR2K w - -
-solution Bg6
-id "ECM.084"
-go
-setboard r1br2k1/ppb1qpp1/2P4p/2n1p3/4B3/P1N2N2/1P3PPP/2RQ1RK1 w - -
-solution Nd5
-id "ECM.085"
-go
-setboard 2r3k1/1nqbrp2/p5pp/1p1Pp1N1/8/1P5P/P1B2PP1/2RQR1K1 w - -
-solution Nxf7
-id "ECM.086"
-go
-setboard 2r1rbk1/1b3ppp/pp6/2q1pNP1/Pn1RP3/2N5/1PP2QBP/5R1K w - -
-solution Nh6+
-id "ECM.087"
-go
-setboard r1b1rk2/3n1pbQ/2qp2p1/p2N2P1/2Bp3N/4P3/PP3PP1/2KR3R w - -
-solution Nxg6+
-id "ECM.088"
-go
-setboard r1r2qkb/4pp1p/pBbp3P/3Nn1P1/4Q3/1B6/PPP5/1K1R2R1 w - -
-solution g6
-id "ECM.089"
-go
-setboard r4k2/q4npp/P2P4/2p1R3/2N5/6PP/Q5K1/8 w - -
-solution Re7
-id "ECM.090"
-go
-setboard rn1q1r2/4bpk1/p3p3/1pN1N1np/2pP4/4PpBb/PPQ4P/1B1RK1R1 w - -
-solution Nc6
-id "ECM.091"
-go
-setboard 5rk1/6pp/8/2Q4q/N2pP3/4b1Pb/4PP1K/1R3R2 b - -
-solution Bxf1+
-id "ECM.092"
-go
-setboard 2r4k/pp2Q1pp/5r2/P2P4/3Pb1P1/4Ppq1/1P1R3N/3R3K b - -
-solution Qe1+
-id "ECM.093"
-go
-setboard 1r1rb1k1/2p3pp/p2q1p2/3PpP1Q/Pp1bP2N/1B5R/1P4PP/2B4K w - -
-solution Qxh7+
-id "ECM.094"
-go
-setboard r1b4k/p2n1Bpp/1p1Q1n2/5p2/3P4/P3BqP1/1P3P1P/R4RK1 b - -
-solution Bb7
-id "ECM.095"
-go
-setboard rn1r2k1/p4ppp/2p3b1/3PQ3/1B2Np1q/1B3P2/P1P3PP/4R1K1 w - -
-solution Nf6+
-solution Qe8+
-id "ECM.096"
-go
-setboard 4r2k/5R1p/pp1Bq1pN/2p1P3/1n1b3Q/3P4/1P4KP/8 w - -
-solution Rxh7+
-id "ECM.097"
-go
-setboard r2nk1r1/pb3q1p/4p3/3p2pQ/8/BP6/P4PPP/2R1R1K1 w q -
-solution Rc7
-id "ECM.098"
-go
-setboard 6k1/1pqb1p2/5bpB/r2n4/4N1P1/1P3P2/1P1Q4/1K5R w - -
-solution Qxd5
-id "ECM.099"
-go
-setboard rr4k1/2p1ppb1/3pbnpp/q1pP4/4P3/1PNNBP1P/P1KR2P1/2Q4R b - -
-solution Qxc3+
-id "ECM.100"
-go
-setboard 1r3rk1/3Q2pp/p3p3/6B1/3np3/6R1/PqP1B2P/3K2R1 w - -
-solution Qxg7+
-id "ECM.101"
-go
-setboard 2r5/p4Q2/k1bBp3/4P3/p1nq4/5B2/2Pr2P1/1R1RK3 w - -
-solution Qb7+
-id "ECM.102"
-go
-setboard 5rk1/p1pb2pp/2p5/3p3q/2P3n1/1Q4BN/PP1Np1KP/R3R3 b - -
-solution Qxh3+
-id "ECM.103"
-go
-setboard 2r1nk2/4qpbQ/4b3/1p2RpP1/4P3/p7/PBP5/1K5R w - -
-solution Qxg7+
-id "ECM.104"
-go
-setboard 2kr4/1bpr3p/4R3/1pQ5/8/6B1/3q2PP/2R4K w - -
-solution Qxc7+
-id "ECM.105"
-go
-setboard r4rk1/1pbb2pp/p1p1p2q/2Pp4/1P1Pn3/P3B2P/2Q1BPP1/R4RNK b - -
-solution Qxe3
-id "ECM.106"
-go
-setboard r1k4r/ppp1b3/5Npp/4pb1Q/8/1B2B3/PqP2PPP/2RR2K1 w - -
-solution Qxf5+
-id "ECM.107"
-go
-setboard 6r1/p4rkp/3RQ1n1/1pp1p1B1/2p1P3/2P3R1/P4qPK/8 w - -
-solution Qxe5+
-id "ECM.108"
-go
-setboard 2kr1r2/1pp3pp/1n2p1b1/pN2B3/P1q5/1Q1p3P/5PP1/R4R1K w - -
-solution Rac1
-id "ECM.109"
-go
-setboard 2kr1bnr/1ppq4/p3bp2/6pp/4p3/2N2NBP/PP3PP1/2RQ1RK1 w - -
-solution Na4
-id "ECM.110"
-go
-setboard r2q2rk/p3bp1p/4b1p1/3pP2R/1p1B4/3BQ3/PPP3PP/5R1K w - -
-solution Rxf7
-id "ECM.111"
-go
-setboard r1b1Q3/6pk/p6p/1pq1n3/4N3/8/PPP3PP/R6K b - -
-solution Qc6
-id "ECM.112"
-go
-setboard q6r/pp3pkp/5np1/4Q3/4P3/6N1/P4PPP/5RK1 w - -
-solution Nh5+
-id "ECM.113"
-go
-setboard r1b1rk2/pp3ppQ/1np5/4q3/2B4N/4P3/PP3PP1/2R2K1R w - -
-solution Qg8+
-id "ECM.114"
-go
-setboard r1bn1rk1/pp3p1p/6p1/2bR2N1/2B2B2/q1P1P3/2Q2PPP/4K2R w K -
-solution Nxh7
-id "ECM.115"
-go
-setboard r3r1k1/p2N1pp1/1pn1p3/q1n5/2PQ4/P3B3/4PPKP/R5R1 w - -
-solution Nf6+
-id "ECM.116"
-go
-setboard 4qbk1/1R5n/p2pr1p1/2pQpNPp/P1P1P3/2P2P2/3B4/5K2 w - -
-solution Ne7+
-id "ECM.117"
-go
-setboard 3qr1k1/1p1bppbp/p2p2p1/2rPn3/P2N4/4BP2/1PPQ2PP/R2R1BK1 w - -
-solution Ne6
-id "ECM.118"
-go
-setboard 2b2r2/1p2q1k1/r3pppp/4n2P/p3N3/1B4Q1/PPP3P1/3R1R1K w - -
-solution Rxf6
-id "ECM.119"
-go
-setboard 8/R5p1/6k1/pr2p1b1/4K3/7P/5P2/6R1 w - -
-solution h4
-id "ECM.120"
-go
-setboard 5rk1/1b1r1p2/p1q1pQp1/1p2P2p/8/1BP1NR2/PP1n2PP/5R1K w - -
-solution Bxe6
-id "ECM.121"
-go
-setboard 6k1/p1p2r2/1p1p1P1Q/3P4/2P5/5qr1/PP4RP/6RK w - -
-solution Qh3
-id "ECM.122"
-go
-setboard 2b1rr1k/1p5p/1Ppp2q1/p3bN2/2P1n3/5R2/PBQ3BP/3R2K1 w - -
-solution Nxd6
-id "ECM.123"
-go
-setboard 3b2rk/7p/p7/2pbqNrn/Pp1p1R2/1P1Q2P1/1BPN1R1P/6K1 w - -
-solution Rxd4
-id "ECM.124"
-go
-setboard 1rbr2k1/1pq1bp1p/p1pNn1p1/2n1p3/2B1P2P/1NQ1BP2/PP4P1/1K1R3R w - -
-solution Nxf7
-id "ECM.125"
-go
-setboard r4rk1/1pp1b1pp/p1q5/3pPp2/3Pn3/P3N3/1P3PPP/R1BQR1K1 w - -
-solution Qb3
-id "ECM.126"
-go
-setboard rbbq1rk1/p3nppp/1p2p3/8/1B1pN3/P2B4/1P3PPP/2RQ1RK1 w - -
-solution Nf6+
-id "ECM.127"
-go
-setboard rn2qbr1/2p4k/p2p1nb1/1p1Pp2p/2P4P/2NBBPN1/PP1Q4/2KR2R1 w - -
-solution Nxh5
-id "ECM.128"
-go
-setboard 5r1k/1p2qp1p/p4R1Q/P1p5/2Prp3/7P/1P4P1/5R1K w - -
-solution Re6
-id "ECM.129"
-go
-setboard r1bq1rk1/pp2bp1p/2p2np1/3p2B1/3P4/2NQ2N1/PPP2PPP/4RRK1 w - -
-solution Rxe7
-id "ECM.130"
-go
-setboard 2rq1rk1/pp2bppp/1npp1n2/3PpN1b/2P5/2N3PP/PP2PPB1/R1BQ1RK1 w - -
-solution c5
-id "ECM.131"
-go
-setboard rnbq1rk1/pp2b1pp/5n2/2pPp3/2P1N3/3B1N2/PP4PP/R1BQK2R w KQ -
-solution d6
-id "ECM.132"
-go
-setboard 2n1rbk1/5pp1/7p/qP1pp3/4b1Q1/1B5P/1P1N1PP1/2B1R1K1 w - -
-solution Rxe4
-id "ECM.133"
-go
-setboard 4k3/2R2p2/5p1p/8/rb6/1N6/5PPP/5K2 w - -
-solution Rc4
-id "ECM.134"
-go
-setboard 2k3r1/pp2rp2/1np5/2Np1p2/P2P3p/1R2P1Pq/2Q2P1P/1R4K1 w - -
-solution Nxb7
-id "ECM.135"
-go
-setboard 2r1k3/p3nrR1/1p1p4/2p1p1p1/2P1B3/2PP1P2/P5K1/7R w - -
-solution Rh8+
-id "ECM.136"
-go
-setboard 8/1Qp3pk/7p/5p2/5Pqn/1P1r4/P5PP/2B2RK1 b - -
-solution c6
-id "ECM.137"
-go
-setboard 2rr1bk1/5p1p/pPN2np1/3Bp3/2Q1n3/1P2B1Pq/P3PP2/R2R2K1 b - -
-solution Rxd5
-id "ECM.138"
-go
-setboard 3r2k1/1p4pp/p1q1p3/3p1B2/bP1B2P1/P4Q2/5PKP/2b2R2 w - -
-solution Rxc1
-id "ECM.139"
-go
-setboard rnb1r1k1/pp5p/2pp2p1/4b3/2P1P2q/1NN1BPp1/PP1QB1P1/3RR1K1 b - -
-solution Bf4
-id "ECM.140"
-go
-setboard 5n1r/1p2kp2/rB1Nb3/4p1Pp/4p2P/1PP5/8/1K1R1R2 w - -
-solution Rxf7+
-id "ECM.141"
-go
-setboard b3r3/q2B2k1/3Q2p1/1p5p/3pP3/5P2/1p4PP/5RK1 b - -
-solution d3+
-id "ECM.142"
-go
-setboard 4r1k1/3R1ppp/p2p4/5PP1/2q2P2/2n2B2/P1P3QP/1r3R1K w - -
-solution Rxb1
-id "ECM.143"
-go
-setboard 2r3k1/pp2n3/6pQ/4q3/8/2P1p1P1/P5BP/3R2K1 w - -
-solution Bd5+
-id "ECM.144"
-go
-setboard 6k1/4ppbp/p5p1/1B1Q4/2P2Pn1/8/qr4PP/2B2RK1 b - -
-solution Bd4+
-id "ECM.145"
-go
-setboard 8/p3q1kp/1p2Pnp1/3pQ3/2pP4/1nP3N1/1B4PP/6K1 w - -
-solution Ba3
-id "ECM.146"
-go
-setboard r2b1rk1/5qp1/2p2P2/2p3Pp/p6P/2Q5/PPP5/2KR2R1 w - -
-solution g6
-id "ECM.147"
-go
-setboard 5r2/1b3pk1/pqrpp1p1/4n1Nn/1p2PP1P/8/PPPQB3/1NKR2R1 b - -
-solution Rfc8
-id "ECM.148"
-go
-setboard 1r2k2r/p5bp/4p1p1/q2pn3/1p2N1P1/6QP/PPP5/1KBR3R w k -
-solution Bh6
-id "ECM.149"
-go
-setboard rn1q1rk1/pp3p1p/2p5/3p4/5Q1P/2NP3R/PPP3P1/4RK2 w - -
-solution Rg3+
-id "ECM.150"
-go
-setboard 7r/kppQP1pp/p7/2qp1R2/4n3/1P2b2P/P1P3PK/R7 b - -
-solution Re8
-id "ECM.151"
-go
-setboard r1b1kb1Q/qp2pp2/p3n1p1/2nN2Pp/2B4P/7N/PPP5/2KRR3 w q -
-solution Nc7+
-id "ECM.152"
-go
-setboard 8/1bq3kp/p5p1/1pb1p3/4P2P/2PQ2P1/1P5B/5N1K b - -
-solution Qd8
-id "ECM.153"
-go
-setboard 2r1q1r1/6bk/p2pN1pp/1p1N4/4P3/3R3Q/PnP4P/1K4R1 w - -
-solution Nf6+
-id "ECM.154"
-go
-setboard 4r3/Q2bppkp/3p2p1/3Nn3/4P3/6PP/1qr2PB1/R3R1K1 b - -
-solution Ra8
-id "ECM.155"
-go
-setboard 6k1/p1q2pp1/2n2b2/3B2Pp/2P2P2/5N1P/Pr1Q2K1/4R3 w - -
-solution Re8+
-id "ECM.156"
-go
-setboard r1r3k1/p4n2/3p4/5NpR/8/2q2P2/P1PQ4/2K4R w - -
-solution Rh8+
-id "ECM.157"
-go
-setboard 8/p5Q1/2ppq2p/3n1ppk/3B4/2P2P1P/P5P1/6K1 w - -
-solution g4+
-id "ECM.158"
-go
-setboard r1r3k1/1p1b1nq1/6p1/pN1p4/P2Np2R/1P2P3/1Q3PP1/1K5R w - -
-solution Nd6
-id "ECM.159"
-go
-setboard 1r2k2r/3q2pp/p3pp2/P7/2P1Q3/8/1nB3PP/1R3R1K w k -
-solution Ba4
-id "ECM.160"
-go
-setboard r1bq3k/ppp2Qp1/2n1p2p/6N1/2BPN3/2P1n3/PP4PP/R5K1 w - -
-solution Nf6
-id "ECM.161"
-go
-setboard 3R4/1p2kp2/p1b1nN2/6p1/8/6BP/2r1qPPK/Q7 w - -
-solution Rd7+
-id "ECM.162"
-go
-setboard 6k1/p5p1/1p1p1nN1/1B1P4/4PK2/8/2r3b1/7R w - -
-solution Rh8+
-id "ECM.163"
-go
-setboard 8/5P2/4K1kP/4R3/8/8/8/5r2 w - -
-solution Rg5+
-id "ECM.164"
-go
-setboard 3r1rk1/p1p1qp1p/2p1b1p1/8/P2PRP2/2P1NQ2/6PP/R5K1 w - -
-solution f5
-id "ECM.165"
-go
-setboard 6k1/pr3ppp/1p3qn1/5NQ1/2p5/8/P4PPP/4R1K1 w - -
-solution Re8+
-id "ECM.166"
-go
-setboard Q7/1pq2kpp/4bp2/3r4/2B5/P3P3/1r3PPP/2R1K2R b K -
-solution Rd1+
-id "ECM.167"
-go
-setboard 4r1k1/p4ppp/4q2r/1Q6/4p3/4P1P1/P4P1P/2RR2K1 w - -
-solution Rd6
-id "ECM.168"
-go
-setboard 8/5p1k/4p1p1/3p2K1/3P1Q1P/P4P2/7q/8 b - -
-solution f6+
-id "ECM.169"
-go
-setboard r4r2/6k1/3p4/2pPp2p/4Pqp1/3P1P2/1R2Q1KP/5R2 b - -
-solution Ra1
-id "ECM.170"
-go
-setboard 4r1k1/1np1r1pp/1ppp1q2/6N1/1P3P2/4RQP1/7P/4R1K1 w - -
-solution Qh5
-id "ECM.171"
-go
-setboard r4rk1/pp3p1p/3pq1p1/2nNp3/3R1P2/7Q/PP4PP/5RK1 w - -
-solution f5
-id "ECM.172"
-go
-setboard 3qn2k/1p3Bp1/rbn4p/2p5/p1P2p2/P2b2PP/1BQNRP2/1R4K1 w - -
-solution Qxd3
-id "ECM.173"
-go
-setboard 3r1rk1/1pp4p/1q3bp1/p3p3/P2n1P2/2BB3P/1PP2QP1/R4RK1 b - -
-solution Bh4
-id "ECM.174"
-go
-setboard 4rrk1/2p2ppp/p2b4/1p1P4/3P2nq/2P4P/PPQ1RPP1/RNB3K1 b - -
-solution Qxf2+
-id "ECM.175"
-go
-setboard 1q6/2rk1p2/p1n1b1rN/3p2p1/8/3Q4/PP1B1PPP/2R1R1K1 w - -
-solution Nxf7
-id "ECM.176"
-go
-setboard r3kb1r/2q2p2/3p4/ppp1n1B1/P6P/1B3pQ1/1PP3b1/2KRR3 w kq -
-solution Bd5
-id "ECM.177"
-go
-setboard r1b2rk1/1p4pp/p1n3q1/4ppN1/7Q/2P1B3/P1P2PPP/R2R2K1 w - -
-solution Rd6
-id "ECM.178"
-go
-setboard 1rb2r2/1pR1N2p/p2R2pk/5p2/4pP2/1P1nP3/P4P1P/5BK1 w - -
-solution Rf6
-id "ECM.179"
-go
-setboard r1b3k1/ppp2r2/6p1/3n3p/6qP/3BQ3/PBP5/2KR3R w - -
-solution Bd4
-id "ECM.180"
-go
-setboard 3r2k1/p2q1r1p/1p1N2p1/1PpP4/3b1Bn1/1Q4Pb/1P2RP1P/R5KB b - -
-solution Qxd6
-id "ECM.181"
-go
-setboard 4r1k1/1pbb3p/2pp2q1/p1n5/2P2R2/1PN1n1P1/PB2Q1B1/5RK1 w - -
-solution Qxe3
-id "ECM.182"
-go
-setboard 3r2k1/p2r1p1p/1pR1p1qP/3P1pP1/3R4/1P2Q3/P4K2/8 w - -
-solution dxe6
-id "ECM.183"
-go
-setboard 3r3k/p1Q3bp/2p3p1/8/2P1BRn1/1P4Pb/P1N1q2P/6BK b - -
-solution Nf2+
-id "ECM.184"
-go
-setboard r4k2/p1pr1ppp/2q5/3PR2P/3Q4/8/6P1/5RK1 w - -
-solution Re7
-id "ECM.185"
-go
-setboard 1R3b2/3r3k/2p1bp1p/r1q1pNpQ/2PpP2P/6B1/P4PP1/1R4K1 w - -
-solution Nxh6
-id "ECM.186"
-go
-setboard r1b4r/pp2ppk1/2np1np1/3N3p/2B1P3/q3BP2/P1PQ2PP/1R3RK1 w - -
-solution Nxe7
-id "ECM.187"
-go
-setboard r3k2r/pb1n1pbp/4p1p1/q1n1P3/Bp1N1N2/4B3/PP3PPP/R2Q1RK1 w kq -
-solution Ndxe6
-id "ECM.188"
-go
-setboard 5rk1/Q2nqppp/5n2/2p5/8/1B2PP1P/Pr1B1P2/R3K2R b KQ -
-solution Ne4
-id "ECM.189"
-go
-setboard 5rk1/5pbp/b5p1/p1nNN3/1p2n3/1P4PP/P4PB1/2BR2K1 w - -
-solution Nd7
-id "ECM.190"
-go
-setboard 2k1r1r1/ppb2p2/6b1/2qP4/2P2P2/4pP1p/P3Q2P/2RBRN1K b - -
-solution Bd3
-id "ECM.191"
-go
-setboard 5r1k/pp1n1p1p/1b1qpP2/8/1PrN4/P1N1Q1P1/7P/3R1R1K w - -
-solution Qh6
-id "ECM.192"
-go
-setboard r2r1bk1/3qp2p/3pp1p1/p2n2N1/2N3Q1/BP4P1/P4PP1/2R3K1 w - -
-solution Nb6
-id "ECM.193"
-go
-setboard 1r3rk1/p4pbp/q1p2pp1/3p1b2/1n1P1P1B/PB3N2/1PPQR1PP/2KR4 b - -
-solution Bxc2
-id "ECM.194"
-go
-setboard 1rbr2k1/4qp2/p1n2bpp/1pp1p1N1/4P3/2P1BQ1P/PPB2PP1/3RR1K1 w - -
-solution Bxc5
-id "ECM.195"
-go
-setboard 2r2rk1/1p1q1ppp/1p3n2/3p1N2/4n3/1N3Q2/PPP2PPP/R2R2K1 w - -
-solution Rxd5
-id "ECM.196"
-go
-setboard rn3rk1/pp2ppbp/6p1/2R3N1/2B3b1/q3B3/P1P1Q1PP/5RK1 w - -
-solution Rxf7
-id "ECM.197"
-go
-setboard r1k3r1/pppnb1p1/4N3/3QP2p/3P3q/4B3/PPP2P2/R3KB2 w Q -
-solution Ba6
-id "ECM.198"
-go
-setboard r1nqr2k/1p1b1Q1p/p5p1/P1pPb3/5B2/2N5/BP4PP/R4RK1 w - -
-solution Qf8+
-id "ECM.199"
-go
-setboard 8/k3r1b1/Pp2rpp1/1qpQ4/4nB2/2P2NP1/7P/R4RK1 w - -
-solution Bb8+
-id "ECM.200"
-go
-setboard 1k1r4/ppq2p2/8/2pPb1r1/2P1Q1B1/6P1/PP3PK1/R4R2 b - -
-solution f5
-id "ECM.201"
-go
-setboard r1b2nk1/2qn1p1p/1ppR2p1/8/1PP1NP2/4r1PP/1Q2N1B1/3R2K1 w - -
-solution b5
-id "ECM.202"
-go
-setboard 8/5pk1/3q2p1/8/7P/5Q1K/6B1/6b1 b - -
-solution Qh2+
-id "ECM.203"
-go
-setboard 6r1/ppp4k/3p2rp/3Pb3/PPP1Np1q/5P1b/3QRRBP/6K1 b - -
-solution Bd4
-id "ECM.204"
-go
-setboard 4br1k/pR4bp/2r1B1pN/4npB1/3p4/P7/5PPP/4R1K1 w - -
-solution Rxg7
-id "ECM.205"
-go
-setboard r1bq1rk1/pppn2bp/3p2p1/3N1p2/8/BP1BRQ1P/P1PP1PP1/4R1K1 w - -
-solution Nxc7
-id "ECM.206"
-go
-setboard r6r/1p2kp2/3p1b2/pPpPpQ1P/1nP1P2P/6R1/1P2K3/1B6 w - -
-solution Rg6
-id "ECM.207"
-go
-setboard 2q1r1k1/1b3pbp/3p2p1/1Ppn3n/5P2/5B2/1P1B2PP/R2NNQ1K b - -
-solution Ndxf4
-id "ECM.208"
-go
-setboard 2r1r1k1/pp3pp1/3p3B/P2P1P2/2nb4/7R/1q3PQP/1B3R1K w - -
-solution Rb3
-id "ECM.209"
-go
-setboard r2qr1n1/p4pk1/1p1p2p1/4p3/4PQ2/1PN2P2/1PP3P1/2KR3R w - -
-solution Rh7+
-id "ECM.210"
-go
-setboard r4rk1/ppp3b1/3p1qp1/3Pp3/2P1Bn2/4BP2/PP1Q4/2K3RR w - -
-solution Rxg6
-id "ECM.211"
-go
-setboard 1k1r2r1/pp3p1p/B2q1n2/8/3Pb1p1/2Q5/PR3PPP/2B1R1K1 w - -
-solution Bf4
-id "ECM.212"
-go
-setboard k3r3/pR5p/PppR1p1p/4nP2/1PP5/8/4B1rP/2K5 w - -
-solution Re7
-id "ECM.213"
-go
-setboard 1q3rk1/r5b1/pNp1bn1p/2Pp1n2/1P2p3/1N2P2P/PBQKB3/3R3R b - -
-solution Nxe3
-id "ECM.214"
-go
-setboard r4n1r/ppq1nk2/1bpRpN2/4PpQ1/8/2B4P/PPP2PP1/2KR4 w - -
-solution Rd7
-id "ECM.215"
-go
-setboard 3r2k1/p5pp/bpP1p3/3n1p2/2NQpP1q/P3P3/1B1R1R2/4KBr1 b - -
-solution Rxf1+
-id "ECM.216"
-go
-setboard 1rq1r2k/5Rbp/p2p1p1B/2p1p3/2P1P2Q/1P6/P5PP/3b3K w - -
-solution Bxg7+
-id "ECM.217"
-go
-setboard 5Q2/5p1p/3p2p1/4p1k1/4P1P1/3R1P1K/r6P/4q3 w - -
-solution f4+
-id "ECM.218"
-go
-setboard 2b2r1k/ppq3pp/3b3r/n3NpN1/Q2PpP1B/2P1R3/PP5P/4R1K1 w - -
-solution Ngf7+
-id "ECM.219"
-go
-setboard 2r1r1k1/1R4bp/p5p1/2pqn3/8/2B5/1PQ1B1PP/5RK1 w - -
-solution Bc4
-id "ECM.220"
-go
-setboard 7k/pp1q2pp/3Nr1n1/3B2Q1/2pP4/B3P1Pb/P6P/6K1 w - -
-solution Qd8+
-id "ECM.221"
-go
-setboard r5k1/5p1p/bq1p2p1/r2Pp3/1p2N1P1/1P3P2/1KPQ3P/3R3R b - -
-solution Ra2+
-id "ECM.222"
-go
-setboard 5Bk1/pr2pp1p/2b3pQ/2p1q3/8/2P4P/PP4P1/1B1Rb1K1 w - -
-solution Bg7
-id "ECM.223"
-go
-setboard 5nk1/2b1q1p1/2p5/3pP1pQ/1r1P2P1/3B1R2/5PP1/6K1 w - -
-solution Rxf8+
-id "ECM.224"
-go
-setboard 1k1r3r/1pp2p2/p2b4/4n1p1/N3q1P1/1B2B3/PP3RP1/4RQK1 b - -
-solution Rh1+
-id "ECM.225"
-go
-setboard rnb1kr2/p4pQ1/8/1ppPpP2/2p1P3/N6P/Pq4B1/3R1RK1 w q -
-solution Nxb5
-id "ECM.226"
-go
-setboard 5r1k/2p3pp/3pQ3/3P1rN1/pp5q/5PR1/P4PKP/B7 w - -
-solution Bxg7+
-id "ECM.227"
-go
-setboard 8/pR3Bk1/3p2p1/5b1p/2P4P/6P1/P4bQK/4q3 b - -
-solution Bg1+
-id "ECM.228"
-go
-setboard r1b1Rnk1/6pp/p4q2/1pp2P2/3r4/2NB4/PP1Q2PP/4R1K1 w - -
-solution Nd5
-id "ECM.229"
-go
-setboard 1Q6/pb3pk1/1p3qp1/1N3p1p/2Pr3P/3BR1PK/r7/6R1 b - -
-solution Rh2+
-id "ECM.230"
-go
-setboard rq3r1k/p2n1p2/1pbb1np1/2p2BB1/8/2N2N2/PP3QPP/3R1RK1 w - -
-solution Rxd6
-id "ECM.231"
-go
-setboard 2kr3r/Qpp1n1p1/2b2pp1/4b3/8/6N1/PPP2P2/R1B2RK1 b - -
-solution Rh1+
-id "ECM.232"
-go
-setboard 8/2p2Q1p/1rp5/p3q1kp/P7/2P2RP1/5PK1/8 w - -
-solution Rf5+
-id "ECM.233"
-go
-setboard 1r2b3/1p2q1bk/p1p1p1p1/P1PpP2r/1P1KpPQP/4P2N/6R1/4B2R b - -
-solution Rxe5
-id "ECM.234"
-go
-setboard 6k1/3b1p1p/6p1/2BPR3/8/4Q2P/1q3rPK/8 w - -
-solution Re8+
-id "ECM.235"
-go
-setboard 2R5/4ppkp/6p1/p2P4/4P2P/p3B1P1/qbR2PK1/8 w - -
-solution Rg8+
-id "ECM.236"
-go
-setboard 3rr1k1/1b5p/p6p/1p3N2/6Pb/P1Q1p3/1PP4P/R5K1 b - -
-solution Bf2+
-id "ECM.237"
-go
-setboard 6k1/p4pq1/2n1p1p1/1p1pP1N1/3P1QPP/8/P3K3/8 w - -
-solution Qc1
-id "ECM.238"
-go
-setboard 3r1rk1/1pq1nppp/p7/2pB3Q/P4P2/1P2P3/6PP/2RR2K1 w - -
-solution Bf3
-solution Rxc5
-id "ECM.239"
-go
-setboard 8/p1r2q1k/1p1p3p/1Pp1nP2/P1P5/3R2PP/1Q4BK/8 w - -
-solution Rxd6
-id "ECM.240"
-go
-setboard 6k1/1pp2p2/p2p2q1/2PPb3/4r3/Pr4PK/2R5/2Q2NR1 b - -
-solution Rh4+
-id "ECM.241"
-go
-setboard 3r4/1pQ4R/p1b2kp1/P6p/2q5/7P/2P3P1/6K1 b - -
-solution Rd1+
-id "ECM.242"
-go
-setboard 6rr/1b3k1p/pbqppPn1/1p5Q/4PN2/P6R/1PP3BP/2B2R1K w - -
-solution Qxh7+
-id "ECM.243"
-go
-setboard 4rrk1/3b1ppp/pb6/1pqP4/P1p1PP2/1P2NK2/3QB2P/R2R4 b - -
-solution Rxe4
-id "ECM.244"
-go
-setboard 2r1r1k1/1p4bp/p2p1qp1/1n1P4/2P1B2P/1N1Q4/PP2R3/1K5R b - -
-solution Rxc4
-id "ECM.245"
-go
-setboard 6rr/ppqb1pkp/2pb1pn1/3p3Q/3P1P1N/3B1RN1/PPP3PP/5RK1 w - -
-solution Qh6+
-id "ECM.246"
-go
-setboard r2qr1k1/1pnb1pp1/p1n1p2p/8/P2P3P/B2B1NP1/6P1/R2Q1RK1 w - -
-solution Bh7+
-id "ECM.247"
-go
-setboard r2q1rk1/1b1nbpp1/p1p1p2p/1pPpN3/3P1N2/P2BP3/1PQ2PPP/R4RK1 w - -
-solution Bh7+
-id "ECM.248"
-go
-setboard 2r2rk1/pb4pp/1p2p3/4Npq1/3P1n2/5P2/PP1R2PP/RB2Q1K1 b - -
-solution Rc1
-id "ECM.249"
-go
-setboard 2r1rbk1/5pp1/bq5p/1pnBPN2/6Q1/N7/5PPP/R2R2K1 w - -
-solution Bxf7+
-id "ECM.250"
-go
-setboard 1k1r1r2/2b2R2/Bppp2p1/2q4p/Q2pP3/P2P4/2P3PP/1R4K1 w - -
-solution Bb7
-id "ECM.251"
-go
-setboard r5k1/pp2ppb1/4qn2/r3B1p1/3P4/3QNP1R/PP2K1P1/7R w - -
-solution Bxf6
-id "ECM.252"
-go
-setboard 1R2br1k/5r1p/p2p1P2/6RQ/3p1P2/4p2B/q6P/5N1K w - -
-solution Rxe8
-id "ECM.253"
-go
-setboard kr1r4/7p/2bqp1p1/p7/1Pp1PP1P/K1B1nNPB/PP5R/RN2Q3 b - -
-solution Qxb4+
-id "ECM.254"
-go
-setboard 5r1r/1pkb4/5pB1/2P5/p3R2P/Pq6/1PQ2Pn1/K2R4 w - -
-solution Rxd7+
-id "ECM.255"
-go
-setboard kn5r/p2r2p1/1pqBp1np/1Q1pPp2/R2P4/1N6/2P2PPP/R5K1 w - -
-solution Rxa7+
-id "ECM.256"
-go
-setboard 4Rnk1/2p2pp1/3r3p/p2P4/P5Q1/1B5P/5PK1/q7 w - -
-solution Rxf8+
-id "ECM.257"
-go
-setboard 4r3/2k1p2q/pp1nR1p1/2pP1pP1/2P2P2/1P6/P1K3B1/4Q3 w - -
-solution Rxd6
-id "ECM.258"
-go
-setboard 2b3k1/p4ppp/7q/2Q5/8/P3r1P1/1r4BP/R3R1K1 b - -
-solution Rxg2+
-id "ECM.259"
-go
-setboard r1b1rbk1/7p/2p1pBp1/p2pP1P1/5P2/1PqB4/P1P1Q3/1K4RR w - -
-solution Rxh7
-id "ECM.260"
-go
-setboard 2rq4/5rbk/3p1n1p/p2Pp2P/1p2b3/4BNR1/PP1Q1P2/3BK1R1 w - -
-solution Bxh6
-id "ECM.261"
-go
-setboard r2q1rkb/pp2p3/2p2pp1/3pPb2/3P3R/2N3P1/PPPQBPK1/3R4 w - -
-solution Rxh8+
-id "ECM.262"
-go
-setboard 3r2k1/p4rPp/1b1q3Q/n1p1pP2/1p6/3B1NR1/P4P1P/6RK w - -
-solution Qxh7+
-id "ECM.263"
-go
-setboard r1bqrnk1/p4p2/1p5p/3pB1p1/P2P2n1/1P1B2N1/2Q3PP/R4RK1 w - -
-solution Bh7+
-id "ECM.264"
-go
-setboard r2rn1k1/1bqn1ppp/p7/2bpP1P1/1p1N1Q2/1P3B2/PBP1NR1P/3R2K1 w - -
-solution Qxf7+
-id "ECM.265"
-go
-setboard r2r2k1/1bqpbpp1/ppn1p2p/2p1P1N1/P1B2B2/2P5/1PPRQPPP/3R2K1 w - -
-solution Nxf7
-id "ECM.266"
-go
-setboard r1b1r1k1/1p1n1p2/p1nBp1p1/q2pP1Np/P7/R2B3Q/2P2PPP/5RK1 w - -
-solution Nxf7
-id "ECM.267"
-go
-setboard r1b1k2r/ppp3pp/1qp5/2b1Pp2/3Qn3/5N2/PPPBNPPP/2KR3R w kq -
-solution Qd8+
-id "ECM.268"
-go
-setboard 1k6/1p4p1/P1p5/5Q2/2q2r2/P7/8/4R2K w - -
-solution Re8+
-id "ECM.269"
-go
-setboard 6k1/1p3p2/4r1p1/1PPrbq1p/2QN4/P2R1P1P/R4KP1/8 b - -
-solution Bg3+
-id "ECM.270"
-go
-setboard 4n1q1/1k1b4/2p4R/2Pp4/1p1N1rpQ/3B4/PPP2P2/2K5 w - -
-solution Nxc6
-id "ECM.271"
-go
-setboard r2qk2r/1pp2ppp/p3pnn1/6N1/1B1P2P1/1Q2P2P/PP3PK1/R6R b kq -
-solution Nh4+
-id "ECM.272"
-go
-setboard 2kr2r1/R2p3p/2n2p2/1R3P2/2P1p3/4BQ2/1Pq4P/4K3 w - -
-solution Ra8+
-id "ECM.273"
-go
-setboard r3r1k1/pp3pp1/2bb1q2/3p4/4n1Pp/2P1BB1P/PP2NPK1/R1Q4R b - -
-solution Qxf3+
-id "ECM.274"
-go
-setboard r1br4/ppq2pk1/3bpN2/8/2P5/3n2B1/PP2QPPP/R4K1R w - -
-solution Qg4+
-id "ECM.275"
-go
-setboard 6kb/B1p2p2/5r2/1r1p2pR/6q1/3P2P1/P1P2PP1/2KR3Q b - -
-solution Rb1+
-id "ECM.276"
-go
-setboard rn4k1/pp2p1b1/4b3/q2p2Q1/2B2P2/8/P1P1K1P1/R6R w - -
-solution Rh8+
-id "ECM.277"
-go
-setboard 3k2r1/pp1b3Q/1b2pP1p/3pN2q/5B2/7B/PP2nP1K/2R5 b - -
-solution Rg2+
-id "ECM.278"
-go
-setboard 2r2rk1/pp3qpp/8/3P1b2/3Q4/P1N1B3/5PKP/R2R4 b - -
-solution Rxc3
-id "ECM.279"
-go
-setboard r1b2rk1/1pqp1ppp/p1n1pn2/5N2/8/2PBB3/P1P2PPP/R2QR1K1 w - -
-solution Nxg7
-id "ECM.280"
-go
-setboard 4k2r/1bqnbppp/p3p3/1p2P1N1/2r2BB1/8/PPP3PP/R2Q1R1K w k -
-solution Nxf7
-id "ECM.281"
-go
-setboard 5r1k/1pqb3p/2n5/p1pB4/2Pp1r1P/1P5P/R2N2K1/3Q1R2 b - -
-solution Bxh3+
-id "ECM.282"
-go
-setboard r4r2/pp2qk2/4pnp1/3pQ3/2p2P2/3B4/PPP2P2/2KR3R w - -
-solution Bxg6+
-id "ECM.283"
-go
-setboard 3bq3/p1n2rk1/1pp1p1p1/3pPnPp/1P1P1N1P/2PN3K/P2BQR2/8 w - -
-solution Nxg6
-id "ECM.284"
-go
-setboard b6r/2q2k2/4pPp1/1p1n2Bp/2pPB1PP/2P2Q2/8/4R1K1 w - -
-solution Bxg6+
-id "ECM.285"
-go
-setboard r1b2r2/3pNpkp/3pn1p1/2pN3P/2PnP3/q3QP2/4BKP1/1R5R w - -
-solution Qh6+
-id "ECM.286"
-go
-setboard 4k3/p4ppp/nb1P4/4p3/1P6/P4BP1/3q1r1P/2R2QKR w - -
-solution Qb5+
-id "ECM.287"
-go
-setboard r2q1rk1/pp2pp2/3pb3/3Qb2R/4P1p1/1BN1Bn2/PPP2P2/2K4R w - -
-solution Rh8+
-id "ECM.288"
-go
-setboard 2r1r1k1/pp1nbpp1/4pn1p/q3NN1P/P1pP1B2/2P5/1PQ2PP1/R3R1K1 w - -
-solution Nxg7
-id "ECM.289"
-go
-setboard 1rbk2nr/p1pp2b1/7p/2qP1pp1/2Bn4/2NKBP2/PP2N1PP/R2Q3R b - -
-solution Qxc4+
-id "ECM.290"
-go
-setboard 1r3rk1/6p1/p1pb1qPp/3p4/4nPR1/2N4Q/PPP4P/2K1BR2 b - -
-solution Rxb2
-id "ECM.291"
-go
-setboard 5rk1/ppp1q2p/1n1p1np1/3P2N1/1P1R2P1/2Q4P/P3r1B1/5RK1 b - -
-solution Rxg2+
-id "ECM.292"
-go
-setboard 6k1/pp2p2p/3p2p1/4b1r1/2Pn1r1q/2B1N3/PP4B1/R3QRK1 b - -
-solution Qh2+
-id "ECM.293"
-go
-setboard r2qnr2/pp3kbQ/2npb1p1/2pN1pP1/4P3/8/PPP1BP2/R1B1K1NR w KQ -
-solution Qxg6+
-id "ECM.294"
-go
-setboard r2k3r/2pb1ppp/p1p1q3/2Q5/5B2/2N5/PPP2PPP/3R2K1 w - -
-solution Bxc7+
-id "ECM.295"
-go
-setboard 2r2r2/2N2pkp/2Q5/1N2p1b1/1p6/3P1qPb/PPR2P1P/4R1K1 b - -
-solution e4
-id "ECM.296"
-go
-setboard 2r1qrk1/pp1b1ppp/4pn2/n1b5/8/2NQ1NP1/PP1BPPBP/R2R2K1 w - -
-solution b4
-id "ECM.297"
-go
-setboard 2b1qr1k/7p/p1pR2p1/1pP1p1Q1/4P3/1B6/PP4PP/6K1 w - -
-solution Re6
-id "ECM.298"
-go
-setboard 1r2k2r/2p2p1b/q1Pppb1N/p2p2P1/Q2P4/P3B3/1P5P/2KRR3 b k -
-solution Rb4
-id "ECM.299"
-go
-setboard 8/2b2k1p/2N2pp1/P2p4/3KnP2/6BP/P5P1/8 w - -
-solution Kxd5
-id "ECM.300"
-go
-setboard 4b1r1/1p3ppk/3r3p/p1p1qP1B/3pPN2/3P3R/nPPQ3P/6RK w - -
-solution Ne6
-id "ECM.301"
-go
-setboard 4b2k/7p/3q3P/1p1pRpr1/1P1B4/2P2Q2/7K/8 w - -
-solution Qg3
-id "ECM.302"
-go
-setboard 2kr2r1/pbp4p/1p4p1/1NqpNp2/4nQ2/8/PPPR1PPP/2K1R3 w - -
-solution Nc6
-id "ECM.303"
-go
-setboard 1rr3k1/1p1bqpbp/1R1p2p1/pN1P4/P3P1n1/1Q6/3NB1PP/2B1R1K1 b - -
-solution Rc3
-id "ECM.304"
-go
-setboard r1br4/1p3k2/p2q1p2/3N1Pp1/3Q4/8/PP4P1/4RR1K w - -
-solution Re6
-id "ECM.305"
-go
-setboard r3kbnr/p4ppp/2p1p3/8/Q1B3b1/2N1B3/PP3PqP/R3K2R w KQkq -
-solution Bd5
-id "ECM.306"
-go
-setboard 3r1rk1/2p1qp1p/pnP3p1/4n3/PP1NpR2/1BQ4P/6P1/5RK1 w - -
-solution Ne6
-id "ECM.307"
-go
-setboard r1bq1k2/5pb1/p2p1n2/2pPrP2/2p4B/3B2R1/PP1Q2PP/R5K1 w - -
-solution Qg5
-id "ECM.308"
-go
-setboard 2bq1rk1/p4pbp/p2p2p1/3P4/2p1QP2/2Pr3P/PP1N2P1/R1B2RK1 b - -
-solution Bd4+
-id "ECM.309"
-go
-setboard r5rk/1p1bqpnp/3p1b1B/pBnPp2P/4P3/2N2Q2/PP3P2/R3KNR1 b Q -
-solution Nf5
-id "ECM.310"
-go
-setboard r3rk2/p2q1b1p/1pnP1Qp1/5pN1/2p2P2/P1P5/7P/4RRK1 w - -
-solution Re7
-id "ECM.311"
-go
-setboard r3r1k1/p1q2pp1/2p4p/7n/BPPP2N1/3Q1N2/P3n1P1/R1B4K b - -
-solution Nhg3+
-id "ECM.312"
-go
-setboard r2qrbk1/1p4pb/2n2p1p/pNpn4/2N5/PP1PPQPB/1B5P/2R2RK1 w - -
-solution Nbd6
-id "ECM.313"
-go
-setboard 5r1k/1p1b1p1p/p2ppb2/5P1B/1q6/1Pr3R1/2PQ2PP/5R1K w - -
-solution Qh6
-id "ECM.314"
-go
-setboard r1b2rk1/p3bppp/2q5/8/2p1NR2/PnB1P3/1PB1Q1PP/3R2K1 w - -
-solution Rd6
-id "ECM.315"
-go
-setboard r1rbb3/1R3pkp/2pBp1p1/p3P3/q6P/6P1/P2Q1P2/1R3BK1 w - -
-solution R1b4
-id "ECM.316"
-go
-setboard 4r3/pp1b3k/2p2qpp/2Pp4/1P6/PBbP1N1P/2R3P1/3Q3K b - -
-solution Re1+
-id "ECM.317"
-go
-setboard 1rb2rk1/p1p2ppp/2q5/3R4/2P1N3/bP4B1/P1Q2P1P/1K5R w - -
-solution Bd6
-id "ECM.318"
-go
-setboard 8/5k1p/5PpB/3PR3/2r4P/1p3K2/2b5/8 b - -
-solution Re4
-id "ECM.319"
-go
-setboard 4r2k/3b3p/p2p4/2pP1p2/q1B2Q1P/2PK1P2/Pr1R4/7R b - -
-solution Re4
-id "ECM.320"
-go
-setboard rnb2rk1/pp2bppp/2p5/q7/4NN2/4B1QP/PPP3P1/2KR3R w - -
-solution Rd5
-id "ECM.321"
-go
-setboard 2R5/2R4p/5p1k/6n1/8/1P2QPPq/r7/6K1 w - -
-solution Rxh7+
-id "ECM.322"
-go
-setboard r1b1r1kb/p1qn1pnp/2p1p1p1/4P1N1/2p1NPP1/4B3/PPPQ3P/3RK2R w K -
-solution Qxd7
-id "ECM.323"
-go
-setboard 5k1r/ppqnnp2/3b2p1/2pB2Qp/3p3N/1P1P2P1/P1P2P2/2B1R1K1 w - -
-solution Rxe7
-id "ECM.324"
-go
-setboard 5rk1/5p1p/8/3pNp2/RPrqn3/1Q5P/1P3PP1/4R1K1 w - -
-solution Rxe4
-id "ECM.325"
-go
-setboard 2rr2k1/4qppp/bn6/p1bB4/4N3/6P1/PB2PP1P/2RQ1RK1 w - -
-solution Rxc5
-id "ECM.326"
-go
-setboard 3r1rk1/pbqn1pp1/1pp2n1p/2b1p1B1/P1B1P2N/2N4P/1PP1QPP1/3R1RK1 w - -
-solution Rxd7
-id "ECM.327"
-go
-setboard 5rk1/r2nqpp1/p3p3/1p2P3/4N1pP/8/PPP3Q1/1K1R3R w - -
-solution Rxd7
-id "ECM.328"
-go
-setboard 1rr3k1/4ppb1/2q1bnp1/1p2B1Q1/6P1/2p2P2/2P1B2R/2K4R w - -
-solution Qh6
-id "ECM.329"
-go
-setboard 2r2r1k/1pq1b1p1/p1b1Qn1p/8/3B4/2NB4/PPP3PP/3R1R1K w - -
-solution Rxf6
-id "ECM.330"
-go
-setboard 3rqb2/1pR3pk/p3n1pp/3p4/3B4/PP6/1P4PP/4RQK1 w - -
-solution Rxe6
-id "ECM.331"
-go
-setboard rkb2qr1/1p5p/pQ1bp3/3p2B1/5n2/3B1N2/PP3PPP/2R2RK1 w - -
-solution Rxc8+
-id "ECM.332"
-go
-setboard 2r2rk1/1bq2ppp/p7/1p1pNN2/1b1PnB2/3Q3P/PP3PP1/R3R1K1 w - -
-solution Rxe4
-id "ECM.333"
-go
-setboard r3r1k1/1p3pPp/p1p5/3bb2N/7q/1P1Q4/2PB2PP/4RRK1 w - -
-solution Rxe5
-id "ECM.334"
-go
-setboard 8/5p2/4p1k1/4P1p1/2rBRbK1/5P2/r4P2/7R b - -
-solution Rxd4
-id "ECM.335"
-go
-setboard r1bqr1k1/pp3pp1/2p4p/3PN1n1/3P1b2/2NB4/PPQ2PPP/3R1RK1 b - -
-solution Rxe5
-id "ECM.336"
-go
-setboard r3r1k1/pbqn1ppp/1p3n2/1Pb5/2p5/5N1P/PBQ1BPP1/1N1R1RK1 b - -
-solution Rxe2
-id "ECM.337"
-go
-setboard 2r2rbk/6bp/5qp1/1N1p1n2/4p3/1p5P/1P3PP1/RBBQ1RK1 b - -
-solution Ng3
-id "ECM.338"
-go
-setboard r1b1r1k1/pp3p1p/1q2p1pQ/2b1P1B1/8/P2B3P/1P3PP1/2R1R1K1 w - -
-solution Rxc5
-id "ECM.339"
-go
-setboard 1k2r2r/1bpQN2p/1p6/P3p2q/4np2/2P2N2/2P2PPP/R3R1K1 b - -
-solution Rxe7
-id "ECM.340"
-go
-setboard r1k2n1r/2pb4/1p1p1qpp/p2P1p2/3N1P1P/2Q3P1/PPP1R3/2K1RB2 w - -
-solution Re8+
-id "ECM.341"
-go
-setboard r1b2r1R/1p2bpk1/4p1p1/4P1N1/p2p4/5Q2/qPP2PP1/1NKR4 w - -
-solution Qf6+
-id "ECM.342"
-go
-setboard rnb2rk1/3n1ppp/p3p3/1p2P1q1/3N4/1BN5/PPP3PP/R2Q1RK1 w - -
-solution Nxe6
-id "ECM.343"
-go
-setboard 4q1r1/5kpp/2p1nb2/2PpQp2/r4P2/1N3P2/1BP1R2P/6RK w - -
-solution Rxg7+
-id "ECM.344"
-go
-setboard 2r1k2r/1pq1bppp/p3bn2/4N3/2pPN3/2P5/P3QPPP/R1B1R1K1 w k -
-solution Nxf6+
-id "ECM.345"
-go
-setboard 1r3k1r/4Rn1p/pb1p1P2/1p1q2P1/5p2/7Q/PPP1B1RP/2K5 w - -
-solution Rxf7+
-id "ECM.346"
-go
-setboard 4rrk1/ppn3pp/2pb1n1q/3p4/1P1P4/P3BNP1/2P1BPKP/R2Q1R2 b - -
-solution Rxe3
-id "ECM.347"
-go
-setboard 2b1r2k/2Q4p/4q3/1pp5/3b4/4NP2/1P3BP1/3R2K1 w - -
-solution Rxd4
-id "ECM.348"
-go
-setboard r3r1k1/pp3ppp/1qp5/2bbNQ2/5B2/2P5/PP3PPP/3RR1K1 w - -
-solution Rxd5
-id "ECM.349"
-go
-setboard 7r/3qbk1r/3p1n2/p1pPp1p1/Pp1nPpP1/1P1Q1P1B/1NP3K1/R3B2R b - -
-solution Nxg4
-id "ECM.350"
-go
-setboard r2qn1k1/1p1b3p/2pp1b2/6pQ/p1P1P3/P1N3PB/1P6/3R1R1K w - -
-solution Rxf6
-id "ECM.351"
-go
-setboard 2rq3r/5p2/p3pkbQ/3p4/3N4/2P4R/P4PP1/4R1K1 w - -
-solution Rf3+
-id "ECM.352"
-go
-setboard r4k1r/pp2pp2/3p1b2/q2PnQpp/3N4/1BP3P1/PP3PP1/3RR1K1 w - -
-solution Rxe5
-id "ECM.353"
-go
-setboard 5rk1/2p3pp/p1p4r/2P1p3/3pPnq1/1P3R1P/PN1Q3K/R5N1 b - -
-solution Qxf3
-id "ECM.354"
-go
-setboard r1b3rk/pp1n3p/2p2b1n/4pp1q/2P5/1P3NPP/PBQ1NPB1/3RR1K1 w - -
-solution Rxd7
-id "ECM.355"
-go
-setboard 2r2rk1/p3p1bp/3qP1p1/1Q1p4/P4P2/3R4/1P4PP/2B2RK1 b - -
-solution Rxc1
-id "ECM.356"
-go
-setboard r3r1k1/4pp1p/b5pB/q1pP4/3b4/2N4P/PP4P1/R2RQ2K w - -
-solution Rxd4
-id "ECM.357"
-go
-setboard 1r6/3b1pk1/pr1p1q1p/2pPb1p1/2B1P1P1/2N2PP1/1PQ3K1/RR6 b - -
-solution Rxb2
-id "ECM.358"
-go
-setboard 2r2rk1/5ppp/1p2p3/p7/1n1R4/P1NnPN2/1P3PPP/1R4K1 b - -
-solution Nxb2
-id "ECM.359"
-go
-setboard 2r3k1/p1r1ppb1/2bp1np1/q5N1/1p1BP2Q/3P4/PP2N1PP/2R2R1K w - -
-solution Bxf6
-id "ECM.360"
-go
-setboard r3r1k1/p4ppp/2pp1b2/8/q2n1P2/2BQ3P/PPP3P1/1K1R2NR b - -
-solution Re3
-id "ECM.361"
-go
-setboard rn1kr3/pppb4/3p1q2/3P1pNn/2P2P1p/1P2Q2P/P2NR1B1/4R1K1 w - -
-solution Qxe8+
-id "ECM.362"
-go
-setboard r2q1rk1/ppp1b1pp/1nn1p3/4P3/2PP4/2N1B2P/PP1Q4/2KR1B1R b - -
-solution Rxf1
-id "ECM.363"
-go
-setboard r3k3/1pqb1p2/p3p3/4n2r/3N1Q2/2P5/PP4B1/4RRK1 w q -
-solution Rxe5
-id "ECM.364"
-go
-setboard 1rb2bk1/q4r2/pB1p1nn1/3Pp3/N3PpP1/8/1PQ1BNP1/R1R3K1 b - -
-solution Rxb6
-id "ECM.365"
-go
-setboard 2rbr2k/1pq2ppp/p3bn2/4p1B1/P3P3/2N3Q1/1PP1B1PP/3R1R1K w - -
-solution Rxd8
-id "ECM.366"
-go
-setboard r4rk1/5p2/p1b1pQpq/8/1B2P3/2NR4/PPP3PP/1K6 w - -
-solution Rd5
-id "ECM.367"
-go
-setboard 3nr1k1/p6p/2n1pRpB/3pP3/2pP2P1/q1P4P/6BK/5Q2 w - -
-solution Rxg6+
-id "ECM.368"
-go
-setboard 2rr2k1/5ppp/p1b1pn2/q1p5/P1B1PQ2/R1PN1P2/6PP/1R4K1 b - -
-solution Rxd3
-id "ECM.369"
-go
-setboard 1r2r1k1/1pqb2pp/p2bp1n1/2p3BQ/3pN3/1P1P2P1/P1P3BP/4RRK1 w - -
-solution Bd8
-id "ECM.370"
-go
-setboard 1k2rb1r/pbp1q1pp/2pp4/2PnpP2/Q7/1P3NP1/PB5P/2KR1B1R w - -
-solution Rxd5
-id "ECM.371"
-go
-setboard 7k/p1p1r2p/1p1pnr1q/5pp1/2PPPp2/2PB1P1P/P2Q1PRK/7R b - -
-solution g4
-id "ECM.372"
-go
-setboard 5qk1/p4p2/1p3Pp1/2p4Q/3rr3/7R/PP6/6RK b - -
-solution Rh4
-id "ECM.373"
-go
-setboard 5r1k/5Bb1/3p2Pp/p1pP4/1p2Q3/4P1P1/q7/3K3R w - -
-solution Rxh6+
-id "ECM.374"
-go
-setboard 2b4B/1pp2k2/1p6/3P3n/5p1P/1P4p1/P2r2P1/R5KR b - -
-solution f3
-id "ECM.375"
-go
-setboard r3k2N/pppbq1pp/5n2/3Ppn2/2BP4/2P3bP/PP2Q1P1/RNB2K1R b q -
-solution Bh2
-id "ECM.376"
-go
-setboard r2q1r2/p1pbppbk/1p3npp/n2P2B1/7Q/2NB1N2/PPP3PP/4RRK1 w - -
-solution d6
-id "ECM.377"
-go
-setboard 5n2/3bp1r1/1r1p3k/p1p2pNp/1nP2P1P/1PN1PB1K/P5R1/6R1 w - -
-solution Nf7+
-id "ECM.378"
-go
-setboard r3bb2/P1q3k1/Q2p3p/2pPp1pP/2B1P3/2B5/6P1/R5K1 w - -
-solution Bxe5+
-id "ECM.379"
-go
-setboard r1b1qbk1/7p/4p1p1/1p2Bp2/p1B2Q2/P3P3/1P3PPP/3R2K1 w - -
-solution Bc3
-id "ECM.380"
-go
-setboard 2r1k2r/3b1pb1/p2ppp2/2q2P2/2p1P2p/P1N2N2/1PP1Q1PP/3R1R1K w k -
-solution e5
-id "ECM.381"
-go
-setboard 3r1rk1/1pq1bppp/p7/n2RN3/P7/1P6/1B2QPPP/R5K1 w - -
-solution Nd7
-id "ECM.382"
-go
-setboard q1r3k1/2r4p/2p3pP/2Qp1p2/PRn5/4P1P1/5PB1/1R4K1 w - -
-solution Rxc4
-id "ECM.383"
-go
-setboard r3bknr/1p4pp/p3Q3/q4pb1/P1Bn4/8/1PP2PPP/R1B1R1K1 w - -
-solution Qd6+
-id "ECM.384"
-go
-setboard r1b1nrk1/p2n3p/2pp4/8/2P2q1N/1PB4P/P4PB1/R2QR1K1 w - -
-solution Bd5+
-id "ECM.385"
-go
-setboard 7k/5rp1/p1bQB2p/1p4nN/4P3/1Pq5/P5PP/3R3K b - -
-solution Bxe4
-id "ECM.386"
-go
-setboard r4r1k/1bq4p/p4bp1/3pn3/NP6/Q1PBB2P/6P1/3R1RK1 b - -
-solution d4
-id "ECM.387"
-go
-setboard r2r2k1/1bq2pb1/6pp/2P1p3/1nBpN2N/6PP/2Q2P2/3RR1K1 w - -
-solution Nf6+
-id "ECM.388"
-go
-setboard r3rbk1/p1q2pp1/1n5p/2pp4/4N3/1PQ3P1/PB2PP1P/3R1RK1 w - -
-solution Nf6+
-id "ECM.389"
-go
-setboard 2k1r3/Qp3pb1/2p4p/6q1/8/1P4PN/PBPn1P2/K2R4 b - -
-solution Qe5
-id "ECM.390"
-go
-setboard r3r1k1/1pp2p1b/7p/2Q5/2PP2p1/2P1NpPq/P2R1P1P/6RK b - -
-solution Rxe3
-id "ECM.391"
-go
-setboard 5bk1/5p1p/Q5p1/1B4n1/8/2q1p3/6PP/3R2K1 b - -
-solution e2
-id "ECM.392"
-go
-setboard r5k1/1p3pp1/1p3q1p/1P1bQ3/P2P3n/8/3B1PPP/R3R1K1 b - -
-solution Nf3+
-id "ECM.393"
-go
-setboard 2k2r1r/1pp1nqbp/p2p1p2/5P2/2PBN3/1P3Q2/1P4PP/R4RK1 w - -
-solution Rxa6
-id "ECM.394"
-go
-setboard r5kr/p3PR1p/1p1p2pq/4n3/8/3B4/P4QPP/4R1K1 w - -
-solution Rxe5
-id "ECM.395"
-go
-setboard 2bq1b2/1p3k2/1r1p1p1p/pNpP1PpP/P1P3P1/6B1/1P5Q/2K1R3 w - -
-solution Re6
-id "ECM.396"
-go
-setboard 2kr3r/pp3p1p/2b1p3/q3Q3/5P2/2P1B3/P1P3PP/1R3RK1 b - -
-solution Rhg8
-id "ECM.397"
-go
-setboard 2br1rk1/2qnQ2p/p4pp1/4p3/P1p1P1N1/2Pn1N1P/2B2PP1/1R1R1K2 w - -
-solution Rxd3
-id "ECM.398"
-go
-setboard 2r2nk1/6pp/p1rPqp2/1pP1p3/1P6/2B3R1/1P2Q1PP/5RK1 w - -
-solution Rxf6
-id "ECM.399"
-go
-setboard 3r2k1/pb3p1p/1q4p1/2b1P3/1Pp5/2P1p1P1/P3Q1BP/R1B4K b - -
-solution Qc6
-id "ECM.400"
-go
-setboard r2rnbk1/pp3ppp/1q4n1/3p1N2/5P2/1PQB4/PBP3PP/4RR1K w - -
-solution Nh6+
-id "ECM.401"
-go
-setboard r3nrk1/p1pb1qpp/3p1p2/2pP1N2/2P1PR2/P1PB4/4Q1PP/5RK1 w - -
-solution e5
-id "ECM.402"
-go
-setboard r1b2rk1/pp2qp2/2nRp1p1/6Pn/1Pp5/P1N1P3/1BQ2PP1/2K2B1R w - -
-solution Rxh5
-id "ECM.403"
-go
-setboard 5rr1/pp1kq1bp/2bppn2/2p3B1/4N3/2NP2P1/PPP4P/R3QRK1 b - -
-solution Nxe4
-id "ECM.404"
-go
-setboard 1r1q1k2/R4pp1/5p1r/1p1p1n1p/3Pb2N/1BP5/2P1Q1PP/4R1K1 w - -
-solution Qxe4
-id "ECM.405"
-go
-setboard R2b2k1/2rq1n1p/3p2p1/1p1Ppp1n/1P6/1B1PQN1P/1B3PP1/6K1 w - -
-solution Nxe5
-id "ECM.406"
-go
-setboard r1b3kr/bp3ppp/p1nNp3/4P3/P1Q2P2/BBP5/5qPP/R2R3K w - -
-solution Nxc8
-id "ECM.407"
-go
-setboard 6k1/5rb1/6pp/1p2p3/2b5/4B1P1/r4PBP/1RR3K1 w - -
-solution Rxc4
-id "ECM.408"
-go
-setboard 4r1k1/1p5p/5ppP/1qnP4/r4R2/P6P/1B1Q2K1/5R2 w - -
-solution Rxf6
-id "ECM.409"
-go
-setboard r2q1rnk/1p1bb1pp/p2p4/3NP1P1/P2Bp3/3Q3R/1PP1B2P/6RK w - -
-solution e6
-id "ECM.410"
-go
-setboard r4rk1/1b4bp/p1npq1P1/R3p3/8/1N2BP2/1PPQ2P1/4KB1R w K -
-solution Qxd6
-id "ECM.411"
-go
-setboard 6k1/pbq2pp1/4r2p/8/3prb2/1P1Q3P/PN2BPP1/3RRK2 b - -
-solution Bd2
-id "ECM.412"
-go
-setboard 6k1/2p3p1/2b4p/p4P2/2pR2PK/2P1r2P/1B6/8 b - -
-solution Bg2
-id "ECM.413"
-go
-setboard r1b2rk1/pp2ppbp/2np1np1/q7/4P3/2N1BN2/PPPQBPPP/2KR3R b - -
-solution Nxe4
-id "ECM.414"
-go
-setboard 3r1rk1/p1q4p/1p3bp1/3bnp2/3B4/1NPB3P/P1PQ2P1/1R2R2K b - -
-solution Nf3
-id "ECM.415"
-go
-setboard r2q1rk1/p5pp/bn1p1p2/2pP4/1bP1NP2/3B1R2/PBQ3PP/R5K1 w - -
-solution Ng5
-id "ECM.416"
-go
-setboard 1r1q2k1/7p/2p3p1/1P1n1b1r/2BQ4/4B3/P6P/1R3RK1 w - -
-solution bxc6
-id "ECM.417"
-go
-setboard r3kbnr/1ppb3p/p1q1pp2/3p4/3P4/2N2N2/PPP2PPP/R1BQ1RK1 w kq -
-solution Ne5
-id "ECM.418"
-go
-setboard r1b1qbk1/pp3r1p/2pR1np1/5p2/2P1pP2/1PN1Q1PP/PB2P1B1/5RK1 w - -
-solution Rxf6
-id "ECM.419"
-go
-setboard 3rr1k1/1p1qb2p/pP4p1/2p2p2/4RQ2/3P4/1PPB2PP/4R1K1 w - -
-solution Bc3
-id "ECM.420"
-go
-setboard 2b2r2/rpp2pkp/3pq3/2pR2P1/2n1P1N1/2P2B2/1P3Q1P/1K5R b - -
-solution Qxd5
-id "ECM.421"
-go
-setboard 6k1/rnqb3p/5ppQ/2pPp3/p1N1P3/2PB3P/5PP1/1R4K1 w - -
-solution f4
-id "ECM.422"
-go
-setboard 7r/pp4k1/3pn1p1/q1pB1b2/2P5/5NR1/1P3PP1/2Q3K1 w - -
-solution b4
-id "ECM.423"
-go
-setboard 5r2/4prkp/3q2p1/2pP1n2/N1Q2R2/1P4PP/P5K1/4R3 b - -
-solution g5
-id "ECM.424"
-go
-setboard B1b1rbk1/5ppp/pq6/1p2n3/2p2P2/6PP/PPQ4K/R1BR4 b - -
-solution Ng4+
-id "ECM.425"
-go
-setboard 8/2R4p/2R3bk/8/5N1P/1p3PP1/2pqP1K1/8 w - -
-solution g4
-id "ECM.426"
-go
-setboard 6k1/p4p1p/3pqp2/2p1r3/2Pnr1N1/P6P/1P1Q1PP1/3R1RK1 b - -
-solution Ne2+
-id "ECM.427"
-go
-setboard 1kqr3r/p1p4p/RpQP4/2P1p3/4B3/4Bp2/P4P1P/6K1 b - -
-solution Rdg8+
-id "ECM.428"
-go
-setboard 6k1/3Q1pp1/4p2p/p2pP3/1p1P2P1/nP1R1N2/q1r2PKP/8 w - -
-solution Qe8+
-id "ECM.429"
-go
-setboard 6k1/5pp1/p5r1/3Np2q/4P2p/1r3P1Q/n4P1P/3R2RK w - -
-solution Rxg6
-id "ECM.430"
-go
-setboard nr2rb2/3q1kpp/3p4/pnpPpNBP/2N1P3/3Q4/PP3P2/2K3RR w - -
-solution Nh6+
-id "ECM.431"
-go
-setboard r3k1r1/1pp2ppp/pb1p1qn1/4p2b/2B1P3/N1PP1NPP/PP2QPK1/R4R2 b q -
-solution Nh4+
-id "ECM.432"
-go
-setboard 1n2n1r1/r3qppk/p2p3p/3PpP1P/1P2P3/3B2RQ/3B1P1K/6R1 w - -
-solution Bxh6
-id "ECM.433"
-go
-setboard r2b4/pb2q1k1/np1p2r1/1N1Pp2Q/PPN1Pp2/8/2R2BPp/2R4K w - -
-solution Ncxd6
-id "ECM.434"
-go
-setboard r7/2qnb1kp/p2p1nP1/1p1Pp1p1/6N1/3BB2Q/PPP4P/5RK1 w - -
-solution Qxh7+
-id "ECM.435"
-go
-setboard n1rqk3/1p2p3/1n1pP1p1/pP1P1p1r/3B3P/1BN3p1/3Q4/R3K2R w KQ -
-solution Qg5
-id "ECM.436"
-go
-setboard rn2kr2/pp1b1pQp/3Pp3/qB1n4/3N4/P7/1PP2PPP/2KR3R w q -
-solution Nxe6
-id "ECM.437"
-go
-setboard 3r1r2/1b4bk/p1n3pp/1p2p3/4P3/q1P1QNB1/B4RPP/5RK1 w - -
-solution Bh4
-id "ECM.438"
-go
-setboard r1r3kb/1pqbpp2/p2p1npB/n7/3NP3/1BN2P2/PPPQ2P1/2KR3R w - -
-solution Bf8
-id "ECM.439"
-go
-setboard 4rr1k/pbp3bp/3p4/1p5q/3n4/1B1Q2B1/PP1N1N1P/4RRK1 b - -
-solution Rf3
-id "ECM.440"
-go
-setboard r3k2r/pp2ppbp/1qp5/2n2b2/2P5/4BN2/PP1QBP1P/2KR3R b kq -
-solution Nb3+
-id "ECM.441"
-go
-setboard 4qn1k/1b3rpp/pb2pB2/1pp1P2P/3p1NQ1/P2P2PB/1PP4K/5R2 w - -
-solution Ng6+
-id "ECM.442"
-go
-setboard 2b5/2qrrpk1/5Rp1/2p4p/1pB1PR1P/1P1P2P1/5Q1K/8 w - -
-solution Qb2
-id "ECM.443"
-go
-setboard 2r3k1/n3qppp/1B1r1n2/N7/N4P2/1Q4PP/P5B1/R1b4K b - -
-solution Qe1+
-id "ECM.444"
-go
-setboard 7r/2p1q1k1/1p3r1p/p1pPpPp1/2P1P1P1/PP6/3Q2KR/7R w - -
-solution Qxg5+
-id "ECM.445"
-go
-setboard rnb2k2/ppbp2p1/2p2pB1/8/1PN5/2P5/P4PPP/R1B3K1 w - -
-solution Bf4
-id "ECM.446"
-go
-setboard 2k5/1p1b4/2n1p1r1/7q/4RP2/3BQN2/2P2K1P/8 w - -
-solution f5
-id "ECM.447"
-go
-setboard 2k3r1/1ppr3p/p1pB2q1/6n1/N3Pp2/8/PPP1Q1PP/3R1RK1 b - -
-solution f3
-id "ECM.448"
-go
-setboard r3q2r/2p1k1p1/p5p1/1p2Nb2/1P2nB2/P7/2PNQbPP/R2R3K b - -
-solution Rxh2+
-id "ECM.449"
-go
-setboard 6r1/6rk/3p3p/p2Rp3/R1PqPp1b/2N2Q2/6PP/7K b - -
-solution Rxg2
-id "ECM.450"
-go
-setboard 4r1k1/1p2rq1p/2bQpp2/p1Pp4/3P4/P3RN2/5PPP/4R1K1 w - -
-solution Ne5
-id "ECM.451"
-go
-setboard b2b1r1k/3R1ppp/4qP2/4p1PQ/4P3/5B2/4N1KP/8 w - -
-solution g6
-id "ECM.452"
-go
-setboard 1k4q1/1p2Rprp/p1p5/2Pp4/1P1Q3P/6P1/P5K1/8 w - -
-solution Qe5+
-id "ECM.453"
-go
-setboard r2r3k/ppq3pp/2p1n3/4NQ2/3P4/1B6/PP3PPP/6K1 w - -
-solution Ng6+
-id "ECM.454"
-go
-setboard r4r1k/p2bN2p/1p1p1p2/2q4P/3Q4/1P6/1PP3P1/1K2R2R w - -
-solution Ng6+
-id "ECM.455"
-go
-setboard 2kr3r/p5b1/Pp2R1p1/2q2p1p/2p2Pn1/2P2BP1/1PQB2P1/5R1K b - -
-solution h4
-id "ECM.456"
-go
-setboard r1b2k1r/1p2qp2/pN1p1n2/2pP2pp/P2bP1P1/2N5/1P2BPP1/R2Q1RK1 b - -
-solution hxg4
-id "ECM.457"
-go
-setboard 6nk/p4rrp/1p1p1p2/1q1Pp2R/4B1P1/1PP2Q1R/P6P/7K w - -
-solution g5
-id "ECM.458"
-go
-setboard r1b1k2r/6pp/p1p1p3/3np1B1/1b2N3/8/q1PQB1PP/3RK2R w Kkq -
-solution Qxb4
-id "ECM.459"
-go
-setboard 3qrbk1/1r3p2/p1bp1Pp1/1p2p1Pp/4P2R/1P2BB1Q/P1P4P/R6K w - -
-solution Bxh5
-id "ECM.460"
-go
-setboard 2r3k1/4qpp1/2p1r3/pbQpN1Pp/3P1P1P/4P3/PP6/1KR3R1 w - -
-solution Qxb5
-id "ECM.461"
-go
-setboard 4r2k/p2Q3p/2p1r1p1/4NpR1/3P4/2P1PP1b/P4q1P/6RK w - -
-solution Nxg6+
-id "ECM.462"
-go
-setboard 4r1kb/p2r4/1np1p1p1/3nP1Bp/1p3P1R/1B2qP2/PPPN3Q/2K4R w - -
-solution Rxh5
-id "ECM.463"
-go
-setboard 2rq2k1/pp1bpp1p/3p1np1/8/3NPPnQ/1BP5/P1P3P1/1K1R3R w - -
-solution e5
-id "ECM.464"
-go
-setboard r1b3k1/3nqp1p/p1n1p1pP/3pP1N1/Pp3QN1/1Pr3P1/2PR1P2/4RBK1 w - -
-solution Rxd5
-id "ECM.465"
-go
-setboard 2r1kr2/p1qbbp1Q/3pp3/5p2/1p1N1PB1/6P1/PPP4P/K2RR3 w - -
-solution Bxf5
-id "ECM.466"
-go
-setboard r6k/ppr1qpp1/4n2p/3pP3/3P2R1/3BQ2P/P5PK/5R2 w - -
-solution Rf6
-id "ECM.467"
-go
-setboard 2rr2k1/5pn1/1b2q1pp/pP1pP3/2pP1PP1/2R1B2P/2Q3B1/3R3K w - -
-solution f5
-id "ECM.468"
-go
-setboard 2Q2bkr/5p2/1rb5/1pN1n1qB/1P1pPN2/6P1/5P2/R1R3K1 w - -
-solution Nce6
-id "ECM.469"
-go
-setboard 2r4r/1q1kb1p1/4p2p/3pP3/np6/3RBP2/NPP2Q1P/1K2R3 b - -
-solution Nc3+
-id "ECM.470"
-go
-setboard 2r4r/3bk1b1/1q2pp2/3pPp1p/1p1N1P1P/1P1R1BP1/P2Q4/1K1R4 w - -
-solution Nxf5+
-id "ECM.471"
-go
-setboard 1rb3k1/2r2pbp/p2q1npn/P1pPp1N1/2B1P3/2P1B1NP/5QP1/3R1RK1 w - -
-solution Ne6
-id "ECM.472"
-go
-setboard r7/pp4pk/2n3qp/5p2/3p4/P4QB1/1PP1RPPP/6K1 b - -
-solution d3
-id "ECM.473"
-go
-setboard 2r2r1k/1p3p1p/p2p1Pp1/3Pp3/1q2Bn1Q/8/1PP3PP/4RR1K w - -
-solution Rxf4
-id "ECM.474"
-go
-setboard r4rk1/5ppp/p7/4PR2/P1qnp2Q/4B3/1P4PP/5RK1 w - -
-solution Rh5
-id "ECM.475"
-go
-setboard 4r3/pb3pk1/6p1/8/6P1/1PNrB2K/P4P1P/2R5 b - -
-solution Rexe3+
-id "ECM.476"
-go
-setboard 1r3kr1/p3q1b1/3p2Q1/2p2p2/2P2N2/4Pn2/PB6/K2R3R w - -
-solution Ne6+
-id "ECM.477"
-go
-setboard 5r1k/6bp/3p1q2/3Q1nP1/8/6P1/PP3BKP/R2N4 b - -
-solution Ne3+
-id "ECM.478"
-go
-setboard 1r1q1k1r/Q4ppp/2B2n2/8/Pbbp4/1P4P1/2PP1P1P/R1B1K2R b KQ -
-solution Qe8+
-id "ECM.479"
-go
-setboard 5rk1/p1p1R1p1/1p5p/8/2pP1P2/3n2P1/PP2Q2P/5KNq b - -
-solution Nxf4
-id "ECM.480"
-go
-setboard r5k1/1N3ppp/4b3/1Nq5/Pn3pn1/5B2/1PPQ3P/R6K b - -
-solution Qxb5
-id "ECM.481"
-go
-setboard 1r2k2r/1bq2pp1/pn2p2p/1p2P1b1/3N4/2N3Q1/PPP3PP/1K1R1BR1 w k -
-solution Bxb5+
-id "ECM.482"
-go
-setboard r1bqn1r1/p2k1pp1/1p5p/n1pPpN2/2P1P3/P1PBB2P/4Q1P1/R4RK1 w - -
-solution Nxh6
-id "ECM.483"
-go
-setboard 2r2r2/p4p1k/1p2pBpn/2p5/6N1/8/P4P2/R3R1K1 w - -
-solution Kg2
-id "ECM.484"
-go
-setboard r4rk1/p1p2pp1/bp1p1q1p/n1nPpN2/2P1P2P/2PB4/P2BQPP1/R3K2R w KQ -
-solution Bg5
-id "ECM.485"
-go
-setboard 3rn1k1/pp3ppp/6b1/2p1Q3/2P1P3/P4P2/1B1qBP1P/1R5K w - -
-solution Rd1
-id "ECM.486"
-go
-setboard 4r1k1/5ppp/p1q3b1/1ppNr3/2P1P3/1P4QP/P4PP1/4RRK1 w - -
-solution f4
-id "ECM.487"
-go
-setboard 2kr2r1/2pqbp1p/p1n1b3/1P1pP3/4n3/1BP1BN2/1P4PP/RN1Q1RK1 b - -
-solution Bh3
-id "ECM.488"
-go
-setboard 2b3k1/5qp1/p2r1n1p/3p4/3B4/1RP3QP/P2Nr1P1/3R2K1 b - -
-solution Ne4
-id "ECM.489"
-go
-setboard 6k1/5rp1/4Nb1p/2p5/4Q3/1r5P/q5P1/3R1R1K w - -
-solution Rxf6
-id "ECM.490"
-go
-setboard 1r2r1k1/p4ppb/q1pbnn1p/4p3/N1P1P3/pPB2NP1/2Q1RPBP/R5K1 b - -
-solution Nxe4
-id "ECM.491"
-go
-setboard r4r2/1pnqb2k/3p1p1p/p1pPpPpP/2P1N1P1/4BP2/PP1Q4/R2R2K1 w - -
-solution Bxc5
-id "ECM.492"
-go
-setboard rnb3kr/ppp2ppp/1b6/3q4/3pN3/Q4N2/PPP2KPP/R1B1R3 w - -
-solution Nf6+
-id "ECM.493"
-go
-setboard 6kr/1p1r1p1p/p2pnPpQ/3Np2R/2q1P3/5P2/PPP5/2KR4 w - -
-solution Rxe5
-id "ECM.494"
-go
-setboard 3Rq1k1/1pp1Ppbp/r1b3p1/p7/P1N5/1P4P1/1B2PP1P/2R3K1 w - -
-solution Nd6
-id "ECM.495"
-go
-setboard r2q1rk1/pp1n2pp/2pb4/1P1p3n/P1PPpP2/4P2b/1BNNBP1P/R2QR1K1 b - -
-solution Nxf4
-id "ECM.496"
-go
-setboard rq1r2k1/3nbp1p/p2p2p1/1p1Pp1P1/3B1P2/3B3Q/PPP4P/2KR2R1 w - -
-solution f5
-id "ECM.497"
-go
-setboard r4rk1/1bq1bppp/8/p2pPR2/3B4/1NnP3Q/1P4PP/4R1K1 w - -
-solution Rh5
-id "ECM.498"
-go
-setboard r4rk1/1nqb1pbn/6pB/pppPp2p/8/1PP2NNP/P1BQ2P1/R4RK1 w - -
-solution Nxh5
-id "ECM.499"
-go
-setboard r1b2rk1/pp4bp/2p3p1/4q2n/NQPN1p1P/1P5n/P3PPB1/2BRRK2 b - -
-solution f3
-id "ECM.500"
-go
-setboard 4rqk1/p5b1/3p3p/3Pn1p1/1pP1NrP1/4NP2/P3Q1P1/1K1RR3 b - -
-solution Nxf3
-id "ECM.501"
-go
-setboard r2qkr2/1p3pQp/2p1b3/1B1pN3/1p6/8/1P1K1PPP/2B1R3 w q -
-solution Nxc6
-id "ECM.502"
-go
-setboard r3rk2/pb2bpp1/1n5p/q1pP1B2/1p3B2/5N2/PPQ2PPP/R2R2K1 w - -
-solution Bc8
-id "ECM.503"
-go
-setboard r1bqr2k/ppp2p1p/5b2/3Pn1p1/1PP1Bp2/8/PB2N1PP/R2Q1RK1 w - -
-solution Nxf4
-id "ECM.504"
-go
-setboard 1q4k1/p3rppp/3b1n2/8/5P2/4P3/PP1B3P/RNQ3K1 b - -
-solution Bxf4
-id "ECM.505"
-go
-setboard r3k2r/1p1b1p2/p3p3/2b3p1/4N1n1/1B5P/PPP3P1/R1B2R1K b kq -
-solution Bc6
-id "ECM.506"
-go
-setboard r3kb1r/npqbpp1p/p3n1p1/P3P3/6N1/3B1NB1/1PP3PP/R3QRK1 w kq -
-solution Ng5
-id "ECM.507"
-go
-setboard 7k/p6p/4bppb/1N6/P2p1p2/1PrP2P1/2r1P2P/1R1Q2K1 b - -
-solution f3
-id "ECM.508"
-go
-setboard 2kr4/pp1r1pp1/4n1p1/4R3/2Pp1qP1/3P2QP/5PB1/1R4K1 w - -
-solution Rc5+
-id "ECM.509"
-go
-setboard 3r1qk1/5p1p/4b1pP/1pRp4/1P1Q4/r5P1/5P2/4RBK1 w - -
-solution Rxe6
-id "ECM.510"
-go
-setboard r2qkn1r/pb2bp2/1pp1p3/5p1p/2BPN3/5NQ1/PPP2PPP/1K1RR3 w kq -
-solution d5
-id "ECM.511"
-go
-setboard 2rr1nk1/pp2q1b1/4p1p1/5p2/1nB5/2B1N1QP/PP4P1/4RRK1 w - -
-solution Nxf5
-id "ECM.512"
-go
-setboard 3r3k/p4npp/1p2qpb1/4P3/5P2/P3N3/1B2QP1P/6RK w - -
-solution exf6
-id "ECM.513"
-go
-setboard 6rk/1b2bp1p/ppq1p3/2p1Pp2/P1Br1P2/1PNR2P1/2P1QK1P/6R1 b - -
-solution Rxf4+
-id "ECM.514"
-go
-setboard r3r1k1/p1q2pp1/b1pb3p/n7/B3n3/2P1BN2/PP1N1PPP/R2QK2R b KQ -
-solution Nxc3
-id "ECM.515"
-go
-setboard 4qrk1/pp1bbppp/4pn2/2r1Q1B1/7P/2N3R1/PPP2PP1/2KR1B2 w - -
-solution Bxf6
-id "ECM.516"
-go
-setboard r5n1/pppb1B2/2k1pb2/3p2B1/5P2/2N5/PPP3P1/2KR4 w - -
-solution Nxd5
-id "ECM.517"
-go
-setboard 2b2q2/r2n2kp/1n1p1pp1/p1pP4/1pP1NPN1/1P1B4/P5PP/Q3R1K1 w - -
-solution Nexf6
-id "ECM.518"
-go
-setboard 1k1r2r1/p1p3q1/2p2p2/3pn3/1P1b2bB/1QN5/P4PPP/1R2RBK1 b - -
-solution Nf3+
-id "ECM.519"
-go
-setboard r3k2r/1bq1bp1p/p2p1np1/1p2p3/3NP3/P1N2QB1/1PP2PPP/3RR1K1 w kq -
-solution Ndxb5
-id "ECM.520"
-go
-setboard r2q4/5p1P/2p1bR2/ppk1p1P1/3pB2Q/8/PPP5/6K1 w - -
-solution g6
-id "ECM.521"
-go
-setboard r3kb1r/pp1b1pp1/4p3/2q3Qp/5B2/2PB4/P4PPP/R3R1K1 w kq -
-solution Rxe6+
-id "ECM.522"
-go
-setboard 1rbr2k1/p4pp1/5b1p/2p1p3/3qPP2/1PNB2PP/PKP2Q2/5R1R b - -
-solution c4
-id "ECM.523"
-go
-setboard r3r1k1/p6p/bp4p1/2bPN3/6n1/6P1/PB2RPB1/3R2K1 w - -
-solution d6
-id "ECM.524"
-go
-setboard 2bk3r/3r2pp/p2nQ3/q2R2P1/1p6/8/PPP2P1P/1K3B1R b - -
-solution Qxd5
-id "ECM.525"
-go
-setboard 3r1k2/1q1r1pp1/3p2bp/p2N4/8/2P1RQ1P/P4PP1/4R1K1 w - -
-solution Nf6
-id "ECM.526"
-go
-setboard 3q3r/p2r1pkp/bp1N1np1/n2p4/5Q2/B1P5/P4PPP/R3R1K1 w - -
-solution Nf5+
-id "ECM.527"
-go
-setboard r4Nk1/1p2pp1p/p1np2p1/3N4/P3PPn1/8/1bPKBqPP/R2Q1R2 b - -
-solution Qd4+
-id "ECM.528"
-go
-setboard 1kb3rr/1p2n2q/1Np2p2/1p6/1P1N1P1p/8/2P1RQPP/R6K w - -
-solution Nxb5
-id "ECM.529"
-go
-setboard r3r1k1/p3Rp1p/1qp1bQ2/8/1p1P4/3R4/PP3PPP/6K1 w - -
-solution Rg3+
-id "ECM.530"
-go
-setboard rn4k1/pp2rpb1/2pNb1pp/4p3/P3Pq2/2P2N1P/1PB1QPP1/R3R1K1 w - -
-solution Nf5
-id "ECM.531"
-go
-setboard 3r1rk1/pp3ppp/8/2p5/4PB1n/P1P2qPP/Q3RP1K/6R1 b - -
-solution Qg2+
-id "ECM.532"
-go
-setboard r4rn1/ppp1q3/2bp2kp/6P1/3QpP2/2N5/PPP1B3/2KR3R w - -
-solution f5+
-id "ECM.533"
-go
-setboard 3qr2r/1p1bppk1/3p2p1/p1nP1PQp/3N3R/1P4PP/P1P3BK/4R3 w - -
-solution Ne6+
-id "ECM.534"
-go
-setboard 2rq1rk1/1b1nbpp1/1p5p/p2pNB2/3p1N2/4P3/PPQ2PPP/2RR2K1 w - -
-solution Bh7+
-id "ECM.535"
-go
-setboard 8/5pkp/2pp2p1/4P3/1P2P3/2QBq2P/2PnNnPK/8 b - -
-solution Nf1+
-id "ECM.536"
-go
-setboard r3r2k/pb2q1p1/1p2Nn1p/2b5/2B5/2P2P2/PPQ3PP/4RR1K w - -
-solution Nf4
-id "ECM.537"
-go
-setboard r1b2nk1/ppq2ppp/8/1BP1p1NQ/5p2/8/PP3PPP/3R2K1 w - -
-solution Rd7
-id "ECM.538"
-go
-setboard 6k1/5qp1/pN5p/3pRp2/3QnP2/2r4P/r5P1/6RK b - -
-solution Qh5
-id "ECM.539"
-go
-setboard 5r1n/r2q1pkp/3p1npN/NppPp2P/1P2P3/2P1Q1P1/5P2/R3K2R w KQ -
-solution Nf5+
-id "ECM.540"
-go
-setboard 6rk/p2b4/3p1Nqp/2pPpn2/P1P4p/5P1P/Q2B1NP1/6RK b - -
-solution Ng3+
-id "ECM.541"
-go
-setboard r4r1k/pppb2pp/8/3q4/2N5/P1P2nQ1/BP2R2P/R6K b - -
-solution Ne1+
-id "ECM.542"
-go
-setboard r5rk/1pp1n1pp/p1n1b1q1/3p1p2/7R/2QB1N2/PB3PPP/4R1K1 w - -
-solution Rxe6
-id "ECM.543"
-go
-setboard 8/4Ppk1/6p1/1p6/1Pb1Q3/6pq/8/6K1 w - -
-solution Qe5+
-id "ECM.544"
-go
-setboard 3R4/4Qpk1/4p1p1/7p/7K/5rP1/5P2/2q5 w - -
-solution Qf8+
-id "ECM.545"
-go
-setboard 8/5pk1/p6p/2R5/3q2p1/6P1/2Q3PK/4r3 w - -
-solution Rg5+
-id "ECM.546"
-go
-setboard 1Q4R1/8/P1b2p2/2p2k2/2P5/5p2/1r5P/4R1K1 b - -
-solution f2+
-id "ECM.547"
-go
-setboard 5r1k/1q2R3/8/6Q1/8/8/6P1/7K b - -
-solution Rf1+
-id "ECM.548"
-go
-setboard 8/4p3/8/3P3p/P2pK3/6P1/7b/3k4 w - -
-solution d6
-id "ECM.549"
-go
-setboard 3Q4/k3K3/q7/2N1P3/1P6/5r2/8/8 b - -
-solution Rf7+
-id "ECM.550"
-go
-setboard 3k4/p1p5/8/2p1p3/4P3/PpPP2K1/1P6/8 b - -
-solution c4
-id "ECM.551"
-go
-setboard 6r1/5p1k/4p3/3pQp2/1p1P1P1q/1P3RR1/7r/5K2 w - -
-solution Rxg8
-id "ECM.552"
-go
-setboard r1b2rk1/ppp2ppp/2n3q1/b2N2N1/2BP4/4p2P/PPP3P1/R2Q1RK1 w - -
-solution Nxf7
-id "ECM.553"
-go
-setboard 1r4k1/3qb2p/pr1pppn1/2p2N2/2P2PQ1/1P4P1/P2R2BP/R5K1 w - -
-solution Bd5
-id "ECM.554"
-go
-setboard r6r/pR1nqkpp/2p1p3/3p4/6Q1/2b4P/P1PP1PP1/2B1R1K1 w - -
-solution Rxe6
-id "ECM.555"
-go
-setboard 1k1r3r/ppq2pnp/1npbb1p1/3p4/3P1NP1/2NBP2P/PPQ2P1B/1KR4R w - -
-solution Nb5
-id "ECM.556"
-go
-setboard 5rk1/p1p1br2/1p1p2qp/4p3/2PPn1pP/3Q2P1/PPN1P1K1/2RR2B1 b - -
-solution Bxh4
-id "ECM.557"
-go
-setboard r5r1/4q2k/p2p3p/5p2/4p3/P2QR3/1PP2PPP/4R1K1 w - -
-solution Rxe4
-id "ECM.558"
-go
-setboard r1b2rk1/4bnpp/2p5/pp2q3/4N3/PQ2B1P1/1PP3BP/4RRK1 w - -
-solution Ng5
-id "ECM.559"
-go
-setboard 2rr2k1/1p3p2/p2n2p1/P2PnNq1/3QP1p1/1RN5/6PP/5RK1 b - -
-solution Nf3+
-id "ECM.560"
-go
-setboard r3k1r1/pb1qpp1p/1pnp1n1B/2p2R2/3PP3/2P3PN/P1P3BP/R2Q3K b q -
-solution Nxe4
-id "ECM.561"
-go
-setboard 2r2rk1/pp2bppp/3q1n2/3nNRB1/3P4/1B5Q/PP4PP/3R2K1 w - -
-solution Nxf7
-id "ECM.562"
-go
-setboard r1bq1rk1/1pp2ppn/1pnp3p/3N4/2B1PN2/3P4/PPP3PP/R2Q1RK1 w - -
-solution Ng6
-id "ECM.563"
-go
-setboard r1b2rk1/pp3p1p/2pq2pn/2nNN3/2B1QP2/8/P1PP2PP/R1B1K2R w KQ -
-solution Nxf7
-id "ECM.564"
-go
-setboard 1r2r1k1/1bn2pbp/pp1q1np1/2pPN1B1/P1B5/2N4P/1P1Q1PP1/R3R1K1 w - -
-solution Nxf7
-id "ECM.565"
-go
-setboard 1rb2bk1/2n2qp1/p2p3p/R1pP1p2/2B5/1PBQ1N1P/2P2PP1/6K1 w - -
-solution Rxc5
-id "ECM.566"
-go
-setboard r1b3k1/2pq2pp/p4p2/1p1Nr3/2n2R2/1B6/PPQ2PPP/R5K1 w - -
-solution Rxc4
-id "ECM.567"
-go
-setboard 2rq1rk1/3bbppp/p3pn2/1p1pN3/2nP1B2/P1NBP2Q/1P3PPP/2R2RK1 w - -
-solution Nxd5
-id "ECM.568"
-go
-setboard 2r1r1k1/pp1b1ppp/1q6/3P4/7N/Pn1Q4/1P3PPP/1RB2RK1 b - -
-solution Nxc1
-id "ECM.569"
-go
-setboard 1r4nk/3b2bp/3p4/3P3p/2pNPq2/P1N2p1P/1P3Q2/1R4KR b - -
-solution Rxb2
-id "ECM.570"
-go
-setboard 2r5/p3kpp1/P2p4/1P2pP1p/1P2PqnP/6R1/r2N2P1/3RQ1K1 b - -
-solution Rxd2
-id "ECM.571"
-go
-setboard 2br2k1/1p2qppp/r1n1p3/pQ1nN3/P2P4/2B3P1/1P3PBP/2RR2K1 w - -
-solution Qxa6
-id "ECM.572"
-go
-setboard 5rk1/3q2bp/3pb2r/1p1n1p2/3p1P2/P2B1QN1/1P1B2PP/2R1R1K1 w - -
-solution Nxf5
-id "ECM.573"
-go
-setboard 4r1k1/1ppQr1p1/1p1p1pP1/3P3p/7P/1P3q2/P1P5/1KRR4 w - -
-solution Re1
-id "ECM.574"
-go
-setboard 2Rr2k1/7p/4pqp1/p4p2/1p1P1Q1P/8/PP3PP1/6K1 w - -
-solution Qe5
-id "ECM.575"
-go
-setboard 4r1kb/5p1p/6pB/3Np3/4n3/P3Q1PP/2q2P2/R5K1 w - -
-solution Rc1
-id "ECM.576"
-go
-setboard 5rk1/bp4p1/p2rp2p/8/8/2PN4/PP1R1PPP/3R2K1 b - -
-solution e5
-id "ECM.577"
-go
-setboard 2q1rk2/QR3ppp/1pPpb3/1P2p1b1/4P3/6P1/3N1PBP/6K1 w - -
-solution Bh3
-id "ECM.578"
-go
-setboard n1bq3k/pp4bp/6p1/5pP1/3p1P2/1B1P4/PB3Q1P/4R1K1 w - -
-solution Bxd4
-id "ECM.579"
-go
-setboard r3r1k1/p2n4/3p1pp1/qnp3B1/1p2P1P1/1P3P2/PP2N2Q/1K1R1B2 w - -
-solution Nf4
-id "ECM.580"
-go
-setboard 6k1/pb3ppp/1p2p3/4P3/5P2/P1r5/1q4PP/1B2Q1RK b - -
-solution Rc1
-id "ECM.581"
-go
-setboard 2rq1kbR/4R1p1/3p3r/pp1P1Pp1/6P1/3B4/PPP1Q3/6K1 w - -
-solution f6
-id "ECM.582"
-go
-setboard 2r5/5kb1/4ppp1/pp1qB3/2rP4/1RP2R1Q/P4PP1/6K1 b - -
-solution Rh8
-id "ECM.583"
-go
-setboard 4k3/4Bp2/1p2nP1P/2p5/2K1b1B1/8/P7/8 w - -
-solution Bf3
-id "ECM.584"
-go
-setboard 3rr1k1/ppp1qp1p/3b2p1/4np1P/1P1N1Pn1/P1P4R/1B1NB3/R2Q1K2 b - -
-solution Nf3
-id "ECM.585"
-go
-setboard 1k1r3r/ppqb4/5Ppp/3p4/P2np3/3BR1Q1/2PB1PPP/R5K1 w - -
-solution Rxe4
-id "ECM.586"
-go
-setboard r2q1rk1/pb1nbpp1/1pp1pn1p/3pN3/2PPP3/2N1B1P1/PP3PBP/R2Q1RK1 w - -
-solution Nxc6
-id "ECM.587"
-go
-setboard 8/2R2pbk/6pp/1p2pq2/1P2Qn2/3P3P/3B1PP1/r3N1K1 b - -
-solution Nxd3
-id "ECM.588"
-go
-setboard 2r2rk1/pp2pp1p/2np2p1/q4P2/2PBP1b1/2N5/PP1Q2PP/R4RK1 w - -
-solution h3
-id "ECM.589"
-go
-setboard r2b1rnk/1p4qp/p1p1b1p1/2PpNp2/PP1PnP1Q/3BB2R/4N1PP/R6K w - -
-solution Qxh7+
-id "ECM.590"
-go
-setboard r1b2rk1/1p3pbp/2p3p1/p1q5/1P6/1Q4P1/1P2PPBP/R1B1R1K1 b - -
-solution Be6
-id "ECM.591"
-go
-setboard 4r1k1/r1q2p1p/p5pB/1pbBpN1n/1n2P3/5Q2/PP3PPP/R1R3K1 w - -
-solution Rxc5
-id "ECM.592"
-go
-setboard r1r3k1/ppnbb1pp/2ppp1q1/1P3p2/P1PPn3/2N2NP1/2Q1PPBP/1RB2RK1 w - -
-solution Nxe4
-id "ECM.593"
-go
-setboard r1b1k2r/2q1bppp/p3p3/1p1nP1B1/3Q4/2N5/PPP1B1PP/2KR3R w kq -
-solution Bxe7
-id "ECM.594"
-go
-setboard 1rb1r1k1/p1p1qppp/2pb4/8/2P3n1/4P1P1/PB2BP1P/R1QN1RK1 b - -
-solution Nxh2
-id "ECM.595"
-go
-setboard 2rqk1nr/pp3ppp/2n1p3/2b5/3N4/2NQB1P1/PP2PPKP/R4R2 w k -
-solution Nxe6
-id "ECM.596"
-go
-setboard rnb2rk1/pp4pp/2pb1n2/3N1p1q/2P5/3N2P1/P1Q1PPBP/R1B2RK1 w - -
-solution Bf4
-id "ECM.597"
-go
-setboard 8/8/1p1k4/5ppp/PPK1p3/6P1/5PP1/8 b - -
-solution f4
-id "ECM.598"
-go
-setboard 8/5pp1/7p/5P1P/2p3P1/2k5/5P2/2K5 w - -
-solution f6
-id "ECM.599"
-go
-setboard 7k/8/1p1ppp1p/1Pp5/2P2P2/8/3P2PP/6K1 w - -
-solution f5
-id "ECM.600"
-go
-setboard 8/p5k1/2p2p2/4p1p1/1p2P3/1P4PP/1PP5/5K2 b - -
-solution g4
-id "ECM.601"
-go
-setboard 8/5K2/kp6/p1p5/P2p4/1P3P2/2P5/8 b - -
-solution b5
-id "ECM.602"
-go
-setboard 8/2k3p1/2p4p/5P2/2K3PP/8/8/8 w - -
-solution g5
-id "ECM.603"
-go
-setboard 8/1kp1b3/1p4K1/4P2p/P1P3p1/5pP1/P4P2/4B3 b - -
-solution h4
-id "ECM.604"
-go
-setboard 8/8/4b1p1/2Bp3p/5P1P/1pK1Pk2/8/8 b - -
-solution g5
-id "ECM.605"
-go
-setboard 8/8/3K1k2/5p1p/4p1p1/4P1P1/5PP1/8 b - -
-solution f4
-id "ECM.606"
-go
-setboard r1b5/p2k1r1p/3P2pP/1ppR4/2P2p2/2P5/P1B4P/4R1K1 w - -
-solution Bxg6
-id "ECM.607"
-go
-setboard 6r1/1p3k2/pPp4R/K1P1p1p1/1P2Pp1p/5P1P/6P1/8 w - -
-solution Rxc6
-id "ECM.608"
-go
-setboard 1k2b3/4bpp1/p2pp1P1/1p3P2/2q1P3/4B3/PPPQN2r/1K1R4 w - -
-solution f6
-id "ECM.609"
-go
-setboard 2kr3r/ppp1qpp1/2p5/2b2b2/2P1pPP1/1P2P1p1/PBQPB3/RN2K1R1 b Q -
-solution Rh1
-id "ECM.610"
-go
-setboard 1r3qk1/pb3p1p/1pn2PpQ/2pN4/3r4/5B2/PPP4P/4RRK1 w - -
-solution Ne7+
-id "ECM.611"
-go
-setboard 4r1k1/5p1p/3q2p1/1p1P4/1P6/2p4P/2Q1nPB1/4RK2 b - -
-solution Ng3+
-id "ECM.612"
-go
-setboard 6k1/2q3p1/1n2Pp1p/pBp2P2/Pp2P3/1P1Q1KP1/8/8 w - -
-solution e5
-id "ECM.613"
-go
-setboard 5r2/pp1RRrk1/4Qq1p/1PP3p1/8/4B3/1b3P1P/6K1 w - -
-solution Qxf7+
-id "ECM.614"
-go
-setboard 6k1/1q2rpp1/p6p/P7/1PB1n3/5Q2/6PP/5R1K w - -
-solution b5
-id "ECM.615"
-go
-setboard r5r1/8/bRP1pk1p/3pNp2/5P2/7P/PR4P1/6K1 w - -
-solution Rxa6
-id "ECM.616"
-go
-setboard 3r2k1/p6p/b2r2p1/2qPQp2/2P2P2/8/6BP/R4R1K w - -
-solution Rxa6
-id "ECM.617"
-go
-setboard 8/p3q1k1/6p1/1p3nP1/2pp1QBr/P2P4/1PP2K2/R7 b - -
-solution Qe3+
-id "ECM.618"
-go
-setboard 7k/4b2p/5p1P/5PP1/1pNp1P2/1P1B4/2P2K2/r7 w - -
-solution g6
-id "ECM.619"
-go
-setboard 5r1k/1p1b2rP/p2p4/3P3B/P2P4/5pP1/1P2pP2/R3R1K1 b - -
-solution Rxg3+
-id "ECM.620"
-go
-setboard 6B1/2p2pp1/2p5/p3K3/1k6/nP4P1/5P1P/8 b - -
-solution Nc4+
-id "ECM.621"
-go
-setboard 3q1k2/5p2/p5pN/1b2Q2P/8/8/5PPK/8 w - -
-solution Qh8+
-id "ECM.622"
-go
-setboard 6k1/p3b1pp/4p3/4Pp2/Pp1r1P1P/1P4P1/2p2R2/5RK1 b - -
-solution Rc4
-id "ECM.623"
-go
-setboard 4r2k/3n1Qpp/1pRP1p2/p4P2/1p1P2P1/6rP/P3q1B1/6RK w - -
-solution Qe6
-id "ECM.624"
-go
-setboard 2r2rk1/p1N2p1p/2P1p1p1/1Pp3q1/3b4/5Q2/P1P3PP/4RR1K w - -
-solution Nxe6
-id "ECM.625"
-go
-setboard 3r1r2/pp1P3k/4Rbp1/1BP2p1p/8/7P/P4KP1/3R4 w - -
-solution Ba6
-id "ECM.626"
-go
-setboard 3rr1k1/pppRn1pp/4Pp2/1P5q/1QB5/4P3/P4P1P/4K1R1 w - -
-solution Qxe7
-id "ECM.627"
-go
-setboard rn1q2k1/pp3pb1/3p2pp/2pP2N1/3r1P2/7Q/PP4PP/R1B2RK1 w - -
-solution Nxf7
-id "ECM.628"
-go
-setboard 8/6Bp/6p1/2k1p3/4PPP1/1pb4P/8/2K5 b - -
-solution b2+
-id "ECM.629"
-go
-setboard 5bk1/r4ppp/1r1P1n2/2p2N2/b7/2B3P1/5PBP/R3R1K1 w - -
-solution Bxf6
-id "ECM.630"
-go
-setboard 8/8/8/P2k1p2/2N5/1pb2P2/4P3/2K5 w - -
-solution a6
-id "ECM.631"
-go
-setboard 3qr1k1/p4ppp/1p1P4/2r1nN2/4P2n/P7/1B4P1/3QRRK1 w - -
-solution d7
-id "ECM.632"
-go
-setboard 6k1/5pbp/6p1/2p1r3/1pPr4/3n2NP/1PB2PP1/1R1R2K1 b - -
-solution Nxb2
-id "ECM.633"
-go
-setboard 4r3/p4pk1/6p1/P1pB2Pp/2P3b1/2p1N1P1/Qb1r1P2/6K1 b - -
-solution Rxe3
-id "ECM.634"
-go
-setboard 2r1rbk1/p1Bq1ppp/Ppn1b3/1Npp4/B7/3P2Q1/1PP2PPP/R4RK1 w - -
-solution Nxa7
-id "ECM.635"
-go
-setboard r4rk1/ppq3pp/2p1Pn2/4p1Q1/8/2N5/PP4PP/2KR1R2 w - -
-solution Rxf6
-id "ECM.636"
-go
-setboard r3qr1k/1b4pp/p2RQ3/Bp2p3/4p3/6P1/PPP2P1P/3R2K1 b - -
-solution Qh5
-id "ECM.637"
-go
-setboard 8/6kP/6p1/1p1pP3/pP6/P1n2K2/2N5/8 w - -
-solution e6
-id "ECM.638"
-go
-setboard 8/Pb6/8/8/7K/5k1p/6pB/8 b - -
-solution g1=Q
-id "ECM.639"
-go
-setboard 8/pR4pk/1b6/2p5/N1p5/8/PP1r2PP/6K1 b - -
-solution Rxb2
-id "ECM.640"
-go
-setboard 6k1/p4pp1/Pp2r3/1QPq3p/8/6P1/2P2P1P/1R4K1 w - -
-solution cxb6
-id "ECM.641"
-go
-setboard 6k1/p4pbp/Bp2p1p1/n2P4/q3P3/B1rQP3/P5PP/5RK1 w - -
-solution dxe6
-id "ECM.642"
-go
-setboard 5r2/R4p2/5P1k/4PK2/1p6/8/8/8 w - -
-solution Rxf7
-id "ECM.643"
-go
-setboard 4r2k/pppb2pp/2np2q1/3B4/2P2P2/1PB1R1P1/PQ5P/6K1 w - -
-solution f5
-id "ECM.644"
-go
-setboard 1r6/3r1Pk1/p2p1np1/5q2/1p3P2/1B5R/PPP4Q/1K1R4 w - -
-solution Rh8
-id "ECM.645"
-go
-setboard 8/2k5/2p5/2pb2K1/pp4P1/1P1R4/P7/8 b - -
-solution Bxb3
-id "ECM.646"
-go
-setboard 2r5/1r5k/1P3p2/PR2pP1p/4P2p/2p1BP2/1p2n3/4R2K b - -
-solution Nd4
-id "ECM.647"
-go
-setboard 4r2k/p2qr1pp/1pp2p2/2p1nP1N/4R3/1P1P2RP/1PP2QP1/7K w - -
-solution Rxg7
-id "ECM.648"
-go
-setboard 6k1/p4p2/5Ppp/3RP3/Pr4P1/2p2K2/7P/8 w - -
-solution Rd8+
-id "ECM.649"
-go
-setboard 8/1R2P3/6k1/3B4/2P2P2/1p2r3/1Kb4p/8 w - -
-solution Be6
-id "ECM.650"
-go
-setboard 2kr2r1/pp2bQ1p/2b1P3/2qN4/8/1B2p2P/PPP3P1/3R1R1K b - -
-solution e2
-id "ECM.651"
-go
-setboard r1b2rk1/1p2qppp/p3p3/2n5/3N4/3B1R2/PPP1Q1PP/R5K1 w - -
-solution Bxh7+
-id "ECM.652"
-go
-setboard 3r1rk1/pp1q1ppp/3pn3/2pN4/5PP1/P5PQ/1PP1B3/1K1R4 w - -
-solution Bb5
-id "ECM.653"
-go
-setboard r2qrbk1/5ppp/pn1p4/np2P1P1/3p4/5N2/PPB2PP1/R1BQR1K1 w - -
-solution Bxh7+
-id "ECM.654"
-go
-setboard 6rk/3nrpbp/p1bq1npB/1p2p1N1/4P1PQ/P2B3R/1PP1N2P/5R1K w - -
-solution Nxh7
-id "ECM.655"
-go
-setboard 1rb2rk1/3nqppp/p1n1p3/1p1pP3/5P2/2NBQN2/PPP3PP/2KR3R w - -
-solution Bxh7+
-id "ECM.656"
-go
-setboard 2k5/ppp3pp/8/NQ2n2q/2Pp1n2/R4bP1/1P3P1P/4R1K1 b - -
-solution Qxh2+
-id "ECM.657"
-go
-setboard 5rrk/1p3qpp/p3pn2/2PpBp2/3P1P1Q/P1P1R2R/2b1B1PP/6K1 w - -
-solution Qxh7+
-id "ECM.658"
-go
-setboard r4rk1/1bq2ppp/p1p1p3/2b1P1B1/3p2Q1/3B4/PPP2PPP/R3R1K1 w - -
-solution Bxh7+
-id "ECM.659"
-go
-setboard r4rk1/pb1q1ppp/2N1p3/2Rn4/3P4/3BPQ2/1P3PPP/2R3K1 w - -
-solution Bxh7+
-id "ECM.660"
-go
-setboard r5rk/1p1q1p1p/5pn1/p2p1N1Q/3P2P1/PP2R3/5P1P/5RK1 w - -
-solution Qxh7+
-id "ECM.661"
-go
-setboard 2r2r2/p2qppkp/3p2p1/3P1P2/2n2R2/7R/P5PP/1B1Q2K1 w - -
-solution Rxh7+
-id "ECM.662"
-go
-setboard 1r1qr1k1/5p1p/1n2p1p1/pp1pP1P1/2pP1BB1/PnP3P1/1P3PK1/1R1Q3R w - -
-solution Rxh7
-id "ECM.663"
-go
-setboard 4rrk1/2q1bppp/p2p4/1p1Pn3/3B1R2/P2B2Q1/1PP3PP/5R1K w - -
-solution Bxh7+
-id "ECM.664"
-go
-setboard r1b2rk1/2q1bppp/p1n1p3/1p1np1P1/5P2/1NNBBQ2/PPP4P/R4RK1 w - -
-solution Bxh7+
-id "ECM.665"
-go
-setboard 5r1k/ppp2qnp/1n1p1N1Q/3Ppb2/2P4P/7B/PP6/2KR2R1 w - -
-solution Nxh7
-id "ECM.666"
-go
-setboard r4rk1/pp2q1p1/4b2p/2ppb3/6n1/2P3N1/PPQBBPPP/R4RK1 b - -
-solution Nxh2
-id "ECM.667"
-go
-setboard b3r1k1/2rN1ppp/2n1p3/p7/P3BP2/1R6/q1P2QPP/3R2K1 w - -
-solution Bxh7+
-id "ECM.668"
-go
-setboard 2r1qrk1/3n3p/b3pPp1/4P3/1pp1nBN1/pP4PQ/P1P2PK1/3RR3 w - -
-solution Qxh7+
-id "ECM.669"
-go
-setboard r1b1rnk1/pp1nb1pp/2p1pp2/q3N3/2PP1P2/3BP1N1/PBQ3PP/R4RK1 w - -
-solution Bxh7+
-id "ECM.670"
-go
-setboard 4r1k1/2q2r1p/p3bQ2/1p4Bp/2np4/8/PPB2PP1/3RR1K1 w - -
-solution Bxh7+
-id "ECM.671"
-go
-setboard 5rk1/pbrn1ppp/1ppN1q2/2P1p3/3P4/1PRB4/P3QPPP/5RK1 w - -
-solution Bxh7+
-id "ECM.672"
-go
-setboard 2rqr1k1/1p1bbppp/p3p3/n7/3P2Q1/2PB1N2/P4PPP/R1B1R1K1 w - -
-solution Bxh7+
-id "ECM.673"
-go
-setboard r1b2r1k/ppppq1pp/2n1n3/6N1/2B2P2/4B3/PPP3PP/R2Q1RK1 w - -
-solution Nxh7
-id "ECM.674"
-go
-setboard rn1q1rk1/pb1p1ppp/4p3/2pnP3/1bp5/2N2N2/PP3PPP/RBBQK2R w KQ -
-solution Bxh7+
-id "ECM.675"
-go
-setboard r2r2k1/p1p2p1p/4pPp1/1Pqb4/8/7R/1PB2PPP/3QR1K1 w - -
-solution Rxh7
-id "ECM.676"
-go
-setboard r1b2rk1/1pq2ppp/p1p1p3/2n1P3/2N2P2/3B4/PPP3PP/R2Q1RK1 w - -
-solution Bxh7+
-id "ECM.677"
-go
-setboard rnq3rk/4bp1p/p1p3pQ/1p1pP3/1P1N1B2/2P3R1/1P3PPP/R5K1 w - -
-solution e6
-id "ECM.678"
-go
-setboard rn3rk1/pp1bppbp/1qp3p1/4P1N1/PP1PB3/2P1B3/4Q1PP/R4RK1 w - -
-solution Nxh7
-id "ECM.679"
-go
-setboard 3rr1k1/1pq1nppp/p1p2b2/4pB2/2QPP3/P1P1B3/1P4PP/3R1RK1 w - -
-solution Bxh7+
-id "ECM.680"
-go
-setboard 1r2nrkb/2n2p1p/p2p1Pp1/P1pPp1P1/1pP1P1q1/1P1BB1N1/3Q4/2KR3R w - -
-solution Rxh7
-id "ECM.681"
-go
-setboard 2rrn1k1/2q2ppp/p2pp3/1p2P1P1/4B3/P5Q1/1PP3PP/R4R1K w - -
-solution Bxh7+
-id "ECM.682"
-go
-setboard r2q3r/2pkb1p1/p2p1n2/4p1p1/Pp2P1P1/1QP5/1P1P2PP/RNB2RK1 b - -
-solution Rxh2
-id "ECM.683"
-go
-setboard 2rq1rk1/pp1bnpbp/4p1p1/3pP1N1/3P2Q1/2PB4/P4PPP/R1B1R1K1 w - -
-solution Nxh7
-id "ECM.684"
-go
-setboard 2rq1bk1/1br2p1p/p2p2p1/1p1P4/4Q3/PP3N2/1BP5/1K1R3R w - -
-solution Rxh7
-id "ECM.685"
-go
-setboard r2qn1k1/pb4Pp/1pn5/2p5/2P2p2/P1PB4/5PPP/R2Q1RK1 w - -
-solution Bxh7+
-id "ECM.686"
-go
-setboard r4rk1/pp1n1ppp/3qp3/3nN1P1/b2P4/P2B1Q2/3B1P1P/1R2R1K1 w - -
-solution Bxh7+
-id "ECM.687"
-go
-setboard r2r2k1/ppqbbppp/4pn2/6N1/n1P4P/3B1N2/PP2QPP1/1KBR3R w - -
-solution Nxh7
-id "ECM.688"
-go
-setboard r5k1/6bp/2q1p1p1/p2pP3/3P4/1rP2QP1/3B1PK1/2R4R w - -
-solution Rxh7
-id "ECM.689"
-go
-setboard r6r/4ppk1/p2p1bp1/B2p4/3P2p1/QP2P3/P1R1qPPP/2R3K1 b - -
-solution Rxh2
-id "ECM.690"
-go
-setboard 4nrk1/r4p1p/p2p2pQ/2pPpNPP/qpn1P3/5P1R/PPP1N3/2K3R1 w - -
-solution Qxh7+
-id "ECM.691"
-go
-setboard r3k2r/1b1n1p2/pq1p1bp1/1p4p1/P3P3/1NN5/1PP3PP/R2QRB1K b kq -
-solution Rxh2+
-id "ECM.692"
-go
-setboard r2qrnk1/4bppp/b1p5/1p1p2P1/p2P1N1P/2NBP3/PPQ2P2/2K3RR w - -
-solution Bxh7+
-id "ECM.693"
-go
-setboard rn1q1rk1/pppbb1pp/4p3/3pP1p1/3P3P/2NB4/PPP2PP1/R2QK2R w KQ -
-solution Bxh7+
-id "ECM.694"
-go
-setboard 1r2nr1k/6pp/pp1p1p2/2pPnN2/q1P1PB2/5PR1/4K1P1/2Q4R w - -
-solution Bxe5
-id "ECM.695"
-go
-setboard 3r1rk1/4qp1p/p1bb2p1/2p5/3P4/1P6/PBQN1PPP/2R2RK1 b - -
-solution Bxh2+
-id "ECM.696"
-go
-setboard r2q1rk1/3n1ppp/8/1pbP2P1/p1N4P/PnBBPQ2/5P2/R3K2R w KQ -
-solution Bxh7+
-id "ECM.697"
-go
-setboard 2k3r1/ppq2p1p/n1Pb1p2/8/6r1/4BN1b/PPQ2PPP/R3RBK1 b - -
-solution Bxh2+
-id "ECM.698"
-go
-setboard 3qr1k1/1br2ppp/p2b4/8/PpNp4/3P4/1PP2PPP/R1BQ1RK1 b - -
-solution Bxh2+
-id "ECM.699"
-go
-setboard 3r2k1/p1R2p2/4pQp1/1q5p/5P1P/1PR5/2Pr2P1/6K1 b - -
-solution Rxg2+
-id "ECM.700"
-go
-setboard r1b4r/3p1kp1/pp3q1p/4RP2/8/B7/P5PP/4QRK1 w - -
-solution Qe4
-id "ECM.701"
-go
-setboard 1r2rnk1/2R2bpp/p2q4/1p1N2R1/5P2/1Q1B3P/PP4P1/7K w - -
-solution Rxg7+
-id "ECM.702"
-go
-setboard 3r2k1/pb5p/1p2qpp1/8/2p5/1P1nP3/P1N2PPP/1Q1R1R1K b - -
-solution Bxg2+
-id "ECM.703"
-go
-setboard 4rrk1/2qb2pp/p5P1/1p2p3/1b2P3/2N5/PPPQ4/1K1R2R1 w - -
-solution gxh7+
-id "ECM.704"
-go
-setboard 3q1k2/pp3ppn/2p1n2p/4pN1N/P3P2P/5Q2/1PP2PP1/6K1 w - -
-solution Nhxg7
-id "ECM.705"
-go
-setboard 2r2r1k/3b1pb1/p3pp1p/q2p1P1B/8/2N2RR1/P1PQ2PP/7K w - -
-solution Rxg7
-id "ECM.706"
-go
-setboard 5bk1/1p4p1/4N1R1/3p4/p1r2P1q/Pr1QP2P/1P6/1K4R1 w - -
-solution Rxg7+
-id "ECM.707"
-go
-setboard 2r1r1k1/5ppp/p3pn2/1pb1N3/2P5/1PQ3R1/PB2qPPP/3R2K1 w - -
-solution Rxg7+
-id "ECM.708"
-go
-setboard 7k/1bp1P1p1/3p2rp/1pb2p1q/5P2/1BP2N1P/1P4P1/R1B2R1K b - -
-solution Rxg2
-id "ECM.709"
-go
-setboard r1q1bk1r/1p3pp1/4pn1p/p3Q3/P1P2N2/1B4R1/1P3PPP/4R1K1 w - -
-solution Rxg7
-id "ECM.710"
-go
-setboard r4rk1/p2n2p1/1q1Qpn1p/1P6/P6B/2p5/2B1KP1P/R5R1 w - -
-solution Rxg7+
-id "ECM.711"
-go
-setboard r2qr1k1/1p3ppp/2pb4/2Np4/1P1P2bn/3BP3/2QN1PPP/1RR3K1 b - -
-solution Nxg2
-id "ECM.712"
-go
-setboard r3r1k1/pp3pp1/3p4/2q4p/2P5/1PB2Q1P/n4PP1/3R1RK1 w - -
-solution Bxg7
-id "ECM.713"
-go
-setboard r5k1/pn1q1rpp/2pp4/5R1N/bP6/4BQ2/P4PPP/2R3K1 w - -
-solution Nxg7
-id "ECM.714"
-go
-setboard 3r1rk1/5pp1/pq1n1n1p/2pPR3/2B2P2/1PBQ2RP/P5P1/6K1 w - -
-solution Rxg7+
-id "ECM.715"
-go
-setboard rn3rk1/ppq2ppp/2pb1nb1/5N2/2BP4/8/PPP1N1P1/R1B1QR1K w - -
-solution Nxg7
-id "ECM.716"
-go
-setboard r1qb1r1k/2p3pp/p1n1bp2/1p1Np2Q/P3P3/1BP3R1/1P3PPP/R1B3K1 w - -
-solution Rxg7
-id "ECM.717"
-go
-setboard r4rk1/5ppp/p2pbb2/3B3Q/qp2p3/4B3/PPP2P1P/2KR2R1 w - -
-solution Rxg7+
-id "ECM.718"
-go
-setboard 4q1k1/1b3r1p/p4pp1/1p6/2P2n2/1P3N2/1B3PPP/R2Q3K b - -
-solution Nxg2
-id "ECM.719"
-go
-setboard r2r3k/5bp1/2p2N2/5P1p/3q3Q/3B2R1/n5PP/3R3K w - -
-solution Rxg7
-id "ECM.720"
-go
-setboard 4rrk1/2pn2pb/p1p1qp2/1pb1pN2/P3P1PN/1P1P4/1BP2PK1/R2Q3R w - -
-solution Nxg7
-id "ECM.721"
-go
-setboard r3r1k1/p3bppp/q1b2n2/5Q2/1p1B4/1BNR4/PPP3PP/2K2R2 w - -
-solution Rg3
-id "ECM.722"
-go
-setboard r4rk1/1p1q1ppp/p1b4B/8/2R3R1/P2P4/1b1N1QPP/6K1 w - -
-solution Bxg7
-id "ECM.723"
-go
-setboard rq3rk1/3b1ppp/p2bp3/3pB2Q/8/1B5P/PP3PP1/2RR2K1 w - -
-solution Bxg7
-id "ECM.724"
-go
-setboard 4kbr1/pp1bpp1p/3p1p2/3N4/1PBQP3/q7/P1r2PPP/R4RK1 b - -
-solution Rxg2+
-id "ECM.725"
-go
-setboard 2r3k1/1p2R1p1/p3n2p/2pq4/7P/1P1P2P1/PB1Q3K/8 w - -
-solution Bxg7
-id "ECM.726"
-go
-setboard 2rr2k1/4bppp/p1n1p3/3q4/1p1P2N1/2P3R1/P3QPPP/2B2RK1 w - -
-solution Nh6+
-id "ECM.727"
-go
-setboard rq1r1bk1/1b3pp1/3pn2p/1n2BN1P/1P2P3/3R1NP1/3Q1PB1/2R3K1 w - -
-solution Bxg7
-id "ECM.728"
-go
-setboard r1b5/ppqn2bk/3R2pp/2p2p2/2P1rN2/4BN2/PPQ2PPP/4R1K1 w - -
-solution Rxg6
-id "ECM.729"
-go
-setboard 3q1r2/1p1b1pk1/pn5p/3pN1pQ/3P3P/2r3B1/P4PP1/3RR1K1 w - -
-solution Nxf7
-id "ECM.730"
-go
-setboard r1bqkbnr/pp2ppp1/2p4p/3n2N1/2BP4/5N2/PPP2PPP/R1BQK2R w KQkq -
-solution Nxf7
-id "ECM.731"
-go
-setboard r2qr1k1/1ppb1p1p/p1np2p1/7Q/3PP2b/1B2N2P/PP3PP1/R1B2RK1 w - -
-solution Bxf7+
-id "ECM.732"
-go
-setboard 2r3k1/pbq1np1p/1p1b1Bp1/8/6QP/2P2N2/B4PP1/4R1K1 w - -
-solution Bxf7+
-id "ECM.733"
-go
-setboard r3r1k1/1bqn1ppp/1pp2p2/8/3P4/1B4N1/PP3PPP/R2QR1K1 w - -
-solution Bxf7+
-id "ECM.734"
-go
-setboard r3r1k1/pp3ppp/8/1Nbp3q/3NnBn1/2P5/PPQ2PPP/3R1RK1 b - -
-solution Ngxf2
-id "ECM.735"
-go
-setboard r2r2k1/1b2qpp1/1p2n3/p1b1p2p/4P1n1/PP1B2PP/1B1NQP2/R3NRK1 b - -
-solution Nxf2
-id "ECM.736"
-go
-setboard r2qr1k1/1b2bp1p/p3p1p1/1p2N1Bn/3P4/P6Q/1P3PPP/RB2R1K1 w - -
-solution Nxf7
-id "ECM.737"
-go
-setboard r5k1/1pp3pp/1b1p1r2/pN1P1n2/P1P3nq/6N1/1P1B1PQP/4RRK1 b - -
-solution Nxf2
-id "ECM.738"
-go
-setboard 2rqnk1r/pp2bpp1/2p1pn1p/2P1N2P/3P1BP1/3BQ3/PP6/2K2R1R w - -
-solution Nxf7
-id "ECM.739"
-go
-setboard 2rq1rk1/1b2bppp/p1n5/1p1BN3/5B2/P7/1P3PPP/R2Q1RK1 w - -
-solution Nd7
-id "ECM.740"
-go
-setboard 3r1qrk/p1p5/bbp3pp/4p3/4Pp1N/2Pn3P/PPQN1PPB/R4RK1 b - -
-solution Nxf2
-id "ECM.741"
-go
-setboard r2qr1k1/pb2bp1p/1pn1p1pB/8/2BP4/P1P2N2/4QPPP/3R1RK1 w - -
-solution d5
-id "ECM.742"
-go
-setboard r3r1k1/1bq1nppp/p1np4/1ppBpN2/4P3/2PP1N2/PP3PPP/R2QR1K1 w - -
-solution Bxf7+
-id "ECM.743"
-go
-setboard r5k1/p4ppp/3qpb2/1P2N3/1nBP4/1P5P/4QPP1/4R1K1 w - -
-solution Nxf7
-id "ECM.744"
-go
-setboard r2qr1k1/1b1nbp1p/p3pp2/1p2N3/3P4/3B1N2/PP2QPPP/R2R2K1 w - -
-solution Nxf7
-id "ECM.745"
-go
-setboard r3k2r/p1qb1p2/1p2p2p/3pPpN1/P1nP3Q/8/2P2PPP/R1B1R1K1 w kq -
-solution Nxf7
-id "ECM.746"
-go
-setboard 3qNk2/5p1p/1r3p2/2p5/Q1pb4/3b2P1/P4PBP/4R1K1 b - -
-solution Bxf2+
-id "ECM.747"
-go
-setboard 2r1r1k1/1pq1bp1p/p3pnp1/P2n2N1/7R/2P4P/1PB1QPP1/2B1R1K1 w - -
-solution Nxf7
-id "ECM.748"
-go
-setboard r1bq2k1/pp1n1ppp/3b1n2/PQ1B3r/3N1P2/2N5/1PP3PP/R1B2RK1 w - -
-solution Bxf7+
-id "ECM.749"
-go
-setboard 2r1r1k1/5ppp/pq3b2/2pB1P2/2p2B2/5Q1P/Pn3PP1/2R1R1K1 w - -
-solution Bxf7+
-id "ECM.750"
-go
-setboard r4rk1/ppRn1p2/6pb/2P1pq1p/3N4/P1QPn1Pb/1B1NPP1P/4R1KB b - -
-solution Qxf2+
-id "ECM.751"
-go
-setboard r3kr2/1b2qp2/pp2p2N/4p2Q/8/2n5/P3B1PP/3R1R1K w q -
-solution Nxf7
-id "ECM.752"
-go
-setboard b2r1rk1/pq2bpp1/1p2p2p/4N2n/2P2R2/1PB2N2/1P2QPPP/4R1K1 w - -
-solution Rxf7
-id "ECM.753"
-go
-setboard rqb1k2r/1p1nbp1p/p4pp1/8/1PBN1P2/P1N1P3/7P/2RQ1RK1 w kq -
-solution Bxf7+
-id "ECM.754"
-go
-setboard r2r2k1/4ppbp/5np1/p1q5/QnB1P3/5N2/1P3PPP/R1B2RK1 w - -
-solution Bxf7+
-id "ECM.755"
-go
-setboard 1r2q1k1/p3pp2/3p1bp1/2pP2N1/8/P5PB/2Q2PK1/1rBR4 w - -
-solution Nxf7
-id "ECM.756"
-go
-setboard 2rqrbk1/pb1n1p1p/1p2pnp1/4N3/2BP1N2/1P2Q3/PB3PPP/3R1RK1 w - -
-solution Nxf7
-id "ECM.757"
-go
-setboard 1r4k1/p4pp1/bqnrpn1p/2ppN3/2P2P1B/P3P3/1P2B1PP/1Q1R1RK1 w - -
-solution Bxf6
-id "ECM.758"
-go
-setboard r1bqrbk1/5p1p/2pp2nB/pp5Q/4P3/PBNPR2P/1P4P1/R5K1 w - -
-solution Bxf7+
-id "ECM.759"
-go
-setboard r1bqkb1r/1p3ppp/pn1P1n2/4p3/2B5/2N2N2/PP3PPP/R1BQ1RK1 w kq -
-solution Bxf7+
-id "ECM.760"
-go
-setboard 2rqr1k1/pp2nppp/3p2b1/6B1/2BNn1Q1/P7/1PP2PPP/2KRR3 w - -
-solution Bxf7+
-id "ECM.761"
-go
-setboard r3r1k1/pbq1ppbp/1pp2np1/4N3/3P4/2P5/PPB1QPPP/R1B1R1K1 w - -
-solution Nxf7
-id "ECM.762"
-go
-setboard r1b2rk1/p6p/2p3Pb/3pp1q1/8/2PB4/PP3PP1/RN1Q1K1R b - -
-solution Rxf2+
-id "ECM.763"
-go
-setboard r2rn3/1p3pk1/p1pNn1pp/q3P3/P7/1PN4P/2QR1PP1/3R2K1 w - -
-solution Nxf7
-id "ECM.764"
-go
-setboard r1bqr1k1/1p1nnpb1/p5pp/2P1p1B1/B3N3/5N2/P4PPP/2RQR1K1 w - -
-solution Nd6
-id "ECM.765"
-go
-setboard r1b1r1k1/pp2qpbp/2p3p1/2P5/3NnB2/7P/PPQ1PPB1/2RR2K1 b - -
-solution Nxf2
-id "ECM.766"
-go
-setboard rn2r1k1/pp3p1p/3P2p1/2p1bbB1/2B5/2N5/Pq4PP/R2Q1RK1 w - -
-solution Bxf7+
-id "ECM.767"
-go
-setboard 5rk1/r2qnppp/p1nN4/2Q5/3PB3/4P3/6PP/R4RK1 w - -
-solution Nxf7
-id "ECM.768"
-go
-setboard 1bq2k2/1b1n1pp1/pp5p/2pBpN2/P3P2B/3Q1P2/1PP3PP/4K3 w - -
-solution Bxf7
-id "ECM.769"
-go
-setboard rnb2rk1/pp3pbp/2p3pB/2q5/4P3/1BN5/PPP3PP/R2Q1R1K w - -
-solution Rxf7
-id "ECM.770"
-go
-setboard 3qr1k1/1br1bp1p/p3p1pB/1p1nN3/3PB3/7Q/PP3PPP/3RR1K1 w - -
-solution Nxf7
-id "ECM.771"
-go
-setboard 1qr1b1k1/4bpp1/pn2p2p/1p1nN3/3P4/P2BBN1Q/1P3PPP/4R1K1 w - -
-solution Bxh6
-id "ECM.772"
-go
-setboard rr1q2k1/1p2bpp1/2p1p2p/P1Pn4/2NP4/3Q1RP1/5PKP/2B1R3 w - -
-solution Bxh6
-id "ECM.773"
-go
-setboard r2r2k1/pb1nbpp1/1qp1pn1p/1p2N3/3P1B2/P1N1P3/BPQ2PPP/2R2RK1 w - -
-solution Bxh6
-id "ECM.774"
-go
-setboard 2r5/1p4bk/3p2rp/4pN2/1P2P1pR/2P2q2/QP6/1K5R w - -
-solution Rxh6+
-id "ECM.775"
-go
-setboard r1b1r3/pp2Npbk/3pp2p/q5p1/2QNPP2/6P1/PPP3P1/2KR3R w - -
-solution Ndf5
-id "ECM.776"
-go
-setboard r1q3r1/1ppQ2pk/3bNp1p/p3pP2/P3P3/7R/1PP3PP/3R2K1 w - -
-solution Rxh6+
-id "ECM.777"
-go
-setboard 4r1k1/p1pq1pp1/2p5/3p1b2/Q7/2P1B2P/P1P1rPP1/2R2RK1 b - -
-solution Bxh3
-id "ECM.778"
-go
-setboard 1rbqnr2/5p1k/p1np3p/1p1Np3/4P2P/1Q2B3/PPP1BP2/2KR3R w - -
-solution Bxh6
-id "ECM.779"
-go
-setboard r1br2k1/p1q2pp1/4p1np/2ppP2Q/2n5/2PB1N2/2P2PPP/R1B1R1K1 w - -
-solution Bxh6
-id "ECM.780"
-go
-setboard 3r1r1k/p5p1/n1p2p1p/1qp2b2/N1R4R/1PB1P1P1/P2P3P/3Q2K1 w - -
-solution Rxh6+
-id "ECM.781"
-go
-setboard r4rk1/2q1b1p1/p4p1p/n3pP2/1p2Q1N1/4B3/PPP3PP/4RR1K w - -
-solution Nxh6+
-id "ECM.782"
-go
-setboard 6rk/3b1n1p/1p1q3b/1PpNp3/2P1Pp2/2Q2NrP/5RP1/2R2B1K b - -
-solution Bxh3
-id "ECM.783"
-go
-setboard r2q1rk1/ppp2pp1/1b2b2p/3n3Q/2Bp4/3P1N2/PPP2PPP/R1B1R1K1 w - -
-solution Bxh6
-id "ECM.784"
-go
-setboard r3rbk1/1bp1qpp1/p6p/np2p2Q/4P2N/1BP4P/PP3PP1/R1B1R1K1 w - -
-solution Bg5
-id "ECM.785"
-go
-setboard 4q3/p2r1ppk/R6p/3n4/3B1Q2/4P2P/5PP1/6K1 w - -
-solution Rxh6+
-id "ECM.786"
-go
-setboard 7r/1p2qk2/pQ1p2p1/3Ppp2/P4b2/2P2PrP/1P2R1B1/4R2K b - -
-solution Rhxh3+
-id "ECM.787"
-go
-setboard 5rk1/Qp5p/3pp1p1/4n3/2P1P2q/5r1P/P3NPP1/3R1RK1 b - -
-solution Rxh3
-id "ECM.788"
-go
-setboard 2r1r1k1/pb1n1pp1/1p1qpn1p/4N1B1/2PP4/3B4/P2Q1PPP/3RR1K1 w - -
-solution Bxh6
-id "ECM.789"
-go
-setboard 3q1rk1/p2bbpp1/1rn4p/1pp2P2/3pBBP1/3P3P/PPPQ3N/R4RK1 w - -
-solution Bxh6
-id "ECM.790"
-go
-setboard 2br2k1/4qppp/p5r1/2pBp3/2P1Pn2/4Q2P/RP3PPK/1N4R1 b - -
-solution Bxh3
-id "ECM.791"
-go
-setboard r2qr3/2p1b1pk/p5pp/1p2p3/nP2P1P1/1BP2RP1/P3QPK1/R1B5 w - -
-solution Bxh6
-id "ECM.792"
-go
-setboard r5r1/pbn4k/1p1p1Ppp/2pPn3/4BQq1/1PN3P1/PB3PK1/3R1R2 w - -
-solution Qxh6+
-id "ECM.793"
-go
-setboard r1b2rk1/pp2bpp1/4p2p/2q4Q/5nNB/2PB4/PP3PPP/2KR3R w - -
-solution Nxh6+
-id "ECM.794"
-go
-setboard 6k1/p4ppp/1pn1b1rr/8/PBpPp2q/2P1P1NP/5PP1/RR3QK1 b - -
-solution Bxh3
-id "ECM.795"
-go
-setboard r1b2rk1/1p3pp1/p5Pp/2bpPp1Q/3N4/1Pq1B1R1/2P4P/3R2K1 w - -
-solution Bxh6
-id "ECM.796"
-go
-setboard r2r2k1/pp1n1bp1/2p2p1p/b4N2/q2BR3/2QB2PP/1PP5/2KR4 w - -
-solution Nxh6+
-id "ECM.797"
-go
-setboard 3r2bk/1q4p1/p2P1N1p/2p1rP2/pb5R/7P/1P4P1/2Q2RK1 w - -
-solution Rxh6+
-id "ECM.798"
-go
-setboard 2b1rk2/r6p/1pP1p1p1/p2pNnR1/5Q2/P1B4q/1PP2P1P/1K4R1 w - -
-solution Nxg6+
-id "ECM.799"
-go
-setboard 6R1/6Q1/3q2p1/5p1p/P3p1k1/1P1r2P1/5PK1/8 b - -
-solution Rxg3+
-id "ECM.800"
-go
-setboard r6r/ppnqpk2/3pbpp1/5N2/1PP1P3/5RR1/P2QB1PP/6K1 w - -
-solution Nh6+
-id "ECM.801"
-go
-setboard 3r3r/p4pk1/5Rp1/3q4/1p1P2RQ/5N2/P1P4P/2b4K w - -
-solution Rfxg6+
-id "ECM.802"
-go
-setboard 2b2r1k/2p3pp/2Nb4/pP5q/2PP4/P4pP1/5P1P/R1BQ2K1 b - -
-solution Bxg3
-id "ECM.803"
-go
-setboard r1bq2k1/pp3r1p/2n1p1p1/3pP3/6Q1/2PB2P1/P4PK1/R1B4R w - -
-solution Bxg6
-id "ECM.804"
-go
-setboard 3q1rk1/2r4p/n1p1n1pQ/p2pP3/Np1P2R1/5PN1/PP3KP1/2R5 w - -
-solution Rxg6+
-id "ECM.805"
-go
-setboard 2Nq1rk1/6pp/b1p2b2/p6Q/np1p4/6P1/PB3PBP/R3R1K1 w - -
-solution Be4
-id "ECM.806"
-go
-setboard r2r4/p4pk1/2p3p1/1p1nPR2/5p1Q/2N5/PPPq4/1K4R1 w - -
-solution e6
-id "ECM.807"
-go
-setboard 2kr3r/pbq3p1/1p2pp2/2b4n/2P1B3/1P1N2Pp/PB2QP1P/R4RK1 b - -
-solution Nxg3
-id "ECM.808"
-go
-setboard r5k1/1p2Rpb1/3p1np1/2nP2B1/1qP5/1pN1Q2P/P5P1/1B4K1 w - -
-solution Bxg6
-id "ECM.809"
-go
-setboard 2rqr1k1/pb2bp1p/1pn1pnpB/4N3/3P4/P1N3R1/1P3PPP/RB1Q2K1 w - -
-solution Rxg6+
-id "ECM.810"
-go
-setboard 2r5/pp2qr1k/1nb3pp/2ppBp2/2P4P/3B2R1/P3QPP1/1R4K1 w - -
-solution Rxg6
-id "ECM.811"
-go
-setboard 3rr3/3q1p1k/p2P2pp/1bp1b3/5N2/6QP/P1B3P1/3RR1K1 w - -
-solution Bxg6+
-id "ECM.812"
-go
-setboard r2q1rk1/pp2ppb1/3pn1pQ/3R4/2P3B1/4BR2/PP4PP/6K1 w - -
-solution Qxg6
-id "ECM.813"
-go
-setboard 1n1b1rk1/r4p1p/p1p2qpQ/P3Np2/2BP4/2P1R3/5PPP/R5K1 w - -
-solution Rb1
-id "ECM.814"
-go
-setboard 6rk/pb3p1p/3bpPq1/3P4/1p1B3r/1B4P1/PPRQ1R1P/6K1 b - -
-solution Bxg3
-id "ECM.815"
-go
-setboard 3rr1k1/pb2bp1p/3qp1pB/1p2N3/3P2Q1/2P1R3/P4PPP/4R1K1 w - -
-solution Nxg6
-id "ECM.816"
-go
-setboard r2q1rk1/pb1nbp1p/1p2p1p1/4N1BQ/2PP4/P7/5PPP/RB2R1K1 w - -
-solution Nxg6
-id "ECM.817"
-go
-setboard 1Q4R1/r2qbp2/3p1kp1/3Bp2p/8/3PP1P1/5PKP/8 w - -
-solution Rxg6+
-id "ECM.818"
-go
-setboard r3r1k1/b1p2pn1/p2q1Bp1/1p1bN1Qp/3P4/2P4P/PPB2PP1/R3R1K1 w - -
-solution Nxg6
-id "ECM.819"
-go
-setboard 3r2k1/p1rn1p1p/1p2pp2/6q1/3PQNP1/5P2/P1P4R/R5K1 w - -
-solution Nxe6
-id "ECM.820"
-go
-setboard k2r3r/ppq2p1p/n1pb1Pp1/4p3/2Q5/1R2B1P1/PPP2PBP/R5K1 w - -
-solution Rxb7
-id "ECM.821"
-go
-setboard 1rb2rk1/p1p1qppp/2p2n2/3P4/1b3P2/2NB4/PPPBQ1PP/2KR3R b - -
-solution Ba3
-id "ECM.822"
-go
-setboard k7/pp1N4/4P3/5P2/8/5p2/1R6/B4Knq w - -
-solution Nb6+
-id "ECM.823"
-go
-setboard 4rrk1/p5pp/1p4q1/3p2n1/2pP2P1/P1P1PP2/3B2K1/1R2QR2 b - -
-solution Nxf3
-id "ECM.824"
-go
-setboard 1q1r3k/3P1pp1/ppBR1n1p/4Q2P/P4P2/8/5PK1/8 w - -
-solution Rxf6
-id "ECM.825"
-go
-setboard 1rbq2k1/b1p3pp/p1Pp4/3Ppr2/8/5N2/PPQ2PPP/R1B2RK1 b - -
-solution Rxf3
-id "ECM.826"
-go
-setboard 1r1q1r1k/2p3pp/1p1bQ3/p7/1PP5/Pn3B2/1B3PPP/R4RK1 b - -
-solution Rxf3
-id "ECM.827"
-go
-setboard r4rk1/2p1qpp1/p1p5/2Ppn2b/2PQ1N1p/4P3/PB3PPP/R4RK1 b - -
-solution Nf3+
-id "ECM.828"
-go
-setboard r1bq1rk1/1p2bppp/p3p3/n3P3/4N3/1P1P1N2/PB4PP/R3QR1K w - -
-solution Nf6+
-id "ECM.829"
-go
-setboard 1n2r3/p1pq1kp1/1b1pNpp1/3P4/5RP1/3Q3P/1B3P2/6K1 w - -
-solution Bxf6
-id "ECM.830"
-go
-setboard r1bq1rk1/ppp3p1/7p/3P2n1/2PQ1p2/1N5P/PPP2PPK/R1B2R2 b - -
-solution Nf3+
-id "ECM.831"
-go
-setboard 3r1b2/p4bkp/1p1P1p2/r3p1p1/2q1N3/2N2P2/1P1R2PP/2QR3K w - -
-solution Nxf6
-id "ECM.832"
-go
-setboard rqbn1rk1/1p3ppp/p3p3/8/4NP2/8/PPP1BQPP/1K1R3R w - -
-solution Nf6+
-id "ECM.833"
-go
-setboard r1b1kb1r/1p4pp/p2ppn2/8/2qNP3/2N1B3/PPP3PP/R2Q1RK1 w kq -
-solution Rxf6
-id "ECM.834"
-go
-setboard 1rn5/p3Bk1p/1pq1bpp1/P3p3/1Q2P2P/2P3P1/5PB1/1R4K1 w - -
-solution Bxf6
-id "ECM.835"
-go
-setboard 2nr2k1/1pq1bppp/p1p5/2p1P1PQ/2P1NP2/1PNR4/P6P/6K1 w - -
-solution Nf6+
-id "ECM.836"
-go
-setboard 6nk/pn2qr1r/1pbp1p1p/2p1pPpN/P1P1P1PP/2PP3R/7Q/2BBK2R w K -
-solution Nxf6
-id "ECM.837"
-go
-setboard 7r/4p1k1/p3Pppp/1p6/3N1R2/3PQ2P/qr4b1/5RK1 w - -
-solution Rxf6
-id "ECM.838"
-go
-setboard r3k2r/1bq1bp2/p3p1pp/1p2P3/3NpP2/4B1Q1/PPP3PP/1K1R3R w kq -
-solution Nxe6
-id "ECM.839"
-go
-setboard rnbqkb1r/pp1n1p2/4p1p1/1N1pP2p/1P4Q1/3B1N2/P1PB1PPP/R3K2R w KQkq -
-solution Qxe6+
-id "ECM.840"
-go
-setboard r1b1kb1r/1p1n1ppp/p2ppn2/6BB/2qNP3/2N5/PPP2PPP/R2Q1RK1 w kq -
-solution Nxe6
-id "ECM.841"
-go
-setboard r1b1k1nr/3n1p1p/1qpBp1p1/pp2b3/4PN2/PBN2Q2/1PP2PPP/2KR3R w kq -
-solution Nxe6
-id "ECM.842"
-go
-setboard 2r2rk1/1b3ppp/pq2p3/1pbn2N1/3B3P/1B4P1/P1P1QP2/2KRR3 w - -
-solution Qh5
-id "ECM.843"
-go
-setboard r3k2r/pp1n1pb1/1qn1p1p1/2p3Pp/4R2P/2NP2QB/PPPB1P2/2K1R3 w kq -
-solution Rxe6+
-id "ECM.844"
-go
-setboard r3k2r/1q3ppp/p3p3/2b1P3/p2N1Q2/P7/1PP3PP/3R1R1K w kq -
-solution Nxe6
-id "ECM.845"
-go
-setboard 3qr1k1/rp3pbp/2p3p1/3p1b2/N1nP4/P2NP3/1PQ2PPP/1BRR2K1 b - -
-solution Rxe3
-id "ECM.846"
-go
-setboard rnbqkb1r/1p1n1pp1/p3p2p/3pP3/3p1NQP/2N5/P1PB1PP1/R3KB1R w KQkq -
-solution Nxe6
-id "ECM.847"
-go
-setboard 3r1b1R/3bkpp1/1p1np3/1BqpPPP1/PQ1N4/8/1PP5/1K6 w - -
-solution f6+
-id "ECM.848"
-go
-setboard 4r1k1/pp2n2p/1r1n1bp1/q2p1pB1/3P3N/P1NQ1P1P/1PP3R1/1K5R b - -
-solution Rxb2+
-id "ECM.849"
-go
-setboard 3r2k1/2p1bppp/4b3/p2pP3/qr1N1B1P/8/1PPQ2P1/1K1RR3 b - -
-solution Rxb2+
-id "ECM.850"
-go
-setboard 1k1r3r/ppR2ppp/1q2b3/1N6/4Q3/8/PP3PPP/4R1K1 w - -
-solution Rxb7+
-id "ECM.851"
-go
-setboard 1r3rk1/5pbp/p2Pp1p1/q1n3P1/2p2P1P/2N1Q2R/PP6/1BKR4 b - -
-solution Rxb2
-id "ECM.852"
-go
-setboard rr4k1/5p1p/n2p1npQ/q1pP4/6P1/2N2P1N/PP1R3P/2K4R b - -
-solution Rxb2
-id "ECM.853"
-go
-setboard 1k2bb1r/1p3p1p/p2qpP1p/3pN3/3P1Q2/2RB2P1/PP3P1P/6K1 w - -
-solution Qc1
-id "ECM.854"
-go
-setboard 1r4k1/1r3p2/p1p1b1pQ/q3P3/P7/bPN1R1P1/2P4P/1K1R1B2 b - -
-solution Bxb3
-id "ECM.855"
-go
-setboard 5rk1/5rp1/p2qb3/R2Np2Q/3bP2B/7P/P5PK/1R6 b - -
-solution Rf1
-id "ECM.856"
-go
-setboard 6k1/5p2/R3p1p1/1pq1PpB1/4nP2/5Q1P/P2r2PK/8 w - -
-solution Ra8+
-id "ECM.857"
-go
-setboard 3r1rk1/p3q1pp/2Rb4/3P4/8/1P2Qp2/PB3PPP/3R2K1 b - -
-solution Bxh2+
-id "ECM.858"
-go
-setboard 1r6/5pk1/p1b2qpp/P1P1n3/1N6/Q5NP/5PP1/3R2K1 b - -
-solution Bxg2
-id "ECM.859"
-go
-setboard 1r4k1/1q3pb1/r1b3p1/pp1Qp3/P3P3/1B2BP2/1PP3P1/1K1R3R w - -
-solution Qd8+
-id "ECM.860"
-go
-setboard 2R5/p3q1kp/6p1/3p4/b2P2p1/Pr4N1/5Q2/3K3R w - -
-solution Nf5+
-id "ECM.861"
-go
-setboard 3r4/kb6/pp6/4R1pr/PPpq4/2N3Q1/2P3PP/3R3K b - -
-solution Rf8
-id "ECM.862"
-go
-setboard 4r1k1/5p1p/4q1p1/8/Q5n1/3B2P1/P4P1P/2R3K1 b - -
-solution Nxf2
-id "ECM.863"
-go
-setboard 8/2q1np1k/6p1/1PPn3p/8/P2Q3P/6P1/2R4K b - -
-solution Nf5
-id "ECM.864"
-go
-setboard r1bq1rk1/ppp1n1bn/3p2p1/3Pp1Pp/1PP1Pp1P/2NN1P2/P3B3/R1BQ1RK1 b - -
-solution Nxg5
-id "ECM.865"
-go
-setboard 7R/1p1r4/2b2p2/2Pp1qk1/3P1bp1/3N4/2Q2PB1/6K1 w - -
-solution Rg8+
-id "ECM.866"
-go
-setboard r6r/1pn1b1k1/2p1pq2/2Pp3p/p2P1Pp1/P2BP1P1/1P2QB2/3R2KR w - -
-solution Rxh5
-id "ECM.867"
-go
-setboard 1r4k1/pp4pp/2n1b3/1Rq1p3/2P2r2/P1B2P2/2Q1B1PP/3R1K2 b - -
-solution Rxf3+
-id "ECM.868"
-go
-setboard 7k/1p4p1/2p4r/5p2/p1QP1q2/2P2PR1/r4P1P/4R2K b - -
-solution Rxh2+
-id "ECM.869"
-go
-setboard 1r3r2/6kp/3p1pp1/qnp1pP2/1p2P2N/3P4/PPPQ1P1P/1K1R2R1 w - -
-solution fxg6
-id "ECM.870"
-go
-setboard 5rk1/1rP3pp/p4n2/3Pp3/1P2Pq2/2Q4P/P5P1/R3R1K1 b - -
-solution Rxc7
-id "ECM.871"
-go
-setboard 2rq1rk1/5ppp/2b1pb2/np6/6N1/2NBB3/PP3PPP/R2Q2K1 w - -
-solution Bb6
-id "ECM.872"
-go
-setboard 5r2/p2p2kp/3PnNp1/1qr1Pp2/2p5/P1R5/6PP/2Q1R1K1 w - -
-solution Qh6+
-id "ECM.873"
-go
-setboard 2Qbq1k1/6p1/1p4Np/4p2P/3rP3/8/3p2PK/3R4 w - -
-solution Rf1
-id "ECM.874"
-go
-setboard 2kr1br1/ppp2p1p/2n1p1q1/2Nn4/3P4/1Q2PB2/PP1B1P1P/2R1K2R b K -
-solution Qg1+
-id "ECM.875"
-go
-setboard 2K5/6p1/kp2P3/1p6/1P6/2P1P2p/8/1r6 w - -
-solution e7
-id "ECM.876"
-go
-setboard 2kr3r/1Rp1bpp1/p6q/Q3P3/2P5/3p1NP1/P3P2P/1R4K1 b - -
-solution Qe3+
-id "ECM.877"
-go
-setboard 6k1/1R4pp/2p5/8/P1rNp3/6Pb/4PK2/8 w - -
-solution a5
-id "ECM.878"
-go
-setboard r2r2k1/pp3ppp/2q5/2p5/2P1P1n1/P4P1b/1BQ1BP1P/R3R2K b - -
-solution Rd2
-id "ECM.879"
-go
diff --git a/src/unix.c b/src/unix.c
index 99216d0..68d2319 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -27,8 +27,6 @@ Revision History:
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/select.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
@@ -1020,44 +1018,54 @@ SystemReleaseLock(ULONG u)
}
+/*
+ * These "semaphores" only ever signal between threads of this same
+ * process (see input.c's producer/consumer wait between the stdin
+ * reader thread and the command-dispatch thread) -- there is no
+ * cross-process handoff here, despite the SysV-semaphore-shaped API.
+ * A SysV semget(IPC_PRIVATE, ...) set is kernel-global, outlives the
+ * process, and only gets torn down by an explicit IPC_RMID -- so a
+ * killed (rather than gracefully quit()'d) process leaks it, and on a
+ * shared box with a low kern.ipc.semmni it doesn't take many leaked
+ * engines to exhaust the system-wide semaphore-set table. Every
+ * subsequent semget() then fails, and _WaitUntilTheresInputToRead
+ * (input.c) silently falls back to 100ms-polling instead of blocking
+ * on a real wait -- a ~1000x slowdown that looks exactly like machine
+ * contention. A pthread_mutex_t/pthread_cond_t pair does the same
+ * counting-semaphore job entirely in-process, with no kernel-persistent
+ * object to leak: the OS reclaims it unconditionally the instant the
+ * process dies, SIGKILL or not.
+ */
#define MAX_SEM (8)
-int g_rgSemaphores[MAX_SEM];
-#ifdef DEBUG
-ULONG g_rgSemValues[MAX_SEM];
-#endif
+
+typedef struct _SEM_ENTRY
+{
+ FLAG fInUse;
+ ULONG uCount;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+}
+SEM_ENTRY;
+
+SEM_ENTRY g_rgSemaphores[MAX_SEM];
ULONG
-SystemCreateSemaphore(ULONG uValue)
+SystemCreateSemaphore(ULONG uValue)
{
ULONG u;
- union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- } value;
if (uValue > MAX_USHORT) return((ULONG)-1);
LOCK_SYSTEM;
- for (u = 0; u < MAX_SEM; u++)
+ for (u = 0; u < MAX_SEM; u++)
{
- if (g_rgSemaphores[u] < 0)
+ if (g_rgSemaphores[u].fInUse == FALSE)
{
- g_rgSemaphores[u] = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
- if (g_rgSemaphores[u] < 0)
- {
- u = (ULONG)-1;
- goto end;
- }
- value.val = uValue;
- if (semctl(g_rgSemaphores[u], 0, SETVAL, value) < 0)
- {
- (void)SystemDeleteSemaphore(u);
- u = (ULONG)-1;
- goto end;
- }
+ pthread_mutex_init(&(g_rgSemaphores[u].lock), NULL);
+ pthread_cond_init(&(g_rgSemaphores[u].cond), NULL);
+ g_rgSemaphores[u].uCount = uValue;
+ g_rgSemaphores[u].fInUse = TRUE;
#ifdef DEBUG
- g_rgSemValues[u] = uValue;
- Trace("Semaphore #%u created, initial value is %u\n",
+ Trace("Semaphore #%u created, initial value is %u\n",
u, uValue);
#endif
goto end;
@@ -1071,82 +1079,60 @@ SystemCreateSemaphore(ULONG uValue)
FLAG
SystemDeleteSemaphore(ULONG u) {
- union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- } value;
FLAG fRet = TRUE;
- memset(&value, 0, sizeof(value));
LOCK_SYSTEM;
- if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0))
+ if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE))
{
- if (semctl(g_rgSemaphores[u], 0, IPC_RMID, value) < 0)
- {
- fRet = FALSE;
- }
- else
- {
- g_rgSemaphores[u] = -1;
- }
+ pthread_mutex_destroy(&(g_rgSemaphores[u].lock));
+ pthread_cond_destroy(&(g_rgSemaphores[u].cond));
+ g_rgSemaphores[u].fInUse = FALSE;
+ }
+ else
+ {
+ fRet = FALSE;
}
UNLOCK_SYSTEM;
return(fRet);
}
void
-SystemReleaseSemaphoreResource(ULONG u)
+SystemReleaseSemaphoreResource(ULONG u)
{
- struct sembuf operation;
-
LOCK_SYSTEM;
- if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0))
+ if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE))
{
- operation.sem_num = u;
- operation.sem_op = +1;
- operation.sem_flg = 0;
- if (semop(g_rgSemaphores[u], &operation, 1) < 0)
- {
- UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
- NULL, "semop", (void *)errno, (void *)0,
- __FILE__, __LINE__);
- }
+ pthread_mutex_lock(&(g_rgSemaphores[u].lock));
+ g_rgSemaphores[u].uCount += 1;
#ifdef DEBUG
- g_rgSemValues[u] += 1;
- Trace("Semaphore #%u value incremented to %u\n", u,
- g_rgSemValues[u]);
+ Trace("Semaphore #%u value incremented to %u\n", u,
+ g_rgSemaphores[u].uCount);
#endif
+ pthread_cond_signal(&(g_rgSemaphores[u].cond));
+ pthread_mutex_unlock(&(g_rgSemaphores[u].lock));
}
UNLOCK_SYSTEM;
}
void
-SystemObtainSemaphoreResource(ULONG u)
+SystemObtainSemaphoreResource(ULONG u)
{
- struct sembuf operation;
-
LOCK_SYSTEM;
- if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0))
+ if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE))
{
- operation.sem_num = u;
- operation.sem_op = -1;
- operation.sem_flg = 0;
+ pthread_mutex_lock(&(g_rgSemaphores[u].lock));
UNLOCK_SYSTEM;
- if (semop(g_rgSemaphores[u], &operation, 1) < 0)
+ while (g_rgSemaphores[u].uCount == 0)
{
- UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
- NULL, "semop", (void *)errno, (void *)1,
- __FILE__, __LINE__);
+ pthread_cond_wait(&(g_rgSemaphores[u].cond),
+ &(g_rgSemaphores[u].lock));
}
+ g_rgSemaphores[u].uCount -= 1;
#ifdef DEBUG
- if (g_rgSemValues[u] > 0)
- {
- g_rgSemValues[u] -= 1;
- Trace("Semaphore #%u value decremented to %u\n", u,
- g_rgSemValues[u]);
- }
+ Trace("Semaphore #%u value decremented to %u\n", u,
+ g_rgSemaphores[u].uCount);
#endif
+ pthread_mutex_unlock(&(g_rgSemaphores[u].lock));
return;
}
UNLOCK_SYSTEM;
@@ -1187,9 +1173,9 @@ Return value:
memset(g_AllocHash, 0, sizeof(g_AllocHash));
#endif
- for (u = 0; u < MAX_SEM; u++)
+ for (u = 0; u < MAX_SEM; u++)
{
- g_rgSemaphores[u] = -1;
+ g_rgSemaphores[u].fInUse = FALSE;
}
InitializeListHead(&g_SystemThreadList);
pthread_mutex_init(&g_SystemLock, NULL);