/* 规则引擎测试:node --test tests/ */ const { test } = require('node:test'); const assert = require('node:assert'); const E = require('../js/engine.js'); // 直接往棋盘上摆子,用于构造测试局面(绕过轮流落子) function setStones(game, color, coords) { for (const [x, y] of coords) game.board[y][x] = color; } test('黑先并且落子后交替行棋', () => { const g = E.createGame(); assert.strictEqual(g.currentPlayer, E.BLACK); const r = E.place(g, 7, 7); assert.strictEqual(r.ok, true); assert.strictEqual(g.currentPlayer, E.WHITE); E.place(g, 8, 8); assert.strictEqual(g.currentPlayer, E.BLACK); }); test('横向五连判胜', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 7], [4, 7], [5, 7], [6, 7]]); g.currentPlayer = E.BLACK; const r = E.place(g, 7, 7); assert.strictEqual(r.win, true); assert.strictEqual(g.winner, E.BLACK); assert.strictEqual(g.gameOver, true); assert.deepStrictEqual(g.winningLine, [ { x: 3, y: 7 }, { x: 4, y: 7 }, { x: 5, y: 7 }, { x: 6, y: 7 }, { x: 7, y: 7 }, ]); }); test('纵向五连判胜', () => { const g = E.createGame(); setStones(g, E.WHITE, [[7, 3], [7, 4], [7, 5], [7, 6]]); g.currentPlayer = E.WHITE; const r = E.place(g, 7, 7); assert.strictEqual(r.win, true); assert.strictEqual(g.winner, E.WHITE); }); test('斜向(左上到右下)五连判胜', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 3], [4, 4], [5, 5], [6, 6]]); g.currentPlayer = E.BLACK; const r = E.place(g, 7, 7); assert.strictEqual(r.win, true); }); test('斜向(左下到右上)五连判胜', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 10], [4, 9], [5, 8], [6, 7]]); g.currentPlayer = E.BLACK; const r = E.place(g, 7, 6); assert.strictEqual(r.win, true); assert.strictEqual(g.winningLine.length, 5); }); test('长连(六连)同样判胜', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 5], [4, 5], [5, 5], [6, 5], [8, 5]]); g.currentPlayer = E.BLACK; const r = E.place(g, 7, 5); assert.strictEqual(r.win, true); assert.strictEqual(g.winningLine.length, 6); }); test('四连不判胜', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 7], [4, 7], [5, 7], [6, 7]]); g.currentPlayer = E.BLACK; const r = E.place(g, 9, 9); // 与四连无关的落子 assert.strictEqual(r.win, undefined); assert.strictEqual(g.gameOver, false); }); test('非法落子被拒绝:已占用', () => { const g = E.createGame(); E.place(g, 7, 7); const r = E.place(g, 7, 7); assert.strictEqual(r.ok, false); }); test('非法落子被拒绝:越界', () => { const g = E.createGame(); assert.strictEqual(E.place(g, -1, 0).ok, false); assert.strictEqual(E.place(g, 0, -1).ok, false); assert.strictEqual(E.place(g, 15, 0).ok, false); assert.strictEqual(E.place(g, 0, 15).ok, false); }); test('对局结束后拒绝继续落子', () => { const g = E.createGame(); setStones(g, E.BLACK, [[3, 7], [4, 7], [5, 7], [6, 7]]); g.currentPlayer = E.BLACK; E.place(g, 7, 7); const r = E.place(g, 10, 10); assert.strictEqual(r.ok, false); assert.strictEqual(r.reason, '游戏已结束'); }); test('棋盘下满判平局', () => { const g = E.createGame(); // 用 (x + 2y) mod 4 的双色填充,任意方向连续同色不超过 2,不会误判五连 for (let y = 0; y < E.SIZE; y++) { for (let x = 0; x < E.SIZE; x++) { if (x === 14 && y === 14) continue; const v = ((x + 2 * y) % 4 + 4) % 4; g.board[y][x] = v === 0 || v === 1 ? E.BLACK : E.WHITE; } } g.currentPlayer = E.BLACK; const r = E.place(g, 14, 14); assert.strictEqual(r.draw, true); assert.strictEqual(g.gameOver, true); assert.strictEqual(g.winner, 0); }); test('落子历史被完整记录', () => { const g = E.createGame(); E.place(g, 7, 7); E.place(g, 8, 8); E.place(g, 7, 8); assert.strictEqual(g.moveHistory.length, 3); assert.deepStrictEqual(g.moveHistory[0], { x: 7, y: 7, player: E.BLACK }); assert.deepStrictEqual(g.moveHistory[1], { x: 8, y: 8, player: E.WHITE }); assert.deepStrictEqual(g.moveHistory[2], { x: 7, y: 8, player: E.BLACK }); });