Search code examples
javatic-tac-toe

Is there any COMPACT way to check winner in a simple tic-tac-toe game?


I am coding a simple tic-tac-toe for a high-school mini project, but I need it to be within a strict data volume (not more than 112 lines). I thought checking for each row, column and cross would be long, so is there any alternative to do so (You should see a [[[HERE]]] comment)? (Btw, I already know it looks awful) Thanks in advance!

public class TTTGame {
    //OPTIONS v
    public static final String draw = "DRAW"; // <- Definitions for different states
    public static final String circles = "CIRCLES"; // BOT
    public static final String crosses = "CROSSES"; // PLAYER
    public static final String getCrosses = "X"; //<- Symbols to display
    public static final String getCircles = "O";
    //OPTIONS ^

    //DO NOT MODIFY UNDER THIS LINE (Just kidding, do whatever u want) v

    public static int[][] board = {
            {0,0,0},
            {0,0,0},
            {0,0,0},
    };
    public static final int empty = 0; // Definition of the values
    public static final int cross = 1;
    public static final int circle = 2;
    public static int turns = 0; //Just here to count turns, nothing special

    public static void main(String[]args) { //Main process
        board[1][1] = circle;
        display();
        while (true) {
            PlayerTurn();
            if (checkStop()||checkWinner()!=null) {display();GStop();break;}
            BotTurn();
            if (checkStop()||checkWinner()!=null) {display();GStop();break;}
            display();
            turns += 1;
        }
    }

    private static void GStop() { //Force stop the match function
        System.out.println("Winner : " + checkWinner());
        System.exit(1);
    }

    private static boolean checkStop() { //Check if match is already full / completed (Draw)
        for (int x = 0; x < 3; x++)
            for (int y = 0; y < 3; y++)
                if (board[x][y]==empty) return false;
        return true;
    }

    @Nullable
    private static String checkWinner() { //Check Winner


        //    [[[ HERE ]]]   ---------------



        return null;
    }
    private static void PlayerTurn() { //Player turn
        int x; Scanner c = new Scanner(System.in);
        while (true) {
                x = c.nextInt();
                x = x-1;
                if ((x>=0)&&(x < 9)) {
                    if (board[x / 3][x % 3] == empty) {
                        board[x / 3][x % 3] = cross;
                        break;
                    } else System.out.println("Already chosen");
            } else System.out.println("Invalid");
        }

    }

    private static void BotTurn() { //Bot turn -> (Modify these to change the AI behaviour, here's a very simple one);
        boolean choose = true;
        for (int y = 0; y < 3 ; y++)
            for (int x = 0; x < 3; x++)
                if (board[y][x] == empty&&choose) {
                        board[y][x] = circle;
                        choose = false;
                }
    }
    private static void display() { //Display the board
        int nn = 1;
        String a = "z";
        for (int y = 0; y < 3 ; y++) {
            for (int x = 0; x < 3; x++) {
                if (board[y][x] == 0) a = "*";
                if (board[y][x] == 1) a = getCrosses;
                if (board[y][x] == 2) a = getCircles;
                System.out.print(a + "  ");
            }
            System.out.print("      "); //Indications
            for (int xn = 0; xn < 3; xn++) {
                System.out.print(nn);
                nn+=1;
                System.out.print("  ");
            }
            System.out.println(" ");
        }
    }
}

Solution

  • How about this idea: (neither the only nor the best nor the most performant solution... just an idea)

    You can use the sum of each row, diagonal and column to determine if the either player one (all 1s) or player two (all 2s) wins. Therefore you only need to set the empty field to be higher than 6.

    For example let's say your board looks like this:

    7 1 1    -> 7+1+1 = 9 // no one wins
    2 2 2    -> 2+2+2 = 6 // player two wins, he has 3 * 2 in a row
    1 7 2    -> 1+7+2 =10 // no win here
    

    if all three numbers where 1s (sum == 3) your player one wins.

    It is "cumbersome" to implement, but as I said it is just an idea:

    // first we check every column
    for( int x=0; x<board[y].length; x++){
       int sum = 0;
       for( int y=0; y<board.length; y++){
          sum += board[y][x];
       }
       if(sum == 3 || sum == 6){
          return true;
       }
    }
    
    // then every row
    for( int y=0; y<board.length; y++){
       int sum = 0;
       for( int x=0; x<board[y].length; x++){
          sum += board[y][x];
       }
       if(sum == 3 || sum == 6){
          return true;
       }
    }
    // and finally the diagonals (if we ever reach that part)
    int sum= board[0][0] + board[1][1] + board[2][2];
    if(sum == 3 || sum == 6){
       return true;
    }
    sum= board[0][2] + board[1][1] + board[2][0];
    if(sum == 3 || sum == 6){
       return true;
    }
    

    you could also return 1 when the sum == 3 and the first player wins or 2 when player two wins.