在JS Connect-Four中返回获胜的单元格坐标

时间:2015-04-11 14:57:47

标签: javascript arrays 2d-games

我正在开发一个JS connect-four游戏。我的'board'是一个7 * 6的数组数组(0 =空,1 =由玩家A占用,-1 =由玩家B占用)。

var boardTwo = [[1,1,1,1,0,0],[-1,-1,-1,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]];

这是我的(长篇)功能,用于检查胜利(任何一个玩家在棋盘中创建了一个完整的水平,垂直或对角线长度4)。如何修改它以便它返回一个带有获胜计数器坐标的数组,而不仅仅是一条警告信息?我很欣赏最好的解决方案可能涉及放弃我原来的checkWin函数来代替更简洁的东西。

checkWin = function(board){
    checkVert(board);
    checkHoriz(board);
    checkDia(board);
    }
winAlert = function(checkSum){
    if(checkSum == 4){
        status = "a"
        alert("a wins"); 
    }
    else if(checkSum == -4){
        status = 'b';
        alert("b wins"); 
    }
}
checkVert = function(board){
    for(var i = 0; i < board.length; i++){
       for(var j = 0; j < board[0].length - 3; j++){
           var checkSum = board[i][j] + board[i][j+1] + board[i][j+2] + board[i][j+3];
           winAlert(checkSum);
           }
    }
}

checkHoriz = function(board){
    for(var i = 0; i < board.length-3; i++){
      for(var j = 0; j < board[0].length; j++){
        var checkSum = board[i][j] + board[i+1][j] + board[i+2][j] + board[i+3][j];
        winAlert(checkSum);
      }
    }
  }

checkDia = function(board){
    for(var i = 0; i < board.length-3; i++){
      for(var j = 0; j < board[0].length - 3; j++){
        var checkSum = board[i][j] + board[i+1][j+1] + board[i+2][j+2] + board[i+3][j+3];
    winAlert(checkSum);
        }
      }
    }
checkWin(boardTwo) //alerts "player A wins"

我想checkWin(boardTwo)返回[[0,0],[0,1],[0,2],[0,3]];

2 个答案:

答案 0 :(得分:1)

这是一个简单的解决方案:

    如果有人赢了,
  • winAlert应该返回一个号码,例如1表示A,-1表示B
  • 每个check函数都会检查此结果,如果它是-1或1,那么它将插入检查的值
  • 如果check方法返回未定义的内容,即带有答案的数组,则不应进行其他检查
  • 最终state持有谁赢了(-1, 1 or undefined),如果有人赢了,checkWin的返回值将是一个数组数组

我还对checkDiagonal方法进行了额外的检查,以检查矩阵中存在的另一个对角线

function sgn(x) {
  if (x < 0) return -1;
  if (x > 0) return 1;
  return 0;
}

function interpolate(from, to) {
  var coordinates = [];
  var startX = from[0];
  var startY = from[1];
  var limit = Math.max(
    Math.abs(from[0] - to[0]),
    Math.abs(from[1] - to[1])
  ) + 1;
  for (i = 0; i < limit; i += 1) {
    coordinates.push([
      startX + i * sgn(to[0] - from[0]),
      startY + i * sgn(to[1] - from[1])
    ]);
  }
  return coordinates;
}

var state;
function checkWin(board) {
  var ans;
  ans = ans || checkVert(board);
  ans = ans || checkHoriz(board);
  ans = ans || checkDia(board);
  return ans;
}

function winAlert(checkSum) {
  if (Math.abs(checkSum) === 4) {
    state = sgn(checkSum);
    return state;
  }
}

checkVert = function(board) {
  for (var i = 0; i < board.length; i++) {
    for (var j = 0; j < board[0].length - 3; j++) {
      var checkSum = board[i][j] + board[i][j + 1] + board[i][j + 2] + board[i][j + 3];
      if (winAlert(checkSum)) {
        return interpolate([i, j], [i, j + 3]);
      }
    }
  }
}

checkHoriz = function(board) {
  for (var i = 0; i < board.length - 3; i++) {
    for (var j = 0; j < board[0].length; j++) {
      var checkSum = board[i][j] + board[i + 1][j] + board[i + 2][j] + board[i + 3][j];
      if (winAlert(checkSum)) {
        return interpolate([i, j], [i + 3, j]);
      }
    }
  }
}

checkDia = function(board) {
  for (var i = 0; i < board.length - 3; i++) {
    for (var j = 0; j < board[0].length - 3; j++) {
      var checkSum = board[i][j] + board[i + 1][j + 1] + board[i + 2][j + 2] + board[i + 3][j + 3];
      if (winAlert(checkSum)) {
        return interpolate([i, j], [i + 3, j + 3]);
      }
    }
  }
  
  // missing diagonal
  for (i = 3; i < board.length; i += 1) {
    for (var j = 0; j < board[0].length - 3; j++) {
      var checkSum = board[i][j] + board[i - 1][j + 1] + board[i - 2][j + 2] + board[i - 3][j + 3];
      if (winAlert(checkSum)) {
        return interpolate([i, j], [i - 3, j + 3]);
      }
    }
  }
}

var board = [
  [1, 1, 1, 0, 0, 0],
  [-1, -1, -1, -1, 0, 0],
  [0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0]
];

