TicTacToe -- Check winner?

I designed a TicTacToe console game, and I’m trying to figure out how to check if somebody has one. My current code for the game is below.

package tictactoe;

import java.util.Scanner;

public class TicTacToe {
	private String[][] board = new String[3][3];
        private String turn = "O";
	private int turns = 0;
 	
	public void gameLoop() {
		for (int y = 0; y < 3; y++) {
			board[y][0] = " ";
			board[y][1] = " ";
			board[y][2] = " ";
			for (int x = 0; x < 3; x++) {
				board[0][x] = " ";
				board[1][x] = " ";
				board[2][x] = " ";
			}
		}
		
		while (true) {
			try {
				Scanner scan = new Scanner(System.in);
				
				System.out.println("      |      |      ");
				System.out.println("   " + board[0][0] + "  |   " + board[0][1] + "  |   " + board[0][2] + "  ");
				System.out.println("______|______|______");
				System.out.println("      |      |      ");
				System.out.println("   " + board[1][0] + "  |   " + board[1][1] + "  |   " + board[1][2] + "  ");
				System.out.println("______|______|______");
				System.out.println("      |      |      ");
				System.out.println("   " + board[2][0] + "  |   " + board[2][1] + "  |   " + board[2][2] + "  ");
				System.out.println("      |      |      ");
				
				if (turns != 9) {
					if (scan.hasNextInt()) {
						int input = scan.nextInt();
						
						if (!board[input/3][input%3].equals(" ")) {
							System.out.println("Place already taken.");
						} else {
							board[input/3][input%3] = turn;
							turn();
						}
					}
				} else if (turns == 9) {
					System.out.println(checkWin());
					System.exit(0);
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}
	
	public String turn() {
		if (turn == "O") {
			setTurns(getTurns() + 1);
			return turn = "X";
		}
		
		setTurns(getTurns() + 1);
		return turn = "O";
	}

	public String checkWin() { 
	}
	
	public int getTurns() {
		return turns;
	}

	public void setTurns(int turns) {
		this.turns = turns;
	}
}

I’m not sure how to check for the win, all I know is that I will need to loop through the board array to check if there is 3 in a row horizontally, vertically or diagonally.

~Shazer2

On a sidenote: this is extremely dangerous:

if (turn == "O") {

as for example

"O" != "OO".substring(0,1)
"O" != ""+"O"
"O" != "o".toUpperCase()

because they are equal in contents but different objects.

to reliably check strings for equality, you must use

if(turn.equals("O"))

Ah, I’ll fix that up. Thanks Riven. Any idea on checking the winner?

~Shazer2

there are 3+3+2 ways to win: 3x horizontal, 3x vertical, 2x diagonal

so first you need to check whether all strings in the 3 horizontal/vertical lines are equal:
using: board[ y ][ x ]


lineH0 = board[0][0].equals(board[0][1]) && board[0][0].equals(board[0][2]);
lineH1 = board[1][0].equals(board[1][1]) && board[1][0].equals(board[1][2]);
lineH2 = board[2][0].equals(board[2][1]) && board[2][0].equals(board[2][2]);

lineV0 = board[0][0].equals(board[0][0]) && board[0][0].equals(board[2][0]);
lineV1 = board[0][1].equals(board[0][1]) && board[0][1].equals(board[2][1]);
lineV2 = board[0][2].equals(board[0][2]) && board[0][2].equals(board[2][2]);

you can see the repetition here… so let’s write a loop:


for(int i=0; i<3; i++) {
   boolean h = board[i][0].equals(board[i][1]) && board[i][0].equals(board[i][2]);
   boolean v = board[0][i].equals(board[1][i]) && board[0][i].equals(board[2][i]);
   // if H or V is true, we have a row/column with the same chars - that means either a winner, or they are all empty
}

etc etc etc

Adding a check for diagonal is simple, just like adding the check that it’s not an empty line.

As you can see, you mixed ‘visuals’ and ‘logic’ and it is going to be extremely annoying to code with all these strings.

Why don’t you make board an int[][] and make the empty cells 0, and the players: 1 & 2

Suddenly your code would become a lot more readable:


for(int i=0; i<3; i++) {
   boolean h = board[i][0]==board[i][1] && board[i][0]==board[i][2];
   boolean v = board[0][i]==board[1][i] && board[0][i]==board[2][i];
   // if H or V is true, we have a row/column with the same ints - that means either a winner, or they are all zero
}

when you visualize the board, you simply write:


private String getLabelForPlayer(int p) {
   if(p == 1) return "X";
   if(p == 2) return "O";
   throw new IllegalArgumentException("ehmpf");
}

private String getLabelForCell(int x, int y) {
   int cell = board[y][x];
   if(cell == 0) return " ";
   return getLabelForPlayer(cell);
}

private void drawBoardRow(int y) {
            System.out.println("   " + getLabelForCell(0,y) + "  |   " + getLabelForCell(1,y) + "  |   " + getLabelForCell(2,y) + "  ");
}

private void drawBoard() {
            System.out.println("      |      |      ");
            drawBoardRow(0);
            System.out.println("______|______|______");
            drawBoardRow(1);
            System.out.println("______|______|______");
            drawBoardRow(2);
            System.out.println("      |      |      ");
}

I know how my code works though, but I do need to optimize in future if I want to get anywhere. I’ll see if I can take that win check code in. Thanks.

Also, I understand that boolean check if iterating through each cell on the board, but how do we determine who has the pieces there? This is very confusing for me, sorry I might need some extra explanation if you’re willing to help.

~Shazer2

How about you make checkWin() return either 0 for tie, 1 for X and 2 for O?
Then inside the for loop:


for(int i = 0; i < 3; i++) {
    boolean h = ...
    boolean v = ...
    
    if(h)
        return board[i][0];
    if(v)
        return board[0][i];
}

//Check for diagonals here

return 0;

So I either need to make board an int, or return a string for 0 instead.

~Shazer2

If you still want to use Strings, make it return “0”.

Ah yes. Now, how do I tell who has 3 lined up? As of now it only really returns whether one or the other is lined up vertically or horizontally.

~Shazer2

if(checkWin().equals(“X”))
… x wins
else if(checkWin().equals(“O”))
… o wins
else
… tie

Alright, now what about diagonals? :frowning:

~Shazer2

You’re checking each separately.
They should be easy enough if you think about it :wink:

Repeat Riven’s way for diagonal. Write them in stupid way and see the pattern of… index number for example… then turn into loop. I never try to create board game though.

and I’m here not to stalk you ra4king. geez.

Yay, I got it to work.

Many thanks to ra4king and Riven.

~Shazer2

X is 1, O is 0, the board is a nine bit int. Write a bitmask for each win condition and test that the bitwise AND of the condition and the board XOR the mask is zero.

That’s if I wanted to be clever. Truth is, I’d just hardwire the logic with some ‘if’ statements.

Each cell has three possible states :cranky:

You can only use this approach by setting 1 = current player & 0 = anything else, and unleach your bitmasks on that.

If I were to do it, it would do it totally different, properly, with a Player class, etc.

Using OO with tic-tac-toe = overkill :stuck_out_tongue:

Unless you want to get the job done and get a good grade (if applicable).

Blegh, school assignments… :persecutioncomplex: