[fix] Add heuristic evaluation, fork detection, and Phase 1 win/block split to AI.

Minimax leaf nodes now return a positional score instead of 0, using
playable-threat detection (±100), non-playable threats (±40), fork
bonus (±200), two-in-a-row (±5), and center control (±3). Phase 1
is split into two passes so the AI never blocks when it can win.
Game sequence is now auto-logged to the browser console on game end.
Applied to all three implementations (C++, JS, Python).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 16:59:55 +01:00
co-authored by Claude Opus 4.6
parent 54bae2faf5
commit b27032762e
3 changed files with 64 additions and 14 deletions
+20 -4
View File
@@ -268,6 +268,7 @@ int8_t scanBoard() {
int evaluateBoard(int8_t aiP, int8_t huP) {
int score = 0;
int aiThreats = 0, huThreats = 0;
// Center column bonus
for (int r = 0; r < ROWS; r++) {
@@ -277,16 +278,27 @@ int evaluateBoard(int8_t aiP, int8_t huP) {
// Score a window of 4 cells by piece counts
auto scoreWindow = [&](int c, int r, int dc, int dr) -> int {
int ai = 0, hu = 0;
int ai = 0, hu = 0, emptyC = -1, emptyR = -1;
for (int i = 0; i < 4; i++) {
int8_t v = board[c + i * dc][r + i * dr];
int cc = c + i * dc;
int rr = r + i * dr;
int8_t v = board[cc][rr];
if (v == aiP) ai++;
else if (v == huP) hu++;
else { emptyC = cc; emptyR = rr; }
}
if (ai > 0 && hu > 0) return 0;
if (ai == 3) return 50;
if (ai == 3) {
aiThreats++;
bool playable = emptyR == 0 || board[emptyC][emptyR - 1] != 0;
return playable ? 100 : 40;
}
if (ai == 2) return 5;
if (hu == 3) return -50;
if (hu == 3) {
huThreats++;
bool playable = emptyR == 0 || board[emptyC][emptyR - 1] != 0;
return playable ? -100 : -40;
}
if (hu == 2) return -5;
return 0;
};
@@ -296,6 +308,10 @@ int evaluateBoard(int8_t aiP, int8_t huP) {
for (int r = 0; r < 3; r++) for (int c = 0; c < 4; c++) score += scoreWindow(c, r, 1, 1);
for (int r = 3; r < 6; r++) for (int c = 0; c < 4; c++) score += scoreWindow(c, r, 1, -1);
// Fork bonus: multiple threats are disproportionately dangerous
if (aiThreats >= 2) score += 200;
if (huThreats >= 2) score -= 200;
return score;
}