Skip to content

Commit 2555186

Browse files
Merge pull request #5 from CodeKunalTomar/copilot/fix-ai-edge-threats
Fix AI edge/corner blind spot by rebalancing priorities and adding threat detection
2 parents f9cc333 + 192862a commit 2555186

File tree

5 files changed

+488
-20
lines changed

5 files changed

+488
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Test files
22
test-*.html
33
test-*.js
4+
validate-changes.js
45

56
# macOS
67
.DS_Store

Connect-4.js

Lines changed: 115 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ const OPENING_BOOK = {
4343

4444
// Early game center control patterns
4545
'3132113122': 2, '3132413242': 4, '3132513252': 4, '3132213222': 2,
46+
47+
// Edge defense - Human opens on column 0
48+
'0131': 0, // Contest the edge!
49+
'013101': 0, // Continue contesting
50+
51+
// Edge defense - Human opens on column 6
52+
'6131': 6, // Contest the edge!
53+
'613161': 6, // Continue contesting
54+
55+
// Block 3-stacks on edges
56+
'010111': 0, // Block left edge 3-stack
57+
'616161': 6, // Block right edge 3-stack
4658
};
4759
const MAX_OPENING_MOVES = 15; // Use opening book for first 15 moves (7-8 ply per side)
4860

@@ -559,6 +571,38 @@ GameState.prototype.countPotentialLines = function(player) {
559571
return lines;
560572
}
561573

