This code is for one of my assignments (connect four). I need to make this code less than 25 lines and also make the 'if' statements shorter. Also, the board has 6 rows and 7 columns. My code is trying to figure out if a person has won.

I have tried to merge all the loops into one loop, but that does not give me a correct answer.

public static boolean determineWin(String[][] board) {
    boolean won = false;

    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 4; j++) {
            if (board[i][j] != ". ") {
                if (board[i][j].equals(board[i][j+1]) && board[i][j+1].equals(board[i][j+2]) && board[i][j+2].equals(board[i][j+3])) {
                    won = true;
                    break;
                }
            }
        }
    }

    for (int i = 5; i > 2; i--) {
        for (int j = 6; j > 2; j--) {
            if (board[i][j] != ". ") {
                if (board[i][j].equals(board[i-1][j-1]) && board[i-1][j-1].equals(board[i-2][j-2]) && board[i-2][j-2].equals(board[i-3][j-3])){
                    won = true;
                    break;
                }
            }
        }

        for (int j = 0; j < 4; j++) {
            if (board[i][j] != ". ") {
                if (board[i][j].equals(board[i-1][j+1]) && board[i-1][j+1].equals(board[i-2][j+2]) && board[i-2][j+2].equals(board[i-3][j+3])){
                    won = true;
                    break;
                }
            }
        }

        for (int j = 0; j < 7; j++) {
            if (board[i][j] != ". ") {
                if (board[i][j].equals(board[i-1][j]) && board[i-1][j].equals(board[i-2][j]) && board[i-2][j].equals(board[i-3][j])){
                    won = true;
                    break;
                }
            }
        }
    }

    return won;
}

The result should be the same as the code above, but I just need the code to be a bit smaller (25 lines) and the if statements to be shorter.

1 Answers

2
Ian Mc On Best Solutions

The code above is inefficient because it has 4 separate for loops (to track the 4 directions in which you can win: 1) Left to right, 2) Top to bottom, 3) Diagonal 4) Diagonal/other direction -AND- because the if statements must check 4 consecutive positions.

To optimize the solution you can recognize that you can maintain the state for how many consecutive same pieces have occurred at each position in the board, for each of the 4 possible directions you can win (4 unique states).

Consider as an example winning in the horizontal direction. As you move left to right along the same row, the state counter increments by 1 if the piece to the left is the same. If there is ever a '.', the counter resets to 0. If there is a different piece, the counter resets to 1. You are in a winning position if any of these 4 state counters gets to 4.

The code below is complete for the winning directions of horizontal (state variable 0), and vertical (state variable 1). It is left as an exercise to complete the two rows which represent each of the diagonal directions (state variables 2 and 3).

public static boolean determineWin(String[][] board) {

    int[][][] counters = new int[board[0].length+1][board.length+1][4];

    for (int y=0; y<board.length; y++) {
        for (int x=0; x<board[0].length; x++) {
            if (!board[y][x].equals(".")) {
                counters[y][x][0] = (x>0 && board[y][x].equals(board[y][x-1])) ? counters[y][x-1][0] + 1 : 1;
                counters[y][x][1] = (y>0 && board[y][x].equals(board[y-1][x])) ? counters[y-1][x][1] + 1 : 1;
                // Diagonal 1 TODO:  counters[y][x][2] = 
                // Diagonal 2 TODO:  counters[y][x][3] = 
                if (counters[y][x][0] == 4 || counters[y][x][1] == 4 || counters[y][x][2] == 4 || counters[y][x][3] == 4)
                    return true;
            }
        }
    }
    return false;
}