编辑:结果如下:http://gomokuu.glitch.me/
这是我的gomoku密码。我是用JavaScript和HTML做的。我认为checkWinner函数可以改进或缩短。此外,职能是否应该重新组织?
以下是代码:
Javascript:
var turn = 0;
var width = 15;
var height = 15;
var gameOver = false;
var board = Array(width * height);
function announceWinner(winner) {
console.log("a");
if (winner == 0) {
window.alert("X wins");
}
if (winner == 1) {
window.alert("O wins");
}
if (winner == 2) {
window.alert("Board filled");
}
}
function checkWinner() {
var filled = true;
for (var i = 0; i < board.length; i++) {
if (board[i] == undefined) filled = false;
if (board[i] !== undefined) {
if (
(board[i] == board[i + 1] &&
board[i + 1] == board[i + 2] &&
board[i + 2] == board[i + 3] &&
board[i + 3] == board[i + 4]) ||
(board[i] == board[i + width] &&
board[i + width] == board[i + 2 * width] &&
board[i + 2 * width] == board[i + 3 * width] &&
board[i + 3 * width] == board[i + 4 * width]) ||
(board[i] == board[i + 1 + width] &&
board[i + 1 + width] == board[i + 2 + 2 * width] &&
board[i + 2 + 2 * width] == board[i + 3 + 3 * width] &&
board[i + 3 + 3 * width] == board[i + 4 + 4 * width]) ||
(board[i] == board[i - 1 + width] &&
board[i - 1 + width] == board[i - 2 + 2 * width] &&
board[i - 2 + 2 * width] == board[i - 3 + 3 * width] &&
board[i - 3 + 3 * width] == board[i - 4 + 4 * width])
) {
gameOver = true;
announceWinner(board[i]);
}
}
}
if (filled) {
announceWinner(2);
}
}
function tileClick(row, tile) {
var clicked = document.getElementById("board").children[row].children[tile];
if (clicked.innerHTML || gameOver) return;
board[tile + row * width] = turn;
if (turn) {
clicked.innerHTML = "o";
clicked.style.color = "red";
turn = 0;
} else {
clicked.innerHTML = "x";
clicked.style.color = "blue";
turn = 1;
}
checkWinner();
}
//generate board and listen to click event
var domBoard = document.createElement("table");
domBoard.id = "board";
for (let i = 0; i < height; i++) {
var row = document.createElement("tr");
for (let j = 0; j < width; j++) {
var tile = document.createElement("td");
tile.onclick = function() {
tileClick(i, j);
};
row.appendChild(tile);
}
domBoard.appendChild(row);
}
document.body.appendChild(domBoard);HTML:
<!DOCTYPE html>
<html>
<head>
<title>gomoku</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script src="script.js"></script>
</body>
</html>发布于 2020-02-05 03:25:46
我没有时间给您一个完整的评论,所以我将添加一些关于checkWinner的评论:
true或false的纯函数。至于复制,您可以通过引入一个助手函数来捕获每个块中重复的抽象逻辑,从而删除其中的许多内容。这也将澄清检查胜利者的高层次逻辑:
function checkWinner() {
for (var i = 0; i < board.length; i++) {
var rightWin = winAt(i, 1)
var downWin = winAt(i, width)
if (rightWin || downWin) return true
}
return false
}
function winAt(i, step) {
if ( board[i] === undefined ) return false
for ( var j = 1; j < 5; j++) {
var nextIndex = i + (j * step)
if ( board[i] !== board[nextIndex] ) return false
}
return true
}问题的回答
Green Ball,对于您提到的使用2D数组的问题,有一些方法可以解决:您可以使用额外的未定义行填充,或者可以抽象一个隐藏丑陋边界检查的cell(i, j),并将其保存在一个地方。事实上,最后一点是关键,而不是使用一维或二维数组。
在当前的实现中,行周围的算术逻辑被强制输出到客户端:任何想要获得i, j对的代码都必须自己进行计算。目前发生在checkWinner和tileClick:board[tile + row * width]中。它还隐式地发生在构造html的双循环中。
不管包含board的底层结构是什么,您都希望客户端代码能够作为头等公民使用“行”和“列”的概念,因为这是我们人类对此的看法。这将使代码更加自然。
发布于 2020-02-04 14:07:47
在您的announceWinner()函数中,可以将多个if语句缩短为具有三元算子的单行语句,如下所示:
function announceWinner(winner) {
console.log("a");
window.alert(winner == 0 ? "X wins" : winner == 1 ? "O wins" : winner == 2 ? "Board filled");
}或者,如果您确信winner始终是0、1或2,那么您可以省略以下最后一个条件:
function announceWinner(winner) {
console.log("a");
window.alert(winner == 0 ? "X wins" : winner == 1 ? "O wins" : "Board filled");
}在checkWinner()函数中,可以将多个board数组索引推送到单个数组,然后使用每个()方法简化if语句中的多个条件,如下所示:
function checkWinner() {
var filled = true;
for (var i = 0; i < board.length; i++) {
if (board[i] == undefined) filled = false;
if (board[i] !== undefined) {
let arr1 = [board[i+1], board[i+2], board[i+3], board[i+4]];
let arr2 = [board[i+width], board[i+2*width], board[i+3*width], board[i+4*width]];
let arr3 = [board[i+1+width], board[i+2+2*width], board[i+3+3*width], board[i+4+4*width]];
let arr4 = [board[i-1+width], board[i-2+2*width], board[i-3+3*width], board[i-4+4*width]];
if (
(arr1.every(e=> e == board[i])) ||
(arr2.every(e=> e == board[i])) ||
(arr3.every(e=> e == board[i])) ||
(arr4.every(e=> e == board[i]))
) {
gameOver = true;
announceWinner(board[i]);
}
}
}
if (filled) {
announceWinner(2);
}
}发布于 2020-02-05 08:07:54
边缘箱里有个窃听器。如果最后一步,也就是董事会的最后一步,也创造了一个获胜的行列,就会有两个公告。要解决这个问题,您必须在获胜者声明之后使用return。
除此之外,代码非常容易阅读和理解。检查胜利者是相当缓慢的,如果您需要更快的代码,这就是您可以获得性能的地方。但在那之前,我建议保持原样。它很短,很简洁,很优雅。
如果希望减少代码的冗余,可以在checkWinner中定义一个助手函数:
function checkWinner() {
function fiveSame(start, step) {
function same(i) {
return board[start + i * step] === board[start];
}
return same(1) && same(2) && same(3) && same(4);
}
for (const i in board) {
if (fiveSame(i, 1) || fiveSame(i, width - 1) || fiveSame(i, width) || fiveSame(i, width + 1)) {
...
}
...
}https://codereview.stackexchange.com/questions/236619
复制相似问题