[update] Improve heuristic.

This commit is contained in:
2026-03-27 17:24:02 +01:00
parent f5f5e46b32
commit d88a23bd5c
2 changed files with 51 additions and 9 deletions
+22 -5
View File
@@ -1,6 +1,6 @@
/* ============================================================
* Connect Four — Browser Edition
* A single-file game: AI (minimax + alpha-beta), demo mode,
* A single-file game: AI (minimax + alpha-beta + heuristic), demo mode,
* game log (localStorage), blunder mode, idle timeout.
*
* Include this script in an HTML page that has:
@@ -168,6 +168,7 @@ function scanBoard(b) {
function evaluateBoard(b, aiP, huP) {
let score = 0;
let aiThreats = 0, huThreats = 0;
// Center column bonus
for (let r = 0; r < ROWS; r++) {
@@ -177,16 +178,27 @@ function evaluateBoard(b, aiP, huP) {
// Score a window of 4 cells by piece counts
function scoreWindow(c, r, dc, dr) {
let ai = 0, hu = 0;
let ai = 0, hu = 0, emptyC = -1, emptyR = -1;
for (let i = 0; i < 4; i++) {
const v = b[c + i * dc][r + i * dr];
const cc = c + i * dc;
const rr = r + i * dr;
const v = b[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++;
const playable = emptyR === 0 || b[emptyC][emptyR - 1] !== 0;
return playable ? 100 : 40;
}
if (ai === 2) return 5;
if (hu === 3) return -50;
if (hu === 3) {
huThreats++;
const playable = emptyR === 0 || b[emptyC][emptyR - 1] !== 0;
return playable ? -100 : -40;
}
if (hu === 2) return -5;
return 0;
}
@@ -208,6 +220,10 @@ function evaluateBoard(b, aiP, huP) {
for (let c = 0; c <= COLS - 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;
}
@@ -324,6 +340,7 @@ function checkGameEnd() {
if (gameState !== State.DEMO) {
games = logGame(games, gameMenuMode, gameLevel, won ? w : 0, currentMoves);
console.log(`Game: ${currentMoves}${won ? playerName(w) + " wins" : "Draw"}`);
}
gameState = won ? State.FINISHED_WIN : State.FINISHED_DRAW;
demoResetTimer = performance.now() / 1000;