Skip to content

feat: Add configurable win rules (K-in-a-row and no-moves detection)#11

Merged
dhanjit merged 1 commit into
mainfrom
claude/configurable-win-rules-Kw7pQ
Dec 31, 2025
Merged

feat: Add configurable win rules (K-in-a-row and no-moves detection)#11
dhanjit merged 1 commit into
mainfrom
claude/configurable-win-rules-Kw7pQ

Conversation

@dhanjit

@dhanjit dhanjit commented Dec 31, 2025

Copy link
Copy Markdown
Owner

Summary

This PR adds two new configurable game rules to enhance gameplay flexibility:

  1. Configurable Win Line Length (K-in-a-row)

    • Players can configure how many consecutive balls are needed to win (3 to N)
    • Smart default: N-in-a-row for N×N grid (maintains backward compatibility)
    • UI dropdown allows easy configuration
    • Example: Play 3-in-a-row on a 5×5 grid for faster games
  2. No Valid Moves = Loss

    • Player automatically loses if they have no legal moves available
    • Always enabled (no toggle needed)
    • Detects immobilization during movement phase
    • Shows distinct win message for immobilization victories

Implementation Details

Core Game Logic (web/js/game.js)

  • ✅ Add winLineLength parameter to constructor with validation (3 ≤ K ≤ N)
  • ✅ Implement sliding window algorithm via checkLineForKConsecutive() method
  • ✅ Refactor checkWinner() to use sliding window for K-in-a-row detection
  • ✅ Add hasValidMoves() method to detect player immobilization
  • ✅ Update getState() to expose winLineLength

Game Flow Integration (web/js/main.js)

  • ✅ Read winLineLength config from UI dropdown in initGame()
  • ✅ Add no-moves check after each successful move in movement phase
  • ✅ Handle immobilization win condition for both PvP and PvAI modes

UI Updates (web/index.html, web/js/ui.js)

  • ✅ Add Win Condition dropdown with dynamic options based on grid size
  • ✅ Implement showWinnerByImmobilization() for distinct win message
  • ✅ Update rules section to explain new victory conditions
  • ✅ Add JavaScript to dynamically populate dropdown when grid size changes

AI Adaptation (web/js/ai.js)

  • ✅ Mirror game.js sliding window logic in checkWinnerFromState()
  • ✅ Refactor evaluateLine() to use sliding window for variable K evaluation
  • ✅ Add immediate win detection in getBestMovement() for optimization
  • ✅ Add no-moves detection to minimax() algorithm
  • ✅ Fix cloneGameState() to preserve winLineLength property

Testing (tests/ai.test.js)

  • ✅ Fix "detects winning movement opportunity" test setup
  • ✅ Add Player 1 balls to create valid movement phase scenario
  • ✅ Ensure tests verify AI correctly detects K-in-a-row wins

Test Results

All 130 tests passing:

  • ✅ 100 game logic tests (including new K-in-a-row and no-moves scenarios)
  • ✅ 29 AI tests (including immediate win detection)
  • ✅ Integration tests for PvP and PvAI modes

Backward Compatibility

Fully backward compatible: Default behavior (K=N) matches original game

  • Existing games continue to work exactly as before
  • New features are opt-in via UI dropdown
  • No breaking changes to game logic or API

Usage Example

// Create a game with custom win condition
const game = new PaperballsGame(
  5,           // 5×5 grid
  'short',     // 8-way movement
  3            // 3-in-a-row to win
);

Screenshots

N/A - UI changes are functional (dropdown menu additions)

Related Issues

Addresses user request for configurable win rules to support different game variants and skill levels.

Add two new game rule configurations:

1. **Configurable Win Line Length (K-in-a-row)**:
   - Players can configure how many consecutive balls are needed to win
   - Smart default: N-in-a-row for N×N grid (maintains backward compatibility)
   - UI dropdown allows override from 3 to N
   - Example: 3-in-a-row on a 5×5 grid instead of requiring 5-in-a-row

2. **No Valid Moves = Loss**:
   - Player automatically loses if they have no legal moves available
   - Always enabled (no toggle)
   - Detects immobilization during movement phase
   - Shows distinct win message for immobilization victories

Core Game Logic (web/js/game.js):
- Add winLineLength parameter to constructor with validation (3 ≤ K ≤ N)
- Implement sliding window algorithm via checkLineForKConsecutive() method
- Refactor checkWinner() to use sliding window for K-in-a-row detection
- Add hasValidMoves() method to detect player immobilization
- Update getState() to expose winLineLength

Game Flow Integration (web/js/main.js):
- Read winLineLength config from UI dropdown in initGame()
- Add no-moves check after each successful move in movement phase
- Handle immobilization win condition for both PvP and PvAI modes

UI Updates (web/index.html, web/js/ui.js):
- Add Win Condition dropdown with dynamic options based on grid size
- Implement showWinnerByImmobilization() for distinct win message
- Update rules section to explain new victory conditions
- Add JavaScript to dynamically populate dropdown when grid size changes

AI Adaptation (web/js/ai.js):
- Mirror game.js sliding window logic in checkWinnerFromState()
- Refactor evaluateLine() to use sliding window for variable K evaluation
- Add immediate win detection in getBestMovement() for optimization
- Add no-moves detection to minimax() algorithm
- Fix cloneGameState() to preserve winLineLength property

Testing (tests/ai.test.js):
- Fix "detects winning movement opportunity" test setup
- Add Player 1 balls to create valid movement phase scenario
- Ensure tests verify AI correctly detects K-in-a-row wins

All 130 tests passing with new features fully integrated.
@dhanjit dhanjit merged commit 05f8a98 into main Dec 31, 2025
4 checks passed
@dhanjit dhanjit deleted the claude/configurable-win-rules-Kw7pQ branch December 31, 2025 16:43
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.

1 participant