问题描述
<table>
<tbody>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
</tbody>
</table>
我为所有按钮创建了数组
var btnIns = document.querySelectorAll(".btn-in");
然后我写了这个
var arrForPcTurns = [...btnIns];
所以 btnIns 和 arrForPcTurns 必须具有相同的值
然后我尝试从 arrForPcTurns 数组中删除特定元素
btnIns.forEach(obj => {
// obj.addEventListener("click",function () {
// if (counter % 2 != 0) {
// sign = player;
// turn.textContent = "PC Turn";
// } else {
// sign = PC;
// turn.textContent = "Your Turn";
// }
// this.textContent = sign;
// counter++;
// if (obj != "") {
// this.style.cursor = "not-allowed";
// this.disabled = true;
// }
// if (counter == 10) {
// setTimeout(function () {
// reloadBtn.classList.remove("display-none");
// alert("Draw");
// },400);
// }
// checkWinProbablity();
arrForPcTurns.splice(arrForPcTurns.indexOf(this));
});
});
但单击它会从数组中删除所有 9 个元素 我该怎么办?
解决方法
这就是拼接的工作原理
让 myArray= [1,2,3,4,5];
让删除数组 = myArray.splice(0,3);
以下语句从第一个元素开始删除 myArray 的三个元素。
myArray 现在包含两个元素。 // [4,5]
splice(第一个要删除的item的位置,要删除的item个数)
var btnIns = document.querySelectorAll(".btn-in");
var arrForPcTurns = [...btnIns];
console.log(arrForPcTurns);
btnIns.forEach(obj => {
obj.addEventListener("click",function () {
arrForPcTurns.splice(arrForPcTurns.indexOf(this,1));
console.log(arrForPcTurns);
})
});
<table>
<tbody>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
<tr>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
<td><button class="btn-in"></button></td>
</tr>
</tbody>
</table>
如果您正在设计井字游戏,则需要跟踪当前的 turn
和 done
状态。您可以抓取矩阵并抓取每个按钮(单元格)的玩家数据,以确定该单元格是否可用。
在玩家决定标记的位置后,您可以让AI玩家分析当前棋盘并进行移动。
这是查找第一个可用单元格的基本扫描:
const handleAI = (game,player) => {
updateInfo(`Player ${player},is thinking...`,game);
lock = true;
setTimeout(() => {
const cell = analyzeMatrix(stateMatrix());
lock = false;
triggerEvent(cell,'click');
},cpuWait);
};
您可以在此函数中添加一些逻辑,通过在做出选择之前寻找模式来改进 AI 的决策。
演示
const find = (selector,parent = document) => parent.querySelector(selector);
const findAll = (selector,parent = document) => parent.querySelectorAll(selector);
const findParent = (selector,parent) => parent.closest(selector);
const triggerEvent = (el,eventName,data={}) => {
let event;
if (window.CustomEvent && typeof window.CustomEvent === 'function') {
event = new CustomEvent(eventName,{ detail: data });
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(eventName,true,data );
}
el.dispatchEvent(event);
};
const addEvents = (el,events) => Object.entries(events)
.forEach(([type,listener]) => el.addEventListener(type,listener));
const players = ['O','X'];
let
turn = 0,done = false,lock = false;
const main = () => {
findAll('.cell').forEach(btn => addEvents(btn,{
'click': handleClick,'mouseenter': handleMouseEnter,'mouseleave': handleMouseLeave
}));
addEvents(find('.new-game'),{
'click': handleReset
});
initialize(find('.tic-tac-toe'));
};
const currentPlayer = () => players[turn % players.length];
const stateMatrix = (tbody) =>
[...findAll('tr',tbody)].map(tr =>
[...findAll('td',tr)].map(td =>
find('button',td)));
const markCell = (cell,player) => {
cell.textContent = player;
cell.dataset.player = player;
};
const initialize = (game) => {
turn = 0;
done = false
cpuEnabled = true,cpuWait = 1000;
const table = game.querySelector('table');
findAll('button',table).forEach(btn => {
btn.classList.remove('win');
btn.textContent = '';
delete btn.dataset.player;
});
promptPlayer(game);
};
const promptPlayer = (game) => {
const player = currentPlayer();
if (cpuEnabled && player === 'X') {
handleAI(game,player);
} else {
updateInfo(`Player ${player},it's your turn.`,game);
}
};
const handleAI = (game,cpuWait);
};
// Business logic here...
const analyzeMatrix = (matrix) => {
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix.length; col++) {
const cell = matrix[row][col];
if (cell.dataset.player == null) {
return cell;
}
}
}
return null;
};
const handleClick = e => {
const
btn = e.target,game = findParent('.tic-tac-toe',btn);
if (!done && !lock && btn.dataset.player == null) {
const player = currentPlayer();
markCell(btn,player);
btn.textContent = player;
btn.dataset.player = player;
const result = checkWin(player,btn);
if (result) {
establishWin(result);
displayWinCondition(game,result);
done = true;
} else {
turn++;
promptPlayer(game);
}
}
};
const establishWin = (result) => {
switch (result.type) {
case 'row':
highlightRow(result.value,result.matrix);
break;
case 'column':
highlightColumn(result.value,result.matrix);
break;
case 'diagonal':
highlightDiagonal(result.value,result.matrix);
break;
case 'draw':
break;
}
};
const displayWinCondition = (game,result) => {
if (result.type === 'draw') {
updateInfo('Draw!',game);
} else {
updateInfo(`Player ${result.player} wins!`,game);
}
};
// Check winning conditions
const checkWin = (player,btn) => {
const matrix = stateMatrix(btn.closest('td').closest('tr').closest('tbody'));
let result;
result = checkWinRows(player,matrix);
if (result) return result;
result = checkWinCols(player,matrix);
if (result) return result;
result = checkWinDiagonals(player,matrix);
if (result) return result;
if (turn >= matrix.length ** 2 - 1) {
return {
type: 'draw'
};
}
return null;
}
const checkWinRows = (player,matrix) => {
for (let row = 0; row < matrix.length; row++) {
if (matrix[row].every(col => col.dataset.player === player)) {
return {
player,matrix,type: 'row',value: row
};
}
}
return null;
}
const checkWinCols = (player,matrix) => {
for (let col = 0; col < matrix.length; col++) {
const values = [];
for (let row = 0; row < matrix.length; row++) {
values.push(matrix[row][col].dataset.player);
}
if (values.every(col => col === player)) {
return {
player,type: 'column',value: col
};
}
}
return null;
}
const checkWinDiagonals = (player,matrix) => {
const
valuesPositive = [],valuesNegative = [];
for (let col = 0; col < matrix.length; col++) {
for (let row = 0; row < matrix.length; row++) {
if (row === col) {
valuesPositive.push(matrix[row][col].dataset.player);
}
if (row === matrix.length - 1 - col) {
valuesNegative.push(matrix[row][col].dataset.player);
}
}
}
if (valuesPositive.every(col => col === player)) {
return {
player,type: 'diagonal',value: +1
};
}
if (valuesNegative.every(col => col === player)) {
return {
player,value: -1
};
}
return null;
}
// Highlight wining sequence
const highlightRow = (index,matrix) => {
for (let row = 0; row < matrix.length; row++) {
if (row === index) {
for (let col = 0; col < matrix[row].length; col++) {
matrix[row][col].classList.add('win');
}
}
}
};
const highlightColumn = (index,matrix) => {
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (col === index) {
matrix[row][col].classList.add('win');
}
}
}
};
const highlightDiagonal = (index,matrix) => {
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (
(index === +1 && row === col) ||
(index === -1 && row === matrix.length - 1 - col)
) {
matrix[row][col].classList.add('win');
}
}
}
};
// Handlers
const handleMouseEnter = e => {
const btn = e.target;
btn.classList.add('hover');
if (done || btn.dataset.player != null) {
btn.classList.add('taken');
}
};
const handleMouseLeave = e => {
const btn = e.target;
btn.classList.remove('hover','taken');
};
const updateInfo = (text,game) => {
game = game || find('.tic-tac-toe');
const info = find('.game-info',game);
info.textContent = text;
};
const handleReset = e => {
initialize(findParent('.tic-tac-toe',e.target));
};
main();
html,body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: #222;
}
body {
display: flex;
}
.game {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
}
.tic-tac-toe {
display: grid;
grid-auto-flow: row;
grid-row-gap: 0.667em;
justify-content: center;
align-items: center;
border: thin solid #666;
padding: 1em;
background: #444;
color: #EEE;
}
.tic-tac-toe>table,.tic-tac-toe tr,.tic-tac-toe td {
margin: 0;
padding: 0;
}
.tic-tac-toe>table {
display: flex;
margin: 0 auto;
}
.tic-tac-toe tbody {
display: grid;
grid-auto-flow: row;
grid-row-gap: 0.25em;
flex: 1;
}
.tic-tac-toe tr {
display: grid;
grid-auto-flow: column;
grid-column-gap: 0.25em;
flex: 1;
}
.tic-tac-toe td {
display: flex;
margin: 0;
padding: 0;
width: 2em;
height: 2em;
}
.tic-tac-toe .cell {
font-size: 1em;
background: #555;
border: none;
text-align: center;
flex: 1;
}
.tic-tac-toe .cell.hover {
cursor: pointer;
background: #777
}
.tic-tac-toe .cell.hover.taken {
cursor: not-allowed;
background: #644
}
.tic-tac-toe .cell.win {
background: #484;
}
.tic-tac-toe .game-info {
text-align: center;
font-size: smaller;
}
.tic-tac-toe .new-game {
margin: 0 auto;
width: 8em;
height: 2em;
font-size: smaller;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet" />
<div class="game">
<div class="tic-tac-toe">
<table>
<tbody>
<tr>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
</tr>
<tr>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
</tr>
<tr>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
<td><button class="cell"></button></td>
</tr>
</tbody>
</table>
<div class="game-info"></div>
<button class="new-game">New Game</button>
</div>
</div>