java – Check Tic Tac Toe Winner

Question:

The algorithm professor asked us to write code to make a simple tic-tac-toe game in Java. And I already have everything ready, but I'm not very happy with the solution I came up with to validate who won the game.

I did a series of if and elseifs to check each condition a player can win the game. And okay, that covers what the professor asked, except I don't think that's the smartest way to write an algorithm. I was thinking about using nested repeats (for inside for) but I can't find a way where I can apply that in the algorithm, or maybe because of so much thinking I can't think straight anymore.

I also thought about creating an array with all possible possibilities:

   final int[][][] condicoesVencer = {
    //COLUNAS
    {{ 0, 0 }, { 1, 0 }, { 2, 0 }},
    {{ 0, 1 }, { 1, 1 }, { 2, 1 }},
    {{ 0, 2 }, { 1, 2 }, { 2, 2 }},

    //LINHAS
    {{ 0, 0 }, { 0, 1 }, { 0, 2 }},
    {{ 1, 0 }, { 1, 1 }, { 1, 2 }},
    {{ 2, 0 }, { 2, 1 }, { 2, 2 }},

    //DIAGONAIS
    {{ 0, 0 }, { 1, 1 }, { 2, 2 }},
    {{ 2, 0 }, { 1, 1 }, { 0, 2 }}
};

condicoesVencer keeps all possible winning combinations, the positions of the vector char tabuleiro[][] = new char[3][3] where the X or O can win. But I couldn't get a way to iterate through the two vectors in order to check on the board vector every condition in the condicoesVencer vector and now I don't know what to do.

How do I replace the bunch of ifs I made into something more 'smart'? Please, if you have an answer, send the code and explain.

EDIT: Here's the method I created, with all the ifs:

public boolean haGanhador(){
    //Checa X verticalmente
    if(tabuleiro[0][0] == 'X' && tabuleiro[1][0] == 'X' && tabuleiro [2][0] == 'X'){
        System.out.println("'X' VENCEU");
        return true;
    }
     else if(tabuleiro[0][1] == 'X' && tabuleiro[1][1] == 'X' && tabuleiro[2][1] == 'X'){
        System.out.println("'X' VENCEU");
        return true;
     }
     else if(tabuleiro[0][2] == 'X' && tabuleiro[1][2] == 'X' && tabuleiro[2][2] == 'X'){
        System.out.println("'X' VENCEU");
        return true;
    }



     //Checa X horizontalmente
     else if(tabuleiro[0][0] == 'X' && tabuleiro[0][1] == 'X' && tabuleiro[0][2] == 'X'){
    System.out.println("'X' VENCEU");
    return true;
    }
    else if(tabuleiro[1][0] == 'X' && tabuleiro[1][1] == 'X' && tabuleiro[1][2] == 'X'){
    System.out.println("'X' VENCEU");
    return true;
    } 
    else if(tabuleiro[2][0] == 'X' && tabuleiro[2][1] == 'X' && tabuleiro[2][2] == 'X'){
    System.out.println("'X' VENCEU");
    return true;
    }
    //Checa X diagonalmente
    else if(tabuleiro[0][0] == 'X' && tabuleiro[1][1] == 'X' && tabuleiro[2][2] == 'X'){
    System.out.println("'X' VENCEU");
    return true;
    }
    else if(tabuleiro[0][2] == 'X' && tabuleiro[1][1] == 'X' && tabuleiro[2][0] == 'X'){
    System.out.println("'X' VENCEU");
    return true;
    }
    //Checa O verticalmente
    if(tabuleiro[0][0] == 'O' && tabuleiro[1][0] == 'O' && tabuleiro [2][0] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }
    else if(tabuleiro[0][1] == 'O' && tabuleiro[1][1] == 'O' && tabuleiro[2][1] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }
    else if(tabuleiro[0][2] == 'O' && tabuleiro[1][2] == 'O' && tabuleiro[2][2] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }

    //Checa O horizontalmente
    if(tabuleiro[0][0] == 'O' && tabuleiro[0][1] == 'O' && tabuleiro[0][2] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }
    else if(tabuleiro[1][0] == 'O' && tabuleiro[1][1] == 'O' && tabuleiro[1][2] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }
    else if(tabuleiro[2][0] == 'O' && tabuleiro[2][1] == 'O' && tabuleiro[2][2] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }

    //Checa O diagonalmente
    if(tabuleiro[0][0] == 'O' && tabuleiro[1][1] == 'O' && tabuleiro[2][2] == 'O'){
    System.out.println("'O' VENCEU");
    return true;
    }
    else if(tabuleiro[0][2] == 'O' && tabuleiro[1][1] == 'O' && tabuleiro[2][0] == 'O'){
    System.out.println("'O' VENCEU");
    return true; 
    }

    return false;
}

Answer:

Since you prefer with few IF s, I made a solution using an IF and a FOR only.

Solution:

public class JogoVelha {

    public static String obtemVencedor(String[] tabuleiro) {

        if ((tabuleiro == null) || (tabuleiro.length != 9)) {
            throw new IllegalArgumentException
                ("Um tabuleiro deve ser um array de 9 posições.");
        }
        Integer[][] padroesVitoria = {
                    {0, 1, 2},
                    {0, 4, 8},
                    {0, 3, 6},
                    {1, 4, 7},
                    {2, 5, 8},
                    {2, 4, 6},
                    {3, 4, 5},
                    {6, 7, 8}};

        for (Integer[] padraoVitoria: padroesVitoria) {

            boolean haVencedor = tabuleiro[padraoVitoria[0]] != null 
                && tabuleiro[padraoVitoria[0]].equals(tabuleiro[padraoVitoria[1]]) 
                && tabuleiro[padraoVitoria[0]].equals(tabuleiro[padraoVitoria[2]]);

            if (haVencedor) {
                String vencedor = tabuleiro[padraoVitoria[0]];
                return vencedor;
            }
        }
        return null;
    }
}

Test:

@Test
public void jovadorXVence() {

    String[] tabuleiro = {
            "X", "O", null, 
            "O", "O", null,
            "X", "X", "X"} ;

    String vencedor = JogoVelha.obtemVencedor(tabuleiro);

    assertEquals("X", vencedor);
}

@Test
public void naoHaVencedor() {

    String[] tabuleiro = {
            "X", "O", null, 
            "O", "O", null, 
            "X", null, "X"} ;

    String vencedor = JogoVelha.obtemVencedor(tabuleiro);

    assertNull(vencedor);
}

My approach was as follows:

  • I noticed that the board has nine positions. Your preview would look like this:

     0 | 1 | 2 --------- 3 | 4 | 5 --------- 6 | 7 | 8
  • Then the filled or partially filled board can be represented by an array of 9 positions.

  • So I visualized an example of a finished game. It would be as follows:

     X | O | - --------- O | O | - --------- X | X | X
  • Viewing this completed game within my array, I identified the winning patterns (which positions within the array, when occupied by the same player, signal a win):

     0 1 2 0 4 8 0 3 6 1 4 7 2 5 8 2 4 6 3 4 5 6 7 8
  • And so I wrote an algorithm to process the array representing a board, looking inside it for the winning patterns.

After each turn, obtemVencedor can be invoked to identify if there is already a winner. If there is no winner, we can check if there are still available positions on the board (if there are non-null elements in the array) to see if the game ended in a draw.

Scroll to Top