game/js/ui.js

110 lines
3.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 交互控制:点击落子、模式/执子切换、AI 应手、状态栏文案。
*/
(function () {
function createController(canvas, renderer) {
const E = window.GomokuEngine;
const AI = window.GomokuAI;
const statusEl = document.getElementById('status');
const modeSel = document.getElementById('mode');
const sideSel = document.getElementById('side');
const sideRow = document.getElementById('side-row');
const newBtn = document.getElementById('new-game');
let game = E.createGame();
let mode = modeSel.value; // 'ai' | 'pvp'
let humanColor = Number(sideSel.value);
let aiThinking = false;
function isHumanTurn() {
return !game.gameOver && (mode === 'pvp' || game.currentPlayer === humanColor);
}
function updateStatus() {
if (game.gameOver) {
if (game.draw) {
statusEl.textContent = '平局,棋盘已下满';
} else if (mode === 'ai') {
statusEl.textContent = game.winner === humanColor ? '你赢了!🎉' : 'AI 获胜,再接再厉';
} else {
statusEl.textContent = game.winner === E.BLACK ? '黑方获胜!' : '白方获胜!';
}
return;
}
if (aiThinking) {
statusEl.textContent = 'AI 思考中…';
return;
}
if (mode === 'ai') {
statusEl.textContent = game.currentPlayer === humanColor
? `轮到你落子(${humanColor === E.BLACK ? '黑子' : '白子'})`
: '轮到 AI 落子';
} else {
statusEl.textContent = game.currentPlayer === E.BLACK ? '轮到黑方落子' : '轮到白方落子';
}
}
function refresh(hover) {
renderer.render(game, hover || null);
updateStatus();
}
// 轮到 AI 时延迟 300ms 落子:观感自然,也给界面留出渲染时间
function maybeAIMove() {
if (mode !== 'ai' || game.gameOver || game.currentPlayer === humanColor) return;
aiThinking = true;
updateStatus();
setTimeout(() => {
const mv = AI.nextMove(game, game.currentPlayer);
E.place(game, mv.x, mv.y);
aiThinking = false;
refresh();
}, 300);
}
canvas.addEventListener('click', (e) => {
if (!isHumanTurn() || aiThinking) return;
const pos = renderer.cellFromEvent(e);
if (!pos) return;
const r = E.place(game, pos.x, pos.y);
if (!r.ok) return;
refresh();
maybeAIMove();
});
canvas.addEventListener('mousemove', (e) => {
if (!isHumanTurn() || aiThinking) {
refresh();
return;
}
refresh(renderer.cellFromEvent(e));
});
canvas.addEventListener('mouseleave', () => refresh());
function newGame() {
game = E.createGame();
aiThinking = false;
refresh();
maybeAIMove(); // 人执白时让 AI(黑)先落子
}
modeSel.addEventListener('change', () => {
mode = modeSel.value;
sideRow.style.display = mode === 'ai' ? '' : 'none';
newGame();
});
sideSel.addEventListener('change', () => {
humanColor = Number(sideSel.value);
newGame();
});
newBtn.addEventListener('click', newGame);
newGame();
return { refresh };
}
window.GomokuUI = { createController };
})();