var ans = checkWin(board) || [];
document.write(state + '<pre>' + JSON.stringify(ans) + '</pre>');

答案 1 :(得分:1)

我现在看到已经有了答案。我想我应该早点回到这里。我一直在JSFiddle中研究这个版本。请参阅游戏的有用(尽管简单)版本的链接:http://jsfiddle.net/42tfrsva/2/

这不是游戏物理版本的表示,您必须从底部开始并逐步完成游戏。但是,在任何一种情况下,“checkScore()”方法都是相同的,以便扫描棋盘获胜。在这种情况下,该方法返回构成该行的复选框元素,但也可以很容易地修改它以返回每个单元格的坐标。

代码 - HTML

<table>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
    <tr>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
        <td><input type="checkbox" value="0" /></td>
    </tr>
</table>
<div id="player">Player 1</div>
<button id="reset">Reset</button>

代码 - CSS

.player1 {
    background-color: red;
}

.player2 {
    background-color: blue;
}

.winner {
    background-color: green;
}

代码 - JS

var player = 1;

//Set up check events
var cbs = checkboxes();
for (var t = 0; t < cbs.length; t++){
    cbs[t].onclick = checkClick;
}

//Set up reset event
$id("reset").onclick = resetClick;

function resetClick() {
    var cbs = checkboxes();
    for (var c = 0; c < cbs.length; c++) {
        cbs[c].checked = false;
        cbs[c].value = 0;
        cbs[c].parentNode.className = "";
    }
    player = 1;
    $html("player", "Player 1");
}

//create functions
function $id(id) {
    return document.getElementById(id);
}

function $tags(tag, parent) {
    parent = (parent) ? parent : document;
    return parent.getElementsByTagName(tag);
}

function $html(id, html) {
    var el = $id(id);
    if (el) el.innerHTML = html;
}

function checkboxes() {
    var tags = $tags("input");
    var cbs = [];
    for (var t = 0; t < tags.length; t++) {
        if (tags[t].type == "checkbox")
            cbs.push(tags[t]);
    }
    return cbs;
}

function checkClick(e) {
    if (!e || !e.target || !e.target.parentNode
       || e.target.value != "0") {
        e.preventDefault();
        return false;
    }

    e.target.parentNode.className = "player" + player;
    e.target.value = player;

    var path = checkScore();
    if (path.length == 4) {
        alert("Winner player " + player + "!");
        for (var p = 0; p < path.length; p++)
            path[p].parentNode.className = "winner";
    }

    player = (player == 1) ? 2 : 1;
    $html("player", "Player " + player);
}

function valueArray() {
    var values = [];
    var cbs, trs = $tags("tr", $tags("table")[0]);

    for (var t = 0; t < trs.length; t++) {
        cbs = $tags("input", trs[t]);
        var cbarr = [];

        for (var c = 0; c < cbs.length; c++) {
            cbarr.push(cbs[c].value*1);
        }
        values.push(cbarr);
    }

    return values;
}

function cbArray() {
    var values = [];
    var cbs, trs = $tags("tr", $tags("table")[0]);

    for (var t = 0; t < trs.length; t++) {
        cbs = $tags("input", trs[t]);
        var cbarr = [];

        for (var c = 0; c < cbs.length; c++) {
            cbarr.push(cbs[c]);
        }
        values.push(cbarr);
    }

    return values;
}

function checkScore() {
    var path = [];
    var values = valueArray();
    var cbs = cbArray();

    //check up/down
    for (var r = 0; r < 3; r++) {
        for (var c = 0; c < 7; c++) {
            if (values[r][c] == player && values[r+1][c] == player &&
                values[r+2][c] == player && values[r+3][c] == player) {
                path = new Array(
                    cbs[r][c], cbs[r+1][c],
                    cbs[r+2][c], cbs[r+3][c]
                );
                return path;
            }
        }
    }

    //check left/right
    for (var r = 0; r < 6; r++) {
        for (var c = 0; c < 4; c++) {
            if (values[r][c] == player && values[r][c+1] == player &&
                values[r][c+2] == player && values[r][c+3] == player) {
                path = new Array(
                    cbs[r][c], cbs[r][c+1],
                    cbs[r][c+2], cbs[r][c+3]
                );
                return path;
            }
        }
    }

    //check right diagonal
    for (var r = 0; r < 3; r++) {
        for (var c = 0; c < 4; c++) {
            if (values[r][c] == player && values[r+1][c+1] == player &&
                values[r+2][c+2] == player && values[r+3][c+3] == player) {
                path = new Array(
                    cbs[r][c], cbs[r+1][c+1],
                    cbs[r+2][c+2], cbs[r+3][c+3]
                );
                return path;
            }
        }
    }

    //check left diagonal
    for (var r = 0; r < 3; r++) {
        for (var c = 3; c < 7; c++) {
            if (values[r][c] == player && values[r+1][c-1] == player &&
                values[r+2][c-2] == player && values[r+3][c-3] == player) {
                path = new Array(
                    cbs[r][c], cbs[r+1][c-1],
                    cbs[r+2][c-2], cbs[r+3][c-3]
                );
                return path;
            }
        }
    }

    return path;
}

我意识到你不必检查每个细胞。在checkScore方法的每个循环中,行/列循环仅限于获取垂直,水平和对角线所需的单元格。