Search code examples
javascriptarrays2d-games

Return winning cell coordinates in JS Connect-Four


I'm working on a JS connect-four game. My 'board' is an array of arrays dimensions 7 * 6 (0 = empty, 1 = occupied by player A, -1 = occupied by player 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]];

This is my (long-winded) function for checking wins (has either player created an unbroken horizontal, vertical, or diagonal line length 4 in the board). How can I modify this so that It returns an array with the coordinates of the winning counters rather than simply an alert message? I appreciate the best solution may involve abandoning my original checkWin function in place of something more concise.

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"

I want checkWin(boardTwo) to return [[0,0],[0,1],[0,2],[0,3]];


Solution

  • Here's an straightforward solution:

    • winAlert should return a number if someone won, e.g. 1 for A and -1 for B
    • Each check function will check this result and if it's -1 or 1 then it'll interpolate the values it checked
    • if a check method returns something that's not undefined i.e. the array with the answer then other checks should not be made
    • finally state holds who won (-1, 1 or undefined) and the returning value of checkWin will be an array of arrays if someone won

    I also did an additional check on the checkDiagonal method to also check the other diagonal that exists in the matrix

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