检查数组的更好方法

时间:2016-07-24 22:50:00

标签: javascript arrays sorting

我正在通过一个tic tac toe游戏,并且真的碰壁了如何简化一些检查。您可以在下方找到水平,垂直和对角线检查以确定玩家是否赢了。

问题:如果不重复这么多代码,我可以使用哪些来简化此操作?非常感谢任何正确方向的指导。

数组如下所示:

gridArray: [
    ['', '', ''],
    ['', '', ''],
    ['', '', ''],
  ]

播放时,playerTurn变量只是从x变为o。

// Horizontal check
state.gridArray.map((item, index) => {
  if(
    item[0] === playerTurn &&
    item[1] === playerTurn &&
    item[2] === playerTurn) {
    console.log(playerTurn + ' has won!');
  }
});



// Vertical check
if(
  state.gridArray[0][0] === playerTurn &&
  state.gridArray[1][0] === playerTurn &&
  state.gridArray[2][0] === playerTurn
) {
  console.log(playerTurn + ' has won!');
}

if(
  state.gridArray[0][1] === playerTurn &&
  state.gridArray[1][1] === playerTurn &&
  state.gridArray[2][1] === playerTurn
) {
  console.log(playerTurn + ' has won!');
}

if(
  state.gridArray[0][2] === playerTurn &&
  state.gridArray[1][2] === playerTurn &&
  state.gridArray[2][2] === playerTurn
) {
  console.log(playerTurn + ' has won!');
}



// Diagonal check
if(
  state.gridArray[0][0] === playerTurn &&
  state.gridArray[1][1] === playerTurn &&
  state.gridArray[2][2] === playerTurn
) {
  console.log(playerTurn + ' has won!');
}

if(
  state.gridArray[0][2] === playerTurn &&
  state.gridArray[1][1] === playerTurn &&
  state.gridArray[2][0] === playerTurn
) {
  console.log(playerTurn + ' has won!');
}
}

谢谢!

4 个答案:

答案 0 :(得分:4)

您可以使用略有不同的数据结构,只有1维和数字内容。然后,您可以定义另一个变量,该变量列出该结构中表示胜利的所有三元组索引。有了这个设置,检测胜利的功能几乎成了一个单一的:

var gridArray = [
    0, 0, 0,
    0, 0, 0,
    0, 0, 0,
]; 

var lines = [
    [0,1,2],
    [3,4,5],
    [6,7,8],
    [0,3,6],
    [1,4,7],
    [2,5,8],
    [0,4,8],
    [2,4,6]
];

function hasWon(gridArray, lines, playerTurn) {
    return lines.some(line => line.every(cell => gridArray[cell] === playerTurn));
}

注意:网格中的数值对于'X'将变为1,对于'O'将变为2。使用字符串display = [' ', 'X', 'O']可以很容易地将一个字符串转换为另一个字符串。

替代

如果你真的想要获得有效的代码,你可以恢复位操作,并用两个整数表示网格,一个用于'X'位置,一个用于'O'位置。您将使用每个整数的9位。使用相同的原则,您可以定义构成胜利的所有位掩码,并使用&来查看是否匹配。

var gridArray = [0b000000000, 0b000000000]; // X bits, O bits

var lines = [
    0b111000000,
    0b000111000,
    0b000000111,
    0b100100100,
    0b010010010,
    0b001001001,
    0b100010001,
    0b001010100
];

function hasWon(gridArray, lines, playerTurn) {
    return lines.some(line => (line & gridArray[playerTurn]) == line);
}

答案 1 :(得分:2)

使用嵌套的for,此功能可以在任何状态下查看游戏,并通过计算X和Os的数量来告诉您获胜者是否和谁

function whoWon(grid) {
    var i, j,
        rX, rO,
        cX, cO,
        ddX, ddO,
        duX, duO;
    ddX = ddO = duX = duO = 0;
    for (i = 0; i < 3; ++i) {
        rX = rO = cX = cO = 0;
        for (j = 0; j < 3; ++j) {
            if (grid[i][j] === 'x') ++rX;
            else if (grid[i][j] === 'o') ++rO;

            if (grid[j][i] === 'x') ++cX;
            else if (grid[j][i] === 'o') ++cO;
        }
        if (grid[i][i] === 'x') ++ddX;
        else if (grid[i][i] === 'o') ++ddO;

        if (grid[2 - i][i] === 'x') ++duX;
        else if (grid[2 - i][i] === 'o') ++duO;
    }
    if (Math.max(rX, cX, ddX, duX) === 3) return 'x';
    if (Math.max(rO, cO, ddO, duO) === 3) return 'o';
    return null;
}

答案 2 :(得分:0)

而不是使用字符串来检查&#39; X&#39;的值。或者&#39; O&#39;您可以尝试使用数值,如1和4,这样可以对每个轴的值求和。然后,如果它的值为0,那么该轴上没有移动,如果该值为3,则该轴具有“X&#39;”的获胜移动。如果它的值是12,那么它就是“O&#39”的胜利之举。

thx @ 4castle指出,我做了修正确实是误报

答案 3 :(得分:0)

Bitboards&amp;查找表

测试获胜位置的最有效方法之一是使用bitboards和查找表。

Bitboard在Chess引擎中很常用,其中64位整数的每个位都描述了一个正方形的给定属性,例如&#39;白色方块就在这个方块上&#39;主教在这个广场上

对于Tic-Tac-Toe,我们只需要两个位板来描述游戏:一个用于&#39; X&#39;方和一方用于&#39; O&#39;侧。每个位板由9位组成:

8 7 6     // where 8 is the most significant bit
5 4 3     // and 0 is the least significant bit
2 1 0     // (we could do it the other way around just as well)

让我们看一下如何对一个位置进行编码,这里针对&#39; X&#39;侧:

X . X     1 0 1
. X .  =  0 1 0  =  101010011 in binary  =  0x153 in hexadecimal
. X X     0 1 1

现在,让我们编码所有获胜的配置:

X X X   . . .   . . .   X . .   . X .   . . X   X . .   . . X
. . .   X X X   . . .   X . .   . X .   . . X   . X .   . X .
. . .   . . .   X X X   X . .   . X .   . . X   . . X   X . .
0x1C0   0x038   0x007   0x124   0x092   0x049   0x111   0x054

给定一方只有2 ^ 9 = 512个可能的位置(包括一些实际上无法到达的位置)。因此,构建一个包含所有512个位置的查找表是完全可行的,这将告诉我们它是否是一个胜利:

var winMask = [ 0x1C0, 0x038, 0x007, 0x124, 0x092, 0x049, 0x111, 0x054 ],
    isWin = [];

for(var n = 0; n < 512; n++) {
  isWin[n] = winMask.some(function(msk) { return (n & msk) == msk; });
}

现在,我们可以做类似的事情:

if(isWin[xBoard]) {
  console.log('X has won!');
}

当然,对于这样一款简单的游戏来说,这有点过分,但同样的想法也适用于更复杂的游戏。

此外,如果您想要实施“人类与计算机”这样的话。版本,您的AI可以使用isWin[]在搜索树的叶节点上快速评估游戏的结果。

实施

以下是使用我们刚刚描述的技术对整个游戏的简单实现。

在这里,您可以看到使用位板轻松实现的其他两项操作:

  • 检查单元格是否为空:!((board[0] | board[1]) & msk)
  • 检查整个电路板是否已填满:(board[0] | board[1]) == 0x1ff

&#13;
&#13;
var winMask = [ 0x1C0, 0x038, 0x007, 0x124, 0x092, 0x049, 0x111, 0x054 ],
    isWin = [],
    board, player;

for(var n = 0; n < 512; n++) {
  isWin[n] = winMask.some(function(msk) { return (n & msk) == msk; });
}

$('button').click(function() {
  var msk = 0x100 >> $('button').index(this);

  if(!((board[0] | board[1]) & msk)) {
    $(this).html('XO'[player]);
    board[player] |= msk;
    
    if(isWin[board[player]]) {
      alert('XO'[player] + ' has won!');
      newGame();
    }
    else if((board[0] | board[1]) == 0x1ff) {
      alert('This is a draw!');
      newGame();
    }
    else {
      player ^= 1;
    }
  }
});
newGame();

function newGame() {
  board = [ 0, 0 ];
  player = 0;
  $('button').html('.');
}
&#13;
button { width:32px; }
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div><button></button><button></button><button></button></div>
<div><button></button><button></button><button></button></div>
<div><button></button><button></button><button></button></div>
&#13;
&#13;
&#13;