算法连接四个javascript

时间:2012-02-17 15:39:55

标签: javascript jquery html

HY, 我试图在javascript / jQuery中实现Connect Four Game。首先,这不是家庭作业或任何其他职责。我只是想提升自己的能力。

我的“游乐场”是一个简单的html table,有7行6列 但现在我已经到了我的身边。我坚持检查是否有4个相同的td的主要功能。我正在添加一个类来确定它应该在游戏中代表哪种颜色。 首先,我认为我可以使用.nextAll().prevAll()处理此事,但这对我不起作用,因为之间没有检测。
因为我正在寻找兄弟姐妹,在添加一个新项目时,只是查看了找到的兄弟姐妹的长度,如果他们最终匹配4我认为这是对的,但不是没有:D是否有任何类型的{ {1}}它提供了所有下一个css选择器,直到出现不同的东西?

我会将所有代码放入此jsfiddle:http://jsfiddle.net/LcUVf/5/

也许某人曾经尝试过同样的事情,或者有人提出了一个好主意我不会要求任何人做或完成我的代码。我只想获得实现这样一个算法或示例如何解决它的提示!

无论如何,谢谢!

3 个答案:

答案 0 :(得分:12)

DOM遍历不是特别有效,因此,当你可以避免它时,我建议这样做。将它构建为2D数组以存储和更新游戏状态是有意义的。该表只是数组的直观表示。

我知道,通常情况下,您将构建数组,其中行作为第一维,列作为第二维,但为了能够将碎片添加到每个列的“堆栈”,我会创建第一个维度列和第二维是行。

要做检查,看看我做的小提琴:

http://jsfiddle.net/Koviko/4dTyw/

有4个方向可供选择:南北,东西,东北 - 西南和东南 - 西北。这可以表示为具有为X和Y定义的增量的对象:

directions = [
  { x: 0, y: 1  }, // North-South
  { x: 1, y: 0  }, // East-West
  { x: 1, y: 1  }, // Northeast-Southwest
  { x: 1, y: -1 }  // Southeast-Northwest
];

然后,循环通过该对象并循环通过你的“桌子”,从最远的边界开始,这件作品可能有助于获胜。因此,由于您需要连续4件,所以当前放置的部件可以在任何方向上赢得最多3件。

minX = Math.min(Math.max(placedX - (3 * directions[i].x), 0), pieces.length    - 1);
minY = Math.min(Math.max(placedY - (3 * directions[i].y), 0), pieces[0].length - 1);
maxX = Math.max(Math.min(placedX + (3 * directions[i].x),     pieces.length    - 1), 0);
maxY = Math.max(Math.min(placedY + (3 * directions[i].y),     pieces[0].length - 1), 0);

为了避免使用小于和大于(我遇到过)的任何问题,请计算循环遍历各个部分之前的步骤数,而不是使用计算出的边界作为条件。

steps = Math.max(Math.abs(maxX - minX), Math.abs(maxY - minY));

最后,遍历项目,保持与最后放置的棋子相匹配的连续棋子的数量。

function isVictory(pieces, placedX, placedY) {
  var i, j, x, y, maxX, maxY, steps, count = 0,
    directions = [
      { x: 0, y: 1  }, // North-South
      { x: 1, y: 0  }, // East-West
      { x: 1, y: 1  }, // Northeast-Southwest
      { x: 1, y: -1 }  // Southeast-Northwest
    ];

  // Check all directions
  outerloop:
  for (i = 0; i < directions.length; i++, count = 0) {
    // Set up bounds to go 3 pieces forward and backward
    x =     Math.min(Math.max(placedX - (3 * directions[i].x), 0), pieces.length    - 1);
    y =     Math.min(Math.max(placedY - (3 * directions[i].y), 0), pieces[0].length - 1);
    maxX =  Math.max(Math.min(placedX + (3 * directions[i].x),     pieces.length    - 1), 0);
    maxY =  Math.max(Math.min(placedY + (3 * directions[i].y),     pieces[0].length - 1), 0);
    steps = Math.max(Math.abs(maxX - x), Math.abs(maxY - y));

    for (j = 0; j < steps; j++, x += directions[i].x, y += directions[i].y) {
      if (pieces[x][y] == pieces[placedX][placedY]) {
        // Increase count
        if (++count >= 4) {
          break outerloop;
        }
      } else {
        // Reset count
        count = 0;
      }
    }
  }

  return count >= 4;
}

答案 1 :(得分:2)

通常,2维数组更适合检查4行。您可以执行以下操作:

