Skip to content

Conversation

@luccabb
Copy link
Owner

@luccabb luccabb commented Jan 20, 2026

Summary

  • Add draw detection (fifty-move rule, insufficient material, repetition)
  • Properly handle check positions (search all evasions, not just captures)
  • Add is_tactical_move() helper for cleaner tactical move detection
  • Use best_score tracking instead of just alpha

Details

Draw Detection

The quiescence search now detects draws:

  • Fifty-move rule: board.is_fifty_moves()
  • Insufficient material: board.is_insufficient_material()
  • Repetition: Check board.is_repetition(2) after each move

Check Handling

When in check, the position is unstable and we can't use stand-pat for pruning:

  • Search ALL legal moves (evasions), not just tactical moves
  • Don't use stand-pat beta cutoff
  • Initialize best_score to -inf instead of stand_pat

Tactical Move Detection

New is_tactical_move() function that identifies:

  • Captures (material change)
  • Promotions (significant material gain)
  • Checks (forcing moves)

Previously used is_zeroing() which included quiet pawn pushes.

Test plan

  • All 64 unit tests pass
  • Verified proper handling of check positions

🤖 Generated with Claude Code

@luccabb luccabb force-pushed the feature/syzygy-tablebase-init branch from 82526b0 to 5f456a9 Compare January 21, 2026 06:40
@luccabb luccabb force-pushed the feature/quiescence-search-improvements branch from e8b9ff6 to df8a32b Compare January 21, 2026 06:40
@luccabb luccabb force-pushed the feature/syzygy-tablebase-init branch from 5f456a9 to edb7941 Compare January 21, 2026 06:43
@luccabb luccabb force-pushed the feature/quiescence-search-improvements branch from df8a32b to bfb11c1 Compare January 21, 2026 06:44
@luccabb luccabb changed the base branch from feature/syzygy-tablebase-init to master January 21, 2026 07:00
@luccabb luccabb changed the title [4/9] Improve quiescence search Improve quiescence search Jan 21, 2026
@luccabb luccabb force-pushed the feature/quiescence-search-improvements branch 2 times, most recently from 845a25a to 72e2bf9 Compare January 21, 2026 07:22
Enhances quiescence search with better draw detection and check handling:

- Add draw detection: fifty-move rule, insufficient material, repetition
- Proper check handling: when in check, search all evasions instead of
  only tactical moves (position is unstable, can't use stand-pat)
- Add is_tactical_move() helper for cleaner move filtering
- Update organize_moves_quiescence() to use tactical move detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@luccabb luccabb force-pushed the feature/quiescence-search-improvements branch from 72e2bf9 to 7bcc2f0 Compare January 21, 2026 07:33
@github-actions
Copy link

🔬 Stockfish Benchmark Results

vs Stockfish Skill Level 3

Metric Wins Losses Draws Total Win %
Overall 32 61 7 100 32.0%
As White 17 30 3 50 34.0%
As Black 15 31 4 50 30.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 5

vs Stockfish Skill Level 4

Metric Wins Losses Draws Total Win %
Overall 20 75 5 100 20.0%
As White 12 36 2 50 24.0%
As Black 8 39 3 50 16.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 5

vs Stockfish Skill Level 5

Metric Wins Losses Draws Total Win %
Overall 6 86 8 100 6.0%
As White 3 42 5 50 6.0%
As Black 3 44 3 50 6.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 6
  • Draw by fifty moves rule: 1
Configuration
  • 5 chunks × 20 rounds × 3 skill levels = 300 total games
  • Each opening played with colors reversed (-repeat) for fairness
  • Moonfish: 60s per move
  • Stockfish: 60+5 time control

@greptile-apps
Copy link

greptile-apps bot commented Feb 2, 2026

Greptile Overview

Greptile Summary

This PR significantly improves the quiescence search implementation by adding draw detection (fifty-move rule, insufficient material, threefold repetition), properly handling check positions by searching all evasions instead of just captures, and refactoring tactical move detection into a cleaner is_tactical_move() helper function.

Key improvements:

  • Draw detection prevents the engine from searching drawn positions indefinitely
  • Check handling ensures all legal evasions are searched when the king is in check, preventing tactical oversights
  • The new is_tactical_move() function correctly identifies captures, promotions, and checks (excluding quiet pawn pushes that were incorrectly included via is_zeroing())
  • Best score tracking replaces returning alpha, which properly handles positions where no moves improve the position

The changes align well with standard quiescence search algorithms and should improve tactical accuracy.

Confidence Score: 4/5

  • Safe to merge with high confidence - improves search correctness with standard techniques
  • The implementation follows well-established quiescence search patterns and all unit tests pass. The logic is sound for draw detection, check handling, and tactical move filtering. Minor style issue with unnecessary type annotation.
  • No files require special attention

Important Files Changed

Filename Overview
moonfish/engines/alpha_beta.py Improved quiescence search with draw detection, proper check handling, and best_score tracking
moonfish/move_ordering.py Added is_tactical_move() helper for cleaner tactical move detection (captures, promotions, checks)

Sequence Diagram

sequenceDiagram
    participant QS as quiescence_search
    participant Board
    participant MO as organize_moves_quiescence
    
    QS->>Board: is_check()
    alt In Check
        Board-->>QS: true
        QS->>QS: Set best_score = -inf
        QS->>Board: Get all legal moves (evasions)
    else Not In Check
        Board-->>QS: false
        QS->>Board: eval_board() → stand_pat
        alt stand_pat >= beta
            QS-->>QS: Return beta (cutoff)
        end
        QS->>QS: Set best_score = stand_pat
        QS->>QS: Update alpha = max(alpha, stand_pat)
        QS->>MO: organize_moves_quiescence()
        MO->>MO: Filter tactical moves (captures, promotions, checks)
        MO-->>QS: tactical_moves
    end
    
    loop For each move
        QS->>Board: push(move)
        QS->>Board: is_repetition(2)?
        alt Repetition Draw
            Board-->>QS: true
            QS->>QS: score = 0
        else Not Repetition
            Board-->>QS: false
            QS->>QS: Recursive quiescence_search()
            QS-->>QS: score = -recursive_result
        end
        QS->>Board: pop()
        
        alt score > best_score
            QS->>QS: Update best_score
        end
        
        alt score >= beta
            QS-->>QS: Return beta (cutoff)
        end
        
        QS->>QS: Update alpha = max(alpha, score)
    end
    
    QS-->>QS: Return best_score
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile


# Check if this move leads to a repetition (draw)
if board.is_repetition(2):
score: float = 0 # Draw score
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary type annotation on variable assignment

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: moonfish/engines/alpha_beta.py
Line: 143:143

Comment:
unnecessary type annotation on variable assignment

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

🔬 Stockfish Benchmark Results

vs Stockfish Skill Level 3

Metric Wins Losses Draws Total Win %
Overall 28 64 8 100 28.0%
As White 15 31 4 50 30.0%
As Black 13 33 4 50 26.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 7

vs Stockfish Skill Level 4

Metric Wins Losses Draws Total Win %
Overall 27 72 1 100 27.0%
As White 19 30 1 50 38.0%
As Black 8 42 0 50 16.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 1

vs Stockfish Skill Level 5

Metric Wins Losses Draws Total Win %
Overall 13 82 5 100 13.0%
As White 11 37 2 50 22.0%
As Black 2 45 3 50 4.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 4
Configuration
  • 5 chunks × 20 rounds × 3 skill levels = 300 total games
  • Each opening played with colors reversed (-repeat) for fairness
  • Moonfish: 60s per move
  • Stockfish: 60+5 time control

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants