Java Tic Tac Toe console everyone!I have created a bit ugly looking Tic Tac Toe console game using Java. I'm learning how to code and I would love to hear some comments about my code. Because it's quite streatforward, I'm not using classes and objects ( my assignment was not to use any ). Thank you in advance!
package com.company;

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static Scanner scan = new Scanner(System.in);

    public static char[][] table = {
        {'1', '2', '3'},
        {'4', '5', '6'},
        {'7', '8', '9'}
    };

    public static ArrayList&lt;Character&gt; picksTillNow = new ArrayList&lt;Character&gt;();
    public static char playerOne = ' ';
    public static char playerTwo = ' ';

    public static void main(String[] args) {

    for(char i = '1'; i &lt;= '9'; i++){
        picksTillNow.add(i);
    }

    printTable();

    while (true){
        playerOneChoice();
        endGame();
        playerTwoChoice();
        endGame();
    }
}

/**
 * Prints the table with no players choices made ( 1 - 9 )
 */
public static void printTable() {

    for (int i = 0; i &lt; table.length; i++) {
        for (int j = 0; j &lt; table[i].length; j++) {
            System.out.print(table[i][j] + &quot; &quot;);
        }
        if (table[i][2] != 9) {
            System.out.println();
        }
    }
}


/**
 * Prints the table with the players choice included
 * @param player - player 1 or player 2
 * @param choice - char from 1 - 9
 */
public static void printTable(int player, char choice){

    for (int i = 0; i &lt; table.length ; i++) {
        for (int j = 0; j &lt; table[i].length; j++) {
            if(choice == table[i][j] &amp;&amp; player == 1){
                //X
                table[i][j] = 'X';
            }else if(choice == table[i][j] &amp;&amp; player == 2){
                //O
                table[i][j] = 'O';
            }
            System.out.print(table[i][j] + &quot; &quot;);
        }
        if(table[i][2] != 9){
            System.out.println();
        }
    }
}


/**
 * Asks for player one choice method and prints the table, checks if that position has been chosen
 */
public static void playerOneChoice(){
    System.out.print(&quot;Играч 1: &quot;);
    playerOne = scan.next().charAt(0);
    if(picksTillNow.contains(playerOne)){
        picksTillNow.remove(picksTillNow.indexOf(playerOne));
        printTable(1, playerOne);
    }else{
        playerOneChoice();
    }
}


/**
 * Asks for player one choice method and prints the table, checks if that position has been chosen
 */
public static void playerTwoChoice(){
    System.out.print(&quot;Играч 2: &quot;);
    playerTwo = scan.next().charAt(0);
    if(picksTillNow.contains(playerTwo)){
        picksTillNow.remove(picksTillNow.indexOf(playerTwo));
        printTable(2, playerTwo);
    }else{
        playerTwoChoice();
    }
}

/**
 * Checks for a winner. If yes - exits program
 */
public static void endGame(){
    for(int i = 0; i &lt; table.length; i++){
        if(table[i][0] == table[i][1] &amp;&amp; table[i][1] == table[i][2] &amp;&amp; table[0][i] != 'О'){
            System.out.println(&quot;Победа!&quot;);
            System.exit(0);
        }
    }

    for(int j = 0; j &lt; table.length; j++){
        if(table[0][j] == table[1][j] &amp;&amp; table[1][j] == table[2][j] &amp;&amp; table[j][0] != 'O'){
            System.out.println(&quot;Победа!&quot;);
            System.exit(0);
        }
    }

    if(table[0][0] == table[1][1] &amp;&amp; table[1][1] == table[2][2] &amp;&amp; table[0][0] != 'O'){
        System.out.println(&quot;Победа!&quot;);
        System.exit(0);
    }

    if(table[0][2] == table[1][1] &amp;&amp; table[1][1] == table[2][0] &amp;&amp; table[0][2] != 'O'){
        System.out.println(&quot;Победа!&quot;);
        System.exit(0);
    }

    if(picksTillNow.isEmpty()) System.exit(0);
 }
}
Adding to Bobby's very good answer, you could also explore alternative ways for checking the winning game.
You can think of noughts and crosses as 1s and 0s (true and false):
boolean[][] board = new boolean[][]{
     {false, false, false},
     {false, true, false},
     {false, false, true}
};

and therefore transform the board to an integer number:
int intboard = 0;
int exponent = 0;
for (int i = 0; i &lt; board.length; i++) {
    for (int j = 0; j &lt; board[0].length; j++) {
        intboard += board[i][j] ? Math.pow(2, exponent) : 0;
        exponent++;
    }
}

Then you can simply check intboard against a set of pre-calculated integers for all winning boards:
List&lt;Integer&gt; winningBoards = List.of(
        7, // Horizontal, row-0 --&gt; 000000111
        56, // Horizontal, row-1 --&gt; 7 &lt;&lt; 3
        448, // Horizontal, row-2 --&gt; 7 &lt;&lt; 6
        73, // Vertical, column-0 --&gt; 001001001
        146, // Vertical, column-1 --&gt; 73 &lt;&lt; 1
        292, // Vertical, column-2 --&gt; 73 &lt;&lt; 2
        273, // Diagonal-0 --&gt; 100010001
        84 // Diagonal-1 --&gt; (273 &gt;&gt; 2) | 16
);


Note that you can calculate some of these winning boards using bitwise operations too!

Finally checking for the winning cases is a matter of applying the winningBoards masks on intboard:
final int boardToCheck = intboard;
boolean youHaveWon = winningBoards.stream()
        .anyMatch(winningboard -&gt; (boardToCheck &amp; winningboard) == winningboard);

System.out.println(&quot;Nought has won: &quot; + youHaveWon);

If you want to check for crosses you simply need to flip the bits of the winning boards using the complement operator ~:
youHaveWon = winningBoards.stream()
        .anyMatch(winningboard -&gt; (~boardToCheck &amp; winningboard) == winningboard);

System.out.println(&quot;Cross has won: &quot; + youHaveWon);

The advantage of this technique is not clear for a game as simple as noughts and crosses, but if you are working on more complex games and need to check many many boards (even millions or billions!) when performing Minimax or equivalent, you can get a very nice speed up by changing the representation of your game from using objects to bits.