/* AI 行为测试:node --test tests/ai.test.js */ const { test } = require('node:test'); const assert = require('node:assert'); const E = require('../js/engine.js'); const AI = require('../js/ai.js'); function setStones(game, color, coords) { for (const [x, y] of coords) game.board[y][x] = color; } test('空盘首着落天元', () => { const g = E.createGame(); assert.deepStrictEqual(AI.nextMove(g, E.BLACK), { x: 7, y: 7 }); }); test('能一手取胜时直接取胜', () => { const g = E.createGame(); // 白方横向四连(x=4..7, y=5),左端被黑封堵,唯一成五点是 (8,5) setStones(g, E.WHITE, [[4, 5], [5, 5], [6, 5], [7, 5]]); setStones(g, E.BLACK, [[3, 5]]); assert.deepStrictEqual(AI.nextMove(g, E.WHITE), { x: 8, y: 5 }); }); test('对方冲四时必防守', () => { const g = E.createGame(); // 黑方横向四连(x=3..6, y=9),左端 (2,9) 已被白封堵,白必须在 (7,9) 挡 setStones(g, E.BLACK, [[3, 9], [4, 9], [5, 9], [6, 9]]); setStones(g, E.WHITE, [[2, 9]]); assert.deepStrictEqual(AI.nextMove(g, E.WHITE), { x: 7, y: 9 }); }); test('对方活三时封挡端点', () => { const g = E.createGame(); // 黑方两端开阔的活三,白应落在 (5,7) 或 (9,7) 之一 setStones(g, E.BLACK, [[6, 7], [7, 7], [8, 7]]); const mv = AI.nextMove(g, E.WHITE); assert.ok( (mv.x === 5 && mv.y === 7) || (mv.x === 9 && mv.y === 7), `期望封挡 (5,7) 或 (9,7),实际落在 (${mv.x},${mv.y})` ); }); test('己方活三优先于防守对方眠二', () => { const g = E.createGame(); // 白有活二 (4,8)(5,8),黑只有零散两子;白应继续连子而非远端防守 setStones(g, E.WHITE, [[4, 8], [5, 8]]); setStones(g, E.BLACK, [[10, 3], [3, 11]]); const mv = AI.nextMove(g, E.WHITE); const nearOwn = Math.abs(mv.x - 4) + Math.abs(mv.y - 8) <= 4 || Math.abs(mv.x - 5) + Math.abs(mv.y - 8) <= 4; assert.ok(nearOwn, `期望在己方活二附近行棋,实际落在 (${mv.x},${mv.y})`); }); test('返回的点永远是空位', () => { const g = E.createGame(); setStones(g, E.BLACK, [[7, 7], [8, 8], [6, 8]]); setStones(g, E.WHITE, [[7, 8], [8, 6], [6, 6]]); g.currentPlayer = E.WHITE; for (let i = 0; i < 20; i++) { const mv = AI.nextMove(g); assert.strictEqual(g.board[mv.y][mv.x], E.EMPTY); } });