summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-08-30 09:45:06 -0700
committerScott Gasch <[email protected]>2026-08-30 09:45:06 -0700
commitaab2982a2d0ba8edee64538ca26240f89b8eca25 (patch)
tree2070b7168135117d5f418d1f674b76aa6f569880 /src
parentfa210fb9645afd27e2991b3ee8139be231d0b5ec (diff)
Add small static penalties for trapped pieces in _EvalTrappedPieces.
Eval() already detects trapped/attacked pieces (for search hints via RecordEnprisePieceAtPly/RecordTrappedPiece) but never penalized them in the static score. Add two named, DNA-visible constants: a larger flag for the opponent-to-move/imminently-capturable case, a smaller one for the own-move/still-might-escape case -- flat "this is bad" nudges, not an attempt to price the material outcome, which search still owns. Verified flat on ecm_ringers/ecm_confident_quick vs head_reference at sd 10; ecm_hard_quick's lone flip (ECM.370) is a search-instability artifact of that specific position (its true evaluation was still moving through depth 14 in independent runs), not a real regression.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/eval.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/src/eval.c b/src/eval.c
index 424637e..fc22127 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -643,6 +643,16 @@ static SCORE KING_QUEEN_PROXIMITY_DANGER[7] =
};
static SCORE KING_MISSING_ONE_CASTLE_OPTION = -23;
+
+// Flat "this is bad" flags for _EvalTrappedPieces -- not an attempt to
+// price the material outcome (search resolves that), just a nudge away
+// from positions with a piece that looks stuck. ENPRISE_AND_TRAPPED is
+// larger because that case is opponent-to-move / imminently capturable;
+// TRAPPED_WITH_MOVE is our own move, so there's still a chance to
+// wriggle out.
+static SCORE ENPRISE_AND_TRAPPED_PENALTY = -50;
+static SCORE TRAPPED_WITH_MOVE_PENALTY = -10;
+
typedef struct _DNA_BASE_SIZE {
SCORE *pBase;
ULONG uCount;
@@ -5434,9 +5444,7 @@ Return value:
ULONG uColor;
ULONG u;
POSITION *pos = &ctx->sPosition;
-#ifdef DEBUG
PIECE p;
-#endif
FOREACH_COLOR(uColor)
{
@@ -5448,30 +5456,32 @@ Return value:
ASSERT(IS_ON_BOARD(c));
if (_WhoControlsSquareFast(pos, c) == FLIP(uColor))
{
-#ifdef DEBUG
p = pos->rgSquare[c].pPiece;
+#ifdef DEBUG
ASSERT(p);
ASSERT(!IS_PAWN(p));
ASSERT(GET_COLOR(p) == uColor);
#endif
+ // See if the side who created the trap and controls
+ // the square the trapped piece is sitting on has the
+ // move too. If so, uColor moved at ply-1.
if (OPPOSITE_COLORS(uColor, pos->uToMove))
{
- // uColor is the mover at ctx->uPly - 1 (ply
- // parity), not here -- see RecordEnprisePieceAtPly.
if (ctx->uPly > 0)
{
RecordEnprisePieceAtPly(ctx, ctx->uPly - 1, c);
}
+ EVAL_TERM(uColor, p, c, pos->iScore[uColor],
+ ENPRISE_AND_TRAPPED_PENALTY,
+ "en prise and trapped");
}
- else
- {
- //
- // ctx->cTrapped[uPly] (RecordTrappedPiece's target)
- // is a single slot, not a list -- if more than one
- // of our own pieces is genuinely trapped this ply,
- // only report the most valuable one rather than
- // whichever happened to be found last.
- //
+
+ // ctx->cTrapped[uPly] (RecordTrappedPiece's target)
+ // is a single slot, not a list -- if more than one
+ // of our own pieces is genuinely trapped this ply,
+ // only report the most valuable one.
+ else
+ {
if (PIECE_VALUE(pos->rgSquare[c].pPiece) >
uBestOwnTrappedValue)
{
@@ -5479,12 +5489,21 @@ Return value:
PIECE_VALUE(pos->rgSquare[c].pPiece);
cBestOwnTrapped = c;
}
- }
+ }
}
}
+
+ // uColor has the move but we found at least one piece that
+ // seems to have no safe place to move and is actively under
+ // attack now. It may not be lost, at least uColor has the
+ // move. But this is still a bad thing.
if (IS_ON_BOARD(cBestOwnTrapped))
{
RecordTrappedPiece(ctx, cBestOwnTrapped);
+ p = pos->rgSquare[cBestOwnTrapped].pPiece;
+ EVAL_TERM(uColor, p, cBestOwnTrapped, pos->iScore[uColor],
+ TRAPPED_WITH_MOVE_PENALTY,
+ "trapped piece, our move");
}
}
}