这是传递给事件监听器的函数中的一个switch语句,用于跟踪玩家是否获胜。必须有一种更快的方法来比较获胜序列(在每种情况下)。有没有一个函数或循环可以让这更简单。如果这是一款更大的游戏,那么编写代码将是难以忍受的。非常感谢,如果你能帮助:)
let keepTrackPlayerTwo = [];
function addSVGs(e) {
whosGo ++;
if(whosGo % 2 === 0) {
this.innerHTML = circle;
this.removeEventListener("click",addSVGs);
keepTrackPlayerTwo += this.id;
} else{
this.innerHTML = cross;
this.removeEventListener("click",addSVGs);
keepTrackPlayerOne += this.id;
}
switch(keepTrackPlayerOne) {
// Up Top
case '012': console.log('testy'); break;
case '021': console.log('testy'); break;
case '120': console.log('testy'); break;
case '102': console.log('testy'); break;
case '201': console.log('testy'); break;
case '210': console.log('testy'); break;
// Middle
case '345': console.log('testy'); break;
case '354': console.log('testy'); break;
case '543': console.log('testy'); break;
case '534': console.log('testy'); break;
case '453': console.log('testy'); break;
case '435': console.log('testy'); break;
// bottom
case '678': console.log('testy'); break;
case '687': console.log('testy'); break;
case '786': console.log('testy'); break;
case '768': console.log('testy'); break;
case '876': console.log('testy'); break;
case '867': console.log('testy'); break;
// left
case '036': console.log('testy'); break;
case '063': console.log('testy'); break;
case '360': console.log('testy'); break;
case '306': console.log('testy'); break;
case '630': console.log('testy'); break;
case '603': console.log('testy'); break;
// middle
case '147': console.log('testy'); break;
case '174': console.log('testy'); break;
case '417': console.log('testy'); break;
case '471': console.log('testy'); break;
case '741': console.log('testy'); break;
case '714': console.log('testy'); break;
// right
case '258': console.log('testy'); break;
case '285': console.log('testy'); break;
case '582': console.log('testy'); break;
case '528': console.log('testy'); break;
case '852': console.log('testy'); break;
case '825': console.log('testy'); break;
// diagonal left
case '048': console.log('testy'); break;
case '084': console.log('testy'); break;
case '408': console.log('testy'); break;
case '480': console.log('testy'); break;
case '840': console.log('testy'); break;
case '804': console.log('testy'); break;
// diagonal right
case '246': console.log('testy'); break;
case '264': console.log('testy'); break;
case '462': console.log('testy'); break;
case '426': console.log('testy'); break;
case '642': console.log('testy'); break;
case '624': console.log('testy'); break;
}
}
您最好将这项工作委托给一个单独的函数。您可以在下面的演示中查看checkForWinner
——由defineGroupsOfThree
支持——以了解它可能是什么样子的。
我已经用JavaScript编写了几次TicTacToe,我选择提供这个特定的版本,因为它相当简单(尽管如果你是JavaScript新手,可能需要一些研究)。我已经包含了大量的注释来澄清它们是如何结合在一起的。
主要思想是将游戏的当前状态保持在单个state
对象中,这是应用程序的真相来源。当用户采取行动时,updateState
函数执行任何更改,repaintDOM
函数更新视图。所有这些都是由点击侦听器功能handleBoardClick
编排的。
如上所述,defineGroupsOfThree
创建了一个数组数组,我们可以使用它来检查是否有人赢得了游戏。这些数组中的每一个都代表一组三个方块(一行、一列或对角线),任何玩家捕获所有三个方块就会赢得游戏。因此checkForWinner
检查当前状态是否与这些获胜组合中的任何一个匹配。(checkForTie
只是检查是否没有剩余的合法走法)
最后,还有另外两个支持函数:isEmptyCell
,如果用户点击一个他们可以合法捕获的方块,它将返回true;getCharFor
,这是一个查找函数,它将获得代表特定玩家的适当字符("X")或" 0 "或"_"无论是)。
最好不要改变状态对象(即更不容易出错)——也就是说,在状态改变时创建一个全新的状态对象,而不影响旧的状态对象。但我觉得这个版本对你们来说可能更直接一些;请注意,这不是最佳实践。(如果您需要练习,一旦您理解了这段代码在做什么,您可以尝试将其更新到使用不可变状态的版本。)
幸福的编码。
// Calls `handleBoardClick` when user clicks on `board` div
const boardDiv = document.getElementById("board-div");
boardDiv.addEventListener("click", handleBoardClick);
// Sets initial state for the game
let state = {
board: [[0,0,0], [0,0,0], [0,0,0]], // Three rows, three 0s in each row
player: 1, // 1st player (X) has value 1; 2nd player (0) will have -1
winner: void 0 // Neither player has won yet
}
// Defines groupsOfThree (to be used in `checkForWinner`)
const groupsOfThree = defineGroupsOfThree(state.board);
// Displays initial board
repaintDOM(state);
//
// Defines all game functions, starting with the click listener
//
function handleBoardClick(event){
const target = event.target;
// Makes sure user clicked an empty cell before proceeding
if(isEmptyCell(target)){
// Updates the state and repaints the DOM
const {row, col } = target.dataset;
updateState(row, col, state, groupsOfThree);
repaintDOM(state);
// Announces winner if any
if(state.winner){
console.log(`The winner is ${getCharFor(state.winner)}`);
boardDiv.removeEventListener("click", handleBoardClick);
}
// Announces tie if board is full with no winner
else if(checkForTie(state)){
console.log("Another tie game");
}
}
}
function updateState(row, col){
state.board[row][col] = state.player; // Assigns current player to square
state.player *= -1; // Works because player numbers are 1 and -1
state.winner = checkForWinner(state, groupsOfThree); // 1, -1, or undefined
}
function repaintDOM(state){
// Recalculates all squares' contents (even unchanged ones, a bit wasteful)
for (let rowDiv of boardDiv.children){
for (let cellDiv of rowDiv.children){
const
// Retrieves row & col info from each square's data attributes
row = cellDiv.dataset.row,
col = cellDiv.dataset.col;
playerValue = state.board[row][col]; // Gets player value from the board
char = getCharFor(playerValue);
cellDiv.textContent = char; // Shows `X` or `O` (or leaves default `_`)
}
}
//console.log(`It's ${getCharFor(state.player)}'s turn`);
}
function checkForWinner(state, groupsOfThree){
// (Claim all 3 cells in any group to win)
// Makes an array of 8 sums (3 for rows, 3 for cols, and 2 for diags)
const groupSums = groupsOfThree.map(group => { // `map` loops thru groups, gets each sum
let groupSum = 0;
for(let {row, col} of group){ // Destructures current array element to row & col
// Gets the player value from the board (1 or -1) and adds it to the sum
groupSum += state.board[row][col];
}
return groupSum; // Next value returned from `map` (for groupSums array)
});
// Now that `groupSums` array is ready, checks all sums for a winner
// Sum will equal 3 or -3 (ie playerValue * 3) if a player has all 3 cells
// If so, that player's value is returned to `handleBoardClick`
for(let groupSum of groupSums){
if(groupSum == 3){ return 1; }
else if(groupSum == -3){ return -1; }
}
}
function checkForTie(state){
// If any cell in any row still has default value, there is no tie
for(let row of state.board){
if(row.some(cellValue => cellValue == 0))
return false;
}
return true; // If we got this far, there are no empty squares: game over
}
function defineGroupsOfThree(board){
// Creates and returns an array containing 8 arrays (8 "groups")
// Each group contains 3 objects, representing coordinates for cells on the board
const groups = [
// Rows
[ {row: 0, col: 0}, {row: 1, col: 0}, {row: 2, col: 0} ],
[ {row: 0, col: 1}, {row: 1, col: 1}, {row: 2, col: 1} ],
[ {row: 0, col: 2}, {row: 1, col: 2}, {row: 2, col: 2} ],
// Cols
[ {row: 0, col: 0}, {row: 0, col: 1}, {row: 0, col: 2} ],
[ {row: 1, col: 0}, {row: 1, col: 1}, {row: 1, col: 2} ],
[ {row: 2, col: 0}, {row: 2, col: 1}, {row: 2, col: 2} ],
// Diags
[ {row: 0, col: 0}, {row: 1, col: 1}, {row: 2, col: 2} ],
[ {row: 2, col: 0}, {row: 1, col: 1}, {row: 0, col: 2} ]
];
return groups;
}
function isEmptyCell(eventTarget){
return eventTarget.classList.contains("cell") && eventTarget.textContent == "_";
}
function getCharFor(playerValue){
// Player 1 is always "X"; player -1 is "O"
if(playerValue == 1){ return "X"; }
else if(playerValue == -1){ return "O"; }
else if(playerValue == 0){ return "_"; }
else{ console.log("This is not possible"); }
}
div { margin: 0; padding: 1ch; }
.cell { display: inline-block; font-family: monospace; }
<div id="board-div">
<div class="row">
<!-- data-attributes for each cell remember the position -->
<div class="cell" data-row="0" data-col="0"> </div>
<div class="cell" data-row="0" data-col="1"> </div>
<div class="cell" data-row="0" data-col="2"> </div>
</div>
<div class="row">
<div class="cell" data-row="1" data-col="0"> </div>
<div class="cell" data-row="1" data-col="1"> </div>
<div class="cell" data-row="1" data-col="2"> </div>
</div>
<div class="row">
<div class="cell" data-row="2" data-col="0"></div>
<div class="cell" data-row="2" data-col="1"></div>
<div class="cell" data-row="2" data-col="2"></div>
</div>
</div>