Skip to content

one_d4: investigate PinDetector false positives/negatives on the King's Gambit game #1079

@aaylward

Description

@aaylward

Background

PinDetector has two detection paths:

  1. Absolute pins — ray-cast from the king outward; finds one friendly piece followed by a compatible enemy sliding piece.
  2. Relative pins — scan every enemy sliding piece, look for two aligned friendly pieces where the second (anchor) is more valuable (anchor > pinned && anchor >= 4).

Deduplication removes entries with the same (attacker, target) pair, and relative pins where the anchor is the king (anchor != 6) are excluded to avoid double-counting absolute pins.

Suspected issues

The King's Gambit test game (_prior vs zapblast, 54 moves) is used in both FullMotifDetectorTest and MotifE2ETest. The pin test in FullMotifDetectorTest uses contains (not containsExactly), intentionally leaving room for additional occurrences that haven't been audited:

assertThat(pins)
    .extracting(GameFeatures.MotifOccurrence::moveNumber, GameFeatures.MotifOccurrence::side)
    .contains(tuple(4, "white"), tuple(30, "black"), tuple(31, "black"),
              tuple(38, "black"), tuple(50, "black"), tuple(51, "black"));

The unresolved questions are:

1. False positives from relative pin detection

The relative-pin scan may fire on positions where a sliding piece threatens two friendly pieces in a line but no real tactical pin exists (e.g. because the "pinned" piece is free to move without material loss). The condition anchor >= 4 (rook or queen) admits many alignments that aren't practically significant pins.

Specifically suspect:

  • Endgame queen-and-rook positions (moves 29–54) where pieces shuffle along ranks/files and the relative-pin scan hits transient alignments.
  • The anchor-value threshold: a pawn pinned in front of a rook by an enemy bishop may or may not be a meaningful pin depending on game phase.

2. Deduplication gap between absolute and relative paths

deduplicatePins removes entries with matching (attacker, target). But an absolute pin and a relative pin involving the same attacker and a different second friendly piece as anchor could both fire without being deduplicated.

3. Pins detected in positions where the piece has already "left" the pin square

PinDetector runs against every PositionContext in the game — one per half-move. A pin created on move N may be re-reported on moves N+1, N+2, … as long as the geometry holds. This is expected, but if the pinned piece moves and the geometry is transiently re-formed by a different piece, it could produce a spurious occurrence.

Suggested investigation steps

  1. Add a FullMotifDetectorTest assertion using containsExactly (or at least record the full set) to enumerate every detected pin occurrence across all 108 half-moves and audit each one manually.
  2. For each suspicious occurrence, extract the FEN and add a targeted PinDetectorTest unit test that asserts the expected count and (attacker, target, pinType).
  3. Consider tightening the relative-pin condition (e.g. requiring the pinned piece to be a knight or bishop, not just any piece cheaper than the anchor) or adding a move-significance heuristic.
  4. Consider whether deduplicatePins should also deduplicate by target square (regardless of attacker) to prevent the same piece from being reported as pinned by two different attackers in the same position.

Acceptance criteria

  • FullMotifDetectorTest has a containsExactly assertion (or equivalent exhaustive list) for all expected pin occurrences in the King's Gambit game.
  • Any false positives found are fixed and covered by new PinDetectorTest FEN-based unit tests.
  • Any false negatives found are fixed and similarly covered.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions