Javascript 检查数组的更好方法

Javascript 检查数组的更好方法,javascript,arrays,sorting,Javascript,Arrays,Sorting,我正在做一个井字游戏,在如何简化一些检查方面遇到了困难。下面你会看到一个水平、垂直和对角线的检查,看一个玩家是否赢了 问题:在不重复这么多代码的情况下,我可以用什么来简化这个问题?我们非常感谢在正确方向上的任何指导 该数组如下所示: gridArray: [ ['', '', ''], ['', '', ''], ['', '', ''], ] 播放时,playerTurn变量只是从x变为o // Horizontal check state.gridArray.m

我正在做一个井字游戏,在如何简化一些检查方面遇到了困难。下面你会看到一个水平、垂直和对角线的检查,看一个玩家是否赢了

问题:在不重复这么多代码的情况下,我可以用什么来简化这个问题?我们非常感谢在正确方向上的任何指导

该数组如下所示:

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!');
}
}

谢谢

您可以尝试使用数字值,如1和4,而不是使用字符串检查“X”或“O”的值,这样可以对每个轴的值求和。然后,如果其值为0,则该轴上没有移动,如果该值为3,则该轴的“X”移动获胜,如果其值为12,则该轴的“O”移动获胜


thx@4castle为了指出这一点,我做了更正,而不是用字符串来检查“X”或“O”的值。你可以尝试使用数字值,如1和4,以这种方式对每个轴的值求和。然后,如果其值为0,则该轴上没有移动,如果该值为3,则该轴的“X”移动获胜,如果其值为12,则该轴的“O”移动获胜


thx@4castle为了指出这一点,这确实是一个假阳性,我做了更正

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

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));
}
注:网格中的数值为1表示“X”,2表示“O”。使用字符串
display=['''X','O']
很容易将一个转换为另一个

可供替代的 如果你真的想得到高效的代码,你可以回到位操作,用两个整数来表示网格,一个用于“X”位置,另一个用于“O”位置。您将使用每个整数的9位。使用相同的原则,您可以定义构成win的所有位掩码,并使用这些掩码执行
&
,以查看是否有匹配项

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);
}

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

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));
}
注:网格中的数值为1表示“X”,2表示“O”。使用字符串
display=['''X','O']
很容易将一个转换为另一个

可供替代的 如果你真的想得到高效的代码,你可以回到位操作,用两个整数来表示网格,一个用于“X”位置,另一个用于“O”位置。您将使用每个整数的9位。使用相同的原则,您可以定义构成win的所有位掩码,并使用这些掩码执行
&
,以查看是否有匹配项

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);
}

使用嵌套的
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;
}
函数whowen(网格){
var i,j,
rX,rO,
cX公司,
ddX,ddO,
杜,杜,;
ddX=ddO=duX=duO=0;
对于(i=0;i<3;++i){
rX=rO=cX=cO=0;
对于(j=0;j<3;++j){
如果(网格[i][j]=='x')++rX;
else if(网格[i][j]='o')++rO;
如果(网格[j][i]=='x')++cX;
else if(grid[j][i]=='o')++cO;
}
如果(网格[i][i]=='x')++ddX;
else if(网格[i][i]=='o')++ddO;
如果(网格[2-i][i]=='x')++duX;
else if(grid[2-i][i]=='o')++duO;
}
if(数学最大值(rX,cX,ddX,duX)==3)返回'x';
if(Math.max(rO,cO,ddO,duO)==3)返回'o';
返回null;
}

使用嵌套的
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;
}
函数whowen(网格){
var i,j,
rX,rO,
cX公司,
ddX,ddO,
杜,杜,;
ddX=ddO=duX=duO=0;
对于(i=0;i<3;++i){
rX=rO=cX=cO=0;
对于(j=0;j<3;++j){
如果(网格[i][j]=='x')++rX;
else if(网格[i][j]='o')++rO;
如果(网格[j][i]=='x')++cX;
else if(grid[j][i]=='o')++cO;
}
如果(网格[i][i]=='x')++ddX;
else if(网格[i][i]=='o')++ddO;
如果(网格[2-i][i]=='x')++duX;
else if(grid[2-i][i]=='o')++duO;
}
if(数学最大值(rX,cX,ddX,duX)==3)返回'x';
if(Math.max(rO,cO,ddO,duO)==3)返回'o';
返回null;
}
位板和查找表 测试获胜位置最有效的方法之一是使用和查找表

位盘在国际象棋引擎中很常用,其中64位整数的每一位都描述了一个正方形的给定属性,例如“一块白色的棋子在这个正方形上”或“一个主教在这个正方形上”

对于Tic-Tac-Toe,我们只需要两个比特板来描述游戏:一个用于“X”侧,另一个用于“O”侧。每个位板由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)
让我们看看位置是如何编码的,这里是“X”侧:

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; });
}
当然,对于这样一个简单的游戏来说,这有点过头了,但同样的想法也适用于更复杂的游戏

此外,如果您想实现“人机对抗”版本,您的AI可以使用
isWin[]
快速评估