gpt4 book ai didi

javascript - 检查周围的表格单元格

转载 作者:太空狗 更新时间:2023-10-29 13:30:30 26 4
gpt4 key购买 nike

我正在制作名为 Dots and Boxes 的游戏。

网格上有一堆点:

enter image description here

<table>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
</table>

当你点击框的一侧时,它变成黑色:

enter image description here enter image description here

function addLine(obj) {
console.log("Called")

if (obj.style.backgroundColor != "black") {
obj.style.backgroundColor = "black";
changeTurn()
}

一旦你点击第四边,关闭盒子,盒子就会变成点击第四边的玩家的颜色:

enter image description here

目前,玩家必须手动点击方框来改变它的颜色。但是,我希望当盒子周围的所有四个边都是黑色时,它会自动用颜色填充盒子。

如何使用 Javascript 中的函数来检查框的上方、下方、左侧和右侧的行是否填充为黑色?

var playerTurn = "Blue";
changeTurn();
var number = 0;

function addLine(obj) {
console.log("Called")

if (obj.style.backgroundColor != "black") {
obj.style.backgroundColor = "black";
changeTurn()
}
}

function fillBox(obj) {
if (playerTurn == "Blue") {
obj.style.backgroundColor = "red";
}
else if ( playerTurn == "Red") {
obj.style.backgroundColor = "blue";
}
}

function changeTurn() {
if (playerTurn == "Red") {
playerTurn = "Blue";
document.getElementById('turn').style.color = "blue";

}
else if (playerTurn == "Blue") {
playerTurn = "Red";
document.getElementById('turn').style.color = "red";
};
console.log(playerTurn);
document.getElementById('turn').innerHTML = playerTurn + "'s Turn";
}
h3 {
font-family: Arial;
}
table {
border-collapse: collapse;
}
.vLine {
width: 10px;
height: 60px;
}
.box {
width: 60px;
height: 60px;
}
.hLine {
width: 60px;
height: 10px;
}
.gap {
width: 10px;
height: 12px;
background-color: black;
}
.vLine:hover, .hLine:hover {
background-color: black;
}
<h3 id="turn"></h3>

<table>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
<td class="box" onclick="fillBox(this)"></td>
<td class="vLine" onclick="addLine(this)"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
<td class="hLine" onclick="addLine(this)"></td>
<td class="gap"></td>
</tr>
</table>

最佳答案

这相当简单,尽管它需要很好地使用 DOM 遍历。

当您单击一条线时,最多只有 两个 可能的框可以填充。对于水平线,它们是上方和下方的框,这需要跳行。对于垂直线,左和右。

对于这些框中的每一个,我们需要确认四行。同样,我们必须跳转上方和下方的行。

实际上,我已经重新制作了这款游戏,大部分是因为它很有趣,而且有很多东西需要学习。那么让我们来看看重要的部分。我们将避免这段代码中的不良形式,例如内联处理程序和直接在元素上设置样式,我们将让 CSS 类充当控件,尽管更完整的选项是 data-attributes

让我们从两个基本的辅助函数开始。

第一个用于将类似数组的对象转换为实际的数组,因此我们可以对它们使用 Array.prototype 方法。我们主要在 nodeList 对象上使用它。

function toArray (o) {
return Array.prototype.slice.call(o);
}

第二个利用第一个,并为我们提供元素在其 parentNode 中的位置。

function nodeIndex (node) {
return toArray(node.parentNode.children).indexOf(node);
}

接下来,我们的事件处理程序。他们彼此非常相似。当我们点击一​​行时,我们用另一个辅助函数 fill 填充该行,它向名为 .filled 的行添加一个新类。然后我们检查可以填写的框。对于水平线,即上方和下方的垂直框;对于水平框的垂直线,左和右。我们删除了事件监听器,因此只能单击一次行。

function addHLine (e) {
fill(this);
this.removeEventListener(e.type, addHLine);
checkVerticalBoxes(this);
updateGame();
}

function addVLine (e) {
fill(this);
this.removeEventListener(e.type, addVLine);
checkHorizontalBoxes(this);
updateGame();
}

现在让我们看看 checkHorizo​​ntalBoxescheckVerticalBoxes。水平框位于同一行,从我们的起始行开始索引 +/-1。垂直框位于从我们的起始行开始索引为 +/-1 的行中,并与该行共享相同的索引。我们有一些 if 语句,因为有时可能的行或框会越界。

function checkHorizontalBoxes (line) {
var left = line.previousElementSibling,
right = line.nextElementSibling;

if (left) checkSurroundingLines(left);
if (right) checkSurroundingLines(right);
}

function checkVerticalBoxes (line) {
var index = nodeIndex(line),
up = line.parentNode.previousElementSibling,
down = line.parentNode.nextElementSibling;

if (up) checkSurroundingLines(up.children[index]);
if (down) checkSurroundingLines(down.children[index]);
}

这两个函数都在潜在的框上调用 checkSurroundingLines。此函数调用另外两个函数 - checkVerticalLinescheckHorizo​​ntalLines。开始看到模式了吗? isFilled 类似于fill,它是我们定义的辅助函数,用于测试一行是否具有类.filled

function checkHorizontalLines (node, idx) {
var left = node.previousElementSibling,
right = node.nextElementSibling;

return isFilled(left) && isFilled(right);
}

function checkVerticalLines (node, idx) {
var row = node.parentNode,
up = row.previousElementSibling.children[idx],
down = row.nextElementSibling.children[idx];

return isFilled(up) && isFilled(down);
}

如果两者都返回 true,我们将填充我们的框。


这是这种 DOM 遍历的基本逻辑。实际代码还有一些额外的内容,因此请阅读所有部分。

这是工作游戏:

DEMO

// Player objects

function Player (name, className, scoreBox) {
this.name = name;
this.className = className;
this.scoreBox = scoreBox;
this.score = 0;
}

// State

var players = [new Player('Blue', 'blue-mark', 'p1'),
new Player('Red', 'red-mark', 'p2')],
currentPlayerIdx = 0,
currentPlayer = players[currentPlayerIdx],
turnBox = document.getElementById('turn');

// Helpers

function toArray (o) {
return Array.prototype.slice.call(o);
}

function nodeIndex (node) {
return toArray(node.parentNode.children).indexOf(node);
}

function fill (el) {
el.classList.add('filled');
}

function isFilled (el) {
return el.classList.contains('filled');
}

// Checks

function checkHorizontalLines (node, idx) {
var left = node.previousElementSibling,
right = node.nextElementSibling;

return isFilled(left) && isFilled(right);
}

function checkVerticalLines (node, idx) {
var row = node.parentNode,
up = row.previousElementSibling.children[idx],
down = row.nextElementSibling.children[idx];

return isFilled(up) && isFilled(down);
}

function checkSurroundingLines (node) {
var idx = nodeIndex(node),
surrounded = checkVerticalLines (node, idx) && checkHorizontalLines(node, idx);

if (surrounded) {
node.classList.add('marked');
node.classList.add(currentPlayer.className);
return true;
}
}

function checkHorizontalBoxes (line) {
var left = line.previousElementSibling,
right = line.nextElementSibling;

if (left) checkSurroundingLines(left);
if (right) checkSurroundingLines(right);
}

function checkVerticalBoxes (line) {
var index = nodeIndex(line),
up = line.parentNode.previousElementSibling,
down = line.parentNode.nextElementSibling;

if (up) checkSurroundingLines(up.children[index]);
if (down) checkSurroundingLines(down.children[index]);
}


// State sets

function setInfo () {
turnBox.className = currentPlayer.className;
turnBox.innerHTML = currentPlayer.name + "'s Turn";

players.forEach(function (p) {
document.getElementById(p.scoreBox).innerHTML = p.score;
});
}

function getScores() {
players.forEach(function (p) {
p.score = document.querySelectorAll('.box.marked.'+p.className).length;
});
}

function changeTurn () {
currentPlayerIdx = 1 - currentPlayerIdx;
currentPlayer = players[currentPlayerIdx];

setInfo();
}

function updateGame() {
getScores();
changeTurn();
}

// Events

function addHLine (e) {
fill(this);
this.removeEventListener(e.type, addHLine);
checkVerticalBoxes(this);
updateGame();
}

function addVLine (e) {
fill(this);
this.removeEventListener(e.type, addVLine);
checkHorizontalBoxes(this);
updateGame();
}

function assignHandler (sel, ev, fn) {
var els = document.querySelectorAll(sel);
toArray(els).forEach(function (el) {
el.addEventListener(ev, fn);
});
}

assignHandler('.hLine', 'click', addHLine);
assignHandler('.vLine', 'click', addVLine);


setInfo();
h3 {
font-family: Arial;
}
table {
border-collapse: collapse;
}
.vLine {
width: 10px;
height: 60px;
}
.box {
width: 60px;
height: 60px;
}
.hLine {
width: 60px;
height: 10px;
}
.gap {
width: 10px;
height: 12px;
background-color: #333;
}
.vLine:not(.filled):hover,
.hLine:not(.filled):hover {
background-color: #333;
}

.filled {
background-color: grey;
}

.marked {
background-color: green;
}

.box.blue-mark {
background-color: #3355ff;
}

.box.red-mark {
background-color: #ff5533;
}

#turn.blue-mark,
#p1 {
color: #3355ff;
}

#turn.red-mark,
#p2 {
color: #ff5533;
}
<h3 id="turn"></h3>
<p class="counts">
<span id="p1"></span> -
<span id="p2"></span>
</p>

<table>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
<tr>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
<td class="box"></td>
<td class="vLine"></td>
</tr>
<tr>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
<td class="hLine"></td>
<td class="gap"></td>
</tr>
</table>

关于javascript - 检查周围的表格单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31151150/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com