function check( lastPiece, playground, player ) {
   // check length in each direction
   var l = 1, 
       i = 1;

   // top to bottom
   while( (playground[ lastPiece.x ][ lastPiece.y - i ] === player) && ((lastPiece.y - i) >= 0) ) { l += 1; i += 1; };
   i = 1;
   while( (playground[ lastPiece.x ][ lastPiece.y + i ] === player) && ((lastPiece.y + i) <= MAX_Y) ) { l += 1; i += 1; };
   if ( l >= 4 ) { return true; }

   // left to right
   l = 1;
   while( (playground[ lastPiece.x - i][ lastPiece.y ] === player) && ((lastPiece.x - i) >= 0) ) { l += 1; i += 1; };
   i = 1;
   while( (playground[ lastPiece.x + i][ lastPiece.y ] === player) && ((lastPiece.x + i) <= MAX_X) ) { l += 1; i += 1; };
   if ( l >= 4 ) { return true; }

   // same for top left to bottom right and bottom left to top right
   // . . .

   // if we got no hit until here, there is no row of 4
   return false;
}

编辑:添加了对游乐场边框的检查

答案 2 :(得分:2)

我发布了游戏的完整版本on Github

它实现了所提到的algorythm Sirko的优化变体。

为了避免任何不必要的冗余,algorythm直接检查DOM而不是JS表。由于该algorythm需要最少量的检查,因此访问DOM的性能开销可以忽略不计。

当前玩家和用于跟踪游戏是否已经结束的标志基本上是存储在JS本身中的唯一状态。

我甚至使用DOM来存储字符串。它没有外部依赖性,IE6以上的所有IE版本以及现代浏览器都支持它。

代码针对文件大小和性能进行了优化。最新版本还包括动画,即使游戏的总JS代码在缩小后仍然只有 1.216字节


守则:

这是完整的,未缩小的JS代码:

(function (doc, win, onclick, gid, classname, content, showMessage) {
    var
        a, b, c, colorLabel, cid, players, current, finished, newgameLabel, wonLabel, laststart = 1,
        cellAt = function (i, j) {
            return doc[gid](cid + i + j);
        },
        isCurrentColor = function (i, j) {
            return cellAt(i, j)[classname] === players[current];
        },
        start = function () {
            current = laststart = (laststart + 1) % 2;
            finished = 0;
            colorLabel[content] = colorLabel[classname] = players[current = (current + 1) % 2];
            for (a = 1; a < 7; a++)
                for (b = 1; b < 8; b++)
                    cellAt(a, b)[classname] = '';
        },
        makeMove = function (i, j, s) {
            s > 0 && (cellAt(s, j)[classname] = '');
            cellAt(s + 1, j)[classname] = players[current];
            s === i - 1 ? function (i, j) {
                return function (i, j) {
                    for (a = j - 1; 0 < a && isCurrentColor(i, a); a--) {
                    }
                    for (b = j + 1; 8 > b && isCurrentColor(i, b); b++) {
                    }
                    return 4 < b - a;
                }(i, j) || function (i, j) {
                    for (c = i + 1; 7 > c && isCurrentColor(c, j); c++) {
                    }
                    return 3 < c - i;
                }(i, j) || function (i, j) {
                    for (a = i - 1, b = j - 1; 0 < a && !(1 > b) && isCurrentColor(a, b); a--)
                        b--;
                    for (c = i + 1, b = j + 1; 7 > c && !(7 < b) && isCurrentColor(c, b); c++)
                        b++;
                    return 4 < c - a
                }(i, j) || function (i, j) {
                    for (a = i - 1, b = j + 1; 0 < a && !(7 < b) && isCurrentColor(a, b); a--)
                        b++;
                    for (c = i + 1, b = j - 1; 7 > c && !(1 > b) && isCurrentColor(c, b); c++)
                        b--;
                    return 4 < c - a;
                }(i, j);
            }(i, j)
                    ? finished = 1 && win[showMessage](doc[gid](wonLabel)[content].replace("%s", players[current].toLowerCase())) && start()
                    : colorLabel[content] = colorLabel[classname] = players[current = (current + 1) % 2]
                    : setTimeout(function () {
                        makeMove(i, j, s + 1)
                    }, 20);

        };

    return function (n, w, c, h, p1, p2) {
        cid = c;
        newgameLabel = n;
        wonLabel = w;
        colorLabel = doc[gid](c);
        players = [doc[gid](p1)[content], doc[gid](p2)[content]];
        for (a = 1; a < 7; a++)
            for (b = 1; b < 8; b++)
                cellAt(a, b)[onclick] = function (b, a) {
                    return function () {
                        if (!finished)
                            for (a = 6; a > 0; a--)
                                if (!cellAt(a, b)[classname]) {
                                    makeMove(a, b, 0);
                                    break;
                                }
                    };
                }(b);
        ;
        doc[gid](h)[onclick] = function () {
            win[showMessage](doc[gid](newgameLabel)[content]) && start()
        };
        start();
    };
})(document, window, "onclick", "getElementById", "className", "innerHTML", "confirm")("newgame", "won", "color", "restart", "p1", "p2");

截图:

enter image description here