574+
// Detect threats building on edges (columns 0, 1, 5, 6)
575+
GameState.prototype.detectEdgeThreats = function(player) {
576+
let threats = 0;
577+
const edgeCols = [0, 1, 5, 6];
578+
579+
for (const col of edgeCols) {
580+
const height = this.bitboard.heights[col];
581+
582+
// Check vertical stacking - count consecutive pieces from the top
583+
if (height >= 2) {
584+
let consecutive = 0;
585+
let maxConsecutive = 0;
586+
587+
for (let row = 0; row < height; row++) {
588+
if (this.board[col][row] === player) {
589+
consecutive++;
590+
maxConsecutive = Math.max(maxConsecutive, consecutive);
591+
} else {
592+
consecutive = 0;
593+
}
594+
}
595+
596+
// Threat if there are 2+ consecutive pieces and room to grow
597+
if (maxConsecutive >= 2 && height < TOTAL_ROWS) {
598+
threats++;
599+
}
600+
}
601+
}
602+
603+
return threats;
604+
};
605+
562606
// Comprehensive evaluation for near-perfect play
563607
GameState.prototype.advancedEvaluate = function(player) {
564608
const opponent = player === 1 ? 2 : 1;
@@ -605,6 +649,12 @@ GameState.prototype.advancedEvaluate = function(player) {
605649
score += this.countPotentialLines(2) * AI_CONFIG.MOBILITY_WEIGHT;
606650
score -= this.countPotentialLines(1) * AI_CONFIG.MOBILITY_WEIGHT;
607651

652+
// 7. Edge threat detection
653+
const aiEdgeThreats = this.detectEdgeThreats(2);
654+
const humanEdgeThreats = this.detectEdgeThreats(1);
655+
score += aiEdgeThreats * 400;
656+
score -= humanEdgeThreats * 600; // Weight human edge threats higher (defensive)
657+
608658
return score;
609659
}
610660

@@ -644,37 +694,40 @@ function orderMoves(node, depth, ttBestMove) {
644694
const moveScores = moves.map(col => {
645695
let score = 0;
646696

647-
// 1. TT move has highest priority (10000)
697+
// 1. Immediate win detection (HIGHEST PRIORITY - always try winning moves first)
698+
const testState = new GameState(node);
699+
testState.makeMove(2, col);
700+
if (testState.isWin() && testState.score === COMPUTER_WIN_SCORE) {
701+
score += 100000;
702+
}
703+
704+
// 2. Block opponent's immediate win (CRITICAL - must block threats)
705+
const blockState = new GameState(node);
706+
blockState.makeMove(1, col);
707+
if (blockState.isWin() && blockState.score === HUMAN_WIN_SCORE) {
708+
score += 90000;
709+
}
710+
711+
// 3. TT move (good move from previous search)
648712
if (col === ttBestMove) {
649-
score += 10000;
713+
score += 5000;
650714
}
651715

652-
// 2. Killer moves (900 and 800)
716+
// 4. Killer moves (900 and 800)
653717
if (depth < killerMoves.length) {
654718
if (col === killerMoves[depth][0]) score += 900;
655719
if (col === killerMoves[depth][1]) score += 800;
656720
}
657721

658-
// 3. History heuristic
722+
// 5. History heuristic
659723
score += historyTable[col] || 0;
660724

661-
// 4. Center preference (positional bonus)
662-
const centerBonus = [10, 20, 30, 40, 30, 20, 10];
725+
// 6. Center preference (reduced bonus to avoid over-prioritization)
726+
const centerBonus = [5, 10, 15, 20, 15, 10, 5];
663727
score += centerBonus[col];
664728

665-
// 5. Immediate win detection (should be tried first after TT)
666-
const testState = new GameState(node);
667-
testState.makeMove(2, col);
668-
if (testState.isWin() && testState.score === COMPUTER_WIN_SCORE) {
669-
score += 50000; // Even higher than TT move - always try winning moves first
670-
}
671-
672-
// 6. Block opponent's immediate win
673-
const blockState = new GameState(node);
674-
blockState.makeMove(1, col);
675-
if (blockState.isWin() && blockState.score === HUMAN_WIN_SCORE) {
676-
score += 8000; // High priority but below winning move
677-
}
729+
// 7. Threat prevention evaluation (reuse states to optimize performance)
730+
score += evaluateThreatPrevention(node, col, blockState, testState);
678731

679732
return { col, score };
680733
});
@@ -685,6 +738,49 @@ function orderMoves(node, depth, ttBestMove) {
685738
return moveScores.map(m => m.col);
686739
}
687740

741+
// ============================================================================
742+
// THREAT PREVENTION EVALUATION
743+
// ============================================================================
744+
// Evaluate how important it is to play in this column to prevent opponent threats
745+
// This is a lighter-weight version that reuses states already created in orderMoves
746+
function evaluateThreatPrevention(node, col, blockState, testState) {
747+
let score = 0;
748+
const row = node.bitboard.heights[col];
749+
if (row >= TOTAL_ROWS) return 0;
750+
751+
// Reuse blockState if provided, otherwise create it
752+
if (!blockState) {
753+
blockState = new GameState(node);
754+
blockState.makeMove(1, col); // Human moves here
755+
}
756+
757+
// Check if this creates a 3-in-a-row threat for opponent
758+
const threatsAfter = blockState.countThreats(1, 3);
759+
if (threatsAfter > 0) {
760+
score += 3000 * threatsAfter;
761+
}
762+
763+
// Check for potential double-threat setup
764+
const doubleThreatsAfter = blockState.countDoubleThreats(1);
765+
if (doubleThreatsAfter > 0) {
766+
score += 7000;
767+
}
768+
769+
// Reuse testState if provided, otherwise create it
770+
if (!testState) {
771+
testState = new GameState(node);
772+
testState.makeMove(2, col);
773+
}
774+
775+
// Also reward moves that create threats for AI
776+
const aiThreats = testState.countThreats(2, 3);
777+
if (aiThreats > 0) {
778+
score += 2000 * aiThreats;
779+
}
780+
781+
return score;
782+
}
783+
688784
// listen for messages from the main thread
689785
self.addEventListener('message', function(e) {
690786
switch(e.data.messageType) {

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,51 @@ This implementation now includes **10 advanced AI techniques** that create near-
286286
| **Research Platform** | Design a plug-and-play AI module interface, add an analytics dashboard | 📝 **Planned** |
287287
288288
---
289-
## X. License and Citation
289+
## X. AI Testing & Robustness
290+
291+
### Bug Fix: Edge/Corner Blind Spot (v2.0)
292+
A critical vulnerability was identified where the AI over-prioritized center positions and failed to respond to edge column threats. This has been fixed with:
293+
- **Rebalanced move ordering priorities**: Winning moves (100,000), blocking moves (90,000), TT moves (5,000), and reduced center bonus ([5, 10, 15, 20, 15, 10, 5])
294+
- **New threat prevention evaluation**: Detects 3-in-a-row threats and double-threat setups before they become critical
295+
- **Edge threat detection system**: Specifically monitors columns 0, 1, 5, and 6 for vertical stacking threats
296+
- **Expanded opening book for edge defense**: Pre-computed responses to edge and corner opening strategies
297+
298+
### Running Tests
299+
The AI includes a comprehensive test suite in `ai-tests.js`:
300+
```javascript
301+
// In browser console (after loading Connect-4.js and ai-tests.js):
302+
runAITests();
303+
```
304+
305+
Test categories:
306+
- ✅ Immediate win detection (horizontal, vertical, diagonal)
307+
- ✅ Immediate block detection (all directions)
308+
- ✅ Edge/corner threat response (columns 0, 1, 5, 6)
309+
- ✅ Double threat creation and blocking
310+
- ✅ Win vs block priority
311+
- ✅ Strategic opening moves
312+
313+
### Example Bug Scenario (Now Fixed)
314+
**Before Fix:**
315+
```
316+
Turn 1: Human plays column 0 (corner)
317+
Turn 2: AI plays column 3 (center) - IGNORING the threat
318+
Turn 3: Human plays column 0 (stacks corner)
319+
Turn 4: AI plays column 3 (center) - STILL IGNORING
320+
Turn 5: Human plays column 0 (3 in a row!)
321+
Turn 6: AI finally notices but it's too late
322+
```
323+
324+
**After Fix:**
325+
```
326+
Turn 1: Human plays column 0 (corner)
327+
Turn 2: AI plays column 3 (center)
328+
Turn 3: Human plays column 0 (stacks corner)
329+
Turn 4: AI plays column 0 or 1 - BLOCKING the edge threat!
330+
```
331+
332+
---
333+
## XI. License and Citation
290334
This project is licensed under the **MIT License**, granting broad permissions for academic, personal, and commercial use.
291335
292336

TESTING.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# AI Testing Guide
2+
3+
## Overview
4+
This guide explains how to test the AI improvements for the edge/corner blind spot fix.
5+
6+
## Quick Start
7+
8+
### Browser-Based Testing (Recommended)
9+
1. Start a local web server:
10+
```bash
11+
python3 -m http.server 8000
12+
# OR
13+
npx live-server
14+
```
15+
16+
2. Open your browser to:
17+
```
18+
http://localhost:8000/test-ai.html
19+
```
20+
21+
3. Click "Run Tests" to execute all 13 test cases
22+
23+
4. Review results:
24+
- ✅ Green = Test passed
25+
- ❌ Red = Test failed
26+
27+
## Test Categories
28+
29+
### 1. Immediate Win Detection
30+
- Tests that AI takes winning moves when available
31+
- Covers horizontal and vertical wins
32+
- Validates win priority over other moves
33+
34+
### 2. Immediate Block Detection
35+
- Tests that AI blocks opponent's winning moves
36+
- Covers horizontal and vertical blocks
37+
- Validates blocking priority is high
38+
39+
### 3. Edge/Corner Threat Response (THE BUG FIX)
40+
- Tests AI response to column 0 stacking
41+
- Tests AI response to column 6 stacking
42+
- Tests AI blocks 3-stacks on edges
43+
- Validates the fix for the reported vulnerability
44+
45+
### 4. Double Threat Handling
46+
- Tests AI creates double threats when possible
47+
- Tests AI blocks opponent double threat setups
48+
- Validates advanced tactical awareness
49+
50+
### 5. Win vs Block Priority
51+
- Tests AI takes wins over blocks
52+
- Validates priority ordering is correct
53+
54+
### 6. Strategic Opening
55+
- Tests AI prefers center on empty board
56+
- Tests AI contests center appropriately
57+
58+
## Manual Testing
59+
60+
You can also test manually by playing the game:
61+
62+
1. Open `index.html` in your browser
63+
2. Select "VS AI" mode
64+
3. Try to build a vertical stack on column 0 or 6
65+
4. The AI should now contest these edges instead of ignoring them
66+
67+
### Test Scenario 1: Column 0 Stack
68+
```
69+
Turn 1: You play column 0
70+
Turn 2: AI plays column 3 (center)
71+
Turn 3: You play column 0 again
72+
Turn 4: AI should now play column 0 or 1 (not just column 3!)
73+
```
74+
75+
### Test Scenario 2: Column 6 Stack
76+
```
77+
Turn 1: You play column 6
78+
Turn 2: AI plays column 3 (center)
79+
Turn 3: You play column 6 again
80+
Turn 4: AI should now play column 5 or 6 (not just column 3!)
81+
```
82+
83+
## Expected Results
84+
85+
All 13 tests should pass:
86+
- ✅ AI takes horizontal win
87+
- ✅ AI takes vertical win
88+
- ✅ AI blocks horizontal threat
89+
- ✅ AI blocks vertical threat
90+
- ✅ AI responds to column 0 stacking
91+
- ✅ AI responds to column 6 stacking
92+
- ✅ AI blocks corner 3-stack on column 0
93+
- ✅ AI blocks corner 3-stack on column 6
94+
- ✅ AI creates double threat
95+
- ✅ AI blocks opponent double threat setup
96+
- ✅ AI takes win over block
97+
- ✅ AI prefers center on empty board
98+
- ✅ AI contests center
99+
100+
## Troubleshooting
101+
102+
### Tests Don't Run
103+
- Ensure you're using a local web server (not file://)
104+
- Check browser console for errors
105+
- Verify Connect-4.js and ai-tests.js are loaded
106+
107+
### Some Tests Fail
108+
- This may indicate the AI needs deeper search
109+
- Try increasing the depth parameter in the test (currently 10)
110+
- Check that all code changes were applied correctly
111+
112+
### Manual Tests Show Different Behavior
113+
- AI uses randomness when multiple moves have equal scores
114+
- Try multiple games to see consistent patterns
115+
- The AI should generally contest edges, not always the exact same column
116+
117+
## Performance Notes
118+
119+
- Each test runs a depth-10 search
120+
- Full test suite takes 10-30 seconds
121+
- Browser may appear frozen during testing (this is normal)
122+
- Results are logged to console for debugging
123+
124+
## Validation
125+
126+
To verify all changes were applied correctly:
127+
```bash
128+
node validate-changes.js
129+
```
130+
131+
This checks:
132+
- Move ordering priorities
133+
- Threat prevention function
134+
- Edge threat detection
135+
- Opening book expansion
136+
- Test file existence
137+
- Documentation updates

0 commit comments

Comments
 (0)