Sorting through 2D array for Tic Tac Toe winner - java

I have made this very obnoxious way of finding the winner in a tic tac toe game and I was just wondering if there is a simpler way of doing this.
This is the method I currently have, and as you can see it is very redundant and repetitive. Any tips to narrow this down would be amazing. I'm thinking maybe a nested for-loop might work but not entirely sure how to set that up within this.
public static boolean isGameOver(char[][] gameBoard) {
//Testing for Horizontal Win
if(gameBoard[0][0] == 'X' && gameBoard[0][2] == 'X' && gameBoard [0][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[0][0] == 'O' && gameBoard[0][2] == 'O' && gameBoard [0][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
if(gameBoard[2][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [2][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[2][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [2][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
if(gameBoard[4][0] == 'X' && gameBoard[4][2] == 'X' && gameBoard [4][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[4][0] == 'O' && gameBoard[4][2] == 'O' && gameBoard [4][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
//Testing for Vertical Win
if(gameBoard[0][0] == 'X' && gameBoard[2][0] == 'X' && gameBoard [4][0] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[0][0] == 'O' && gameBoard[2][0] == 'O' && gameBoard [4][0] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
if(gameBoard[0][2] == 'X' && gameBoard[2][2] == 'X' && gameBoard [4][2] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[0][2] == 'O' && gameBoard[2][2] == 'O' && gameBoard [4][2] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
if(gameBoard[0][4] == 'X' && gameBoard[2][4] == 'X' && gameBoard [4][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[0][4] == 'O' && gameBoard[2][4] == 'O' && gameBoard [4][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
//Testing for Diagonal Win
if(gameBoard[0][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [4][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[0][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [4][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
if(gameBoard[4][0] == 'X' && gameBoard[2][2] == 'X' && gameBoard [0][4] == 'X') {
System.out.println("Player Wins!\n");
playerScore++;
return true;
}
if(gameBoard[4][0] == 'O' && gameBoard[2][2] == 'O' && gameBoard [0][4] == 'O') {
System.out.println("CPU Wins!\n");
cpuScore++;
return true;
}
//Testing for Tie
if(gameBoard[0][0] != ' ' && gameBoard[0][2] != ' ' && gameBoard[0][4] != ' ' &&
gameBoard[2][0] != ' ' && gameBoard[2][2] != ' ' && gameBoard[2][4] != ' ' &&
gameBoard[4][0] != ' ' && gameBoard[4][2] != ' ' && gameBoard[4][4] != ' ') {
System.out.println("It's a tie!!!\n");
numOfTies++;
return true;
}
return false;
}

Ok, I got a little carried away. But perhaps you could use some ideas presented here. My main goal was to make it so the entire board need not be checked after each move. This is the type of issue that is best considered during the design phase of a program.
I created a TriGroup class (which is essentially a mutable string to hold successive moves.
Then a map is used to hold all the groupings which have a common coordinate.
when a move is made, those groupings have the current player appended.
and check is done to see if that player won.
this program will run by itself using random moves resulting in a victory or a tie.
Some border cases may have been overlooked.
public class TicTacToeCheck {
int moveCount = 0;
static int MAX_MOVES = 27;
class TriGroup {
public String group = "";
#Override
public String toString() {
return group;
}
}
TriGroup row1 = new TriGroup();
TriGroup row2 = new TriGroup();
TriGroup row3 = new TriGroup();
TriGroup col1 = new TriGroup();
TriGroup col2 = new TriGroup();
TriGroup col3 = new TriGroup();
TriGroup diag1 = new TriGroup();
TriGroup diag2 = new TriGroup();
Map<String, List<TriGroup>> commonGroupings = new HashMap<>();
{
commonGroupings.put("00", List.of(row1, col1, diag1));
commonGroupings.put("02", List.of(row1, col2));
commonGroupings.put("04", List.of(row1, col3));
commonGroupings.put("20", List.of(row2, col1));
commonGroupings.put("22", List.of(row2, col2, diag1, diag2));
commonGroupings.put("24", List.of(row2, col3));
commonGroupings.put("40", List.of(row3, col1, diag1));
commonGroupings.put("42", List.of(row3, col2));
commonGroupings.put("44", List.of(row3, col3));
}
public static void main(String[] args) {
new TicTacToeCheck().start();
}
public void start() {
char player = 'X';
Random r = new Random();
outer: while (moveCount < MAX_MOVES) {
commonGroupings.entrySet().forEach(System.out::println);
System.out.println();
int row = r.nextInt(3) * 2;
int col = r.nextInt(3) * 2;
System.out.println("Move: " + row + ", " + col);
player = player == 'X' ? 'O' : 'X';
char val;
switch (val = recordMove(row, col, player)) {
case 'X' -> {
System.out.println("X wins!");
break outer;
}
case 'O' -> {
System.out.println("O wins!");
break outer;
}
case 0 -> {
System.out.println("Tie!");
break outer;
}
default -> {
}
}
}
commonGroupings.entrySet().forEach(System.out::println);
}
public char recordMove(int row, int col, char c) {
moveCount++;
for (TriGroup tri : commonGroupings.get(row + "" + col)) {
if (tri.group.length() > 2) {
// just ignore the row/col and try the next
continue;
}
// update group
tri.group += c;
if (tri.group.equals(c + "" + c + "" + c)) {
return c;
}
}
if (moveCount == MAX_MOVES) {
return 0;
}
return '#';
}
}

This version uses 2 auxiliary, private methods to make the code less repetitive, without changing the behavior of calling isGameOver. The main observation is that there is very little difference between checking for a win by O or checking for one by X - only a single character. So that becomes checkWins. The next observation is that there is a lot of repetition involved in checking 3 positions of the board that are next to each other. If you give me the char to expect, where to start, and where to look next (dcol and drow), that becomes allEqual.
Your code skips over uneven positions of the board; my code does not. I feel that it is an error to mix presentation ("how you show things to users") with model ("how you represent things internally"); so my code is not currently a drop-in replacement for yours, but can quickly be fixed to be such a replacement by tweaking values in checkWins (diagonal down would be 0, 0, 2, 2, and so on).
Note that, efficiency-wise, your code is probably faster. But I find this version to be much shorter, more readable, and therefore easier to debug & maintain.
private static boolean allEqual(char expected, char[][] b,
int row, int col, int drow, int dcol) {
for (int i=0; i<b[0].length; i++) {
if (b[row][col] != expected) return false;
row += drow;
col += dcol;
}
return true;
}
private static boolean checkWins(char playerChar, char[][]b) {
boolean win = allEqual(playerChar, b, 0, 0, 0, 1) // 1st row
|| allEqual(playerChar, b, 1, 0, 0, 1)
|| allEqual(playerChar, b, 2, 0, 0, 1) // 3rd row
|| allEqual(playerChar, b, 0, 0, 1, 0) // 1st col
|| allEqual(playerChar, b, 0, 1, 1, 0)
|| allEqual(playerChar, b, 0, 2, 1, 0) // 3rd col
|| allEqual(playerChar, b, 0, 0, 1, 1) // diagonal down
|| allEqual(playerChar, b, 2, 0, 1,-1); // diagonal up
return win;
}
public static boolean isGameOver(char[][] gameBoard) {
if (checkWins('X', gameBoard)) {
System.out.println("Player Wins!\n");
playerScore ++;
return true;
} else if (checkWins('O', gameBoard)) {
System.out.println("CPU Wins!\n");
cpuScore ++;
return true;
} else {
return false;
}
}

Take a look at this:
https://www.geeksforgeeks.org/tic-tac-toe-game-in-java/
Add the strings of gameBoard[x][y] and check them in a switch statement.
If the compound strings are equals to XXX or OOO, you can return the winner.
For your code something like this:
for (int a = 0; a < 8; a++) {
String line = null;
switch (a) {
case 0:
line = gameBoard[0][0] + gameBoard[0][1] + gameBoard[0][2];
break;
case 1:
line = gameBoard[1][0] + gameBoard[1][1] + gameBoard[1][2];
break;
case 2:
line = gameBoard[2][0] + gameBoard[2][1] + gameBoard[2][2];
break;
case 3:
line = gameBoard[0][0] + gameBoard[1][0] + gameBoard[2][0];
break;
case 4:
line = gameBoard[0][1] + gameBoard[1][1] + gameBoard[2][1];
break;
case 5:
line = gameBoard[0][2] + gameBoard[1][2] + gameBoard[2][2];
break;
case 6:
line = gameBoard[0][0] + gameBoard[1][1] + gameBoard[2][2];
break;
case 7:
line = gameBoard[0][2] + gameBoard[1][1] + gameBoard[2][0];
break;
}
//For X winner
if (line.equals("XXX")) {
return "X";
}
// For O winner
else if (line.equals("OOO")) {
return "O";
}
}

Related

TicTacToe using 2D array in java

Hello Everyone I need help.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[][] board = {
{'?','?','?'},
{'?','?','?'},
{'?','?','?'}
};
System.out.print("Type any key to play the game and type 'n' to stop the game: ");
String Stop = sc.nextLine();
while(true){
if(Stop.equals("n"))break;
System.out.print("Player" + "[" + "X" + "]: ");
int PlayerX = sc.nextInt();
if(PlayerX == 1){
board[2][0] = 'x';
}
if(PlayerX == 2){
board[2][1] = 'x';
}
if(PlayerX == 3){
board[2][2] = 'x';
}
if(PlayerX == 4){
board[1][0] = 'x';
}
if(PlayerX == 5){
board[1][1] = 'x';
}
if(PlayerX == 6){
board[1][2] = 'x';
}
if(PlayerX == 7){
board[0][0] = 'x';
}
if(PlayerX == 8){
board[0][1] = 'x';
}
if(PlayerX == 9){
board[0][2] = 'x';
}
for(char[] x1 : board){
for(char x2 : x1){
System.out.print(x2 + "\t");
}
System.out.println();
}
System.out.print("Player" + "[" + "O" + "]: ");
int PlayerO = sc.nextInt();
if(PlayerO == 1){
board[2][0] = 'o';
}
if(PlayerO == 2){
board[2][1] = 'o';
}
if(PlayerO == 3){
board[2][2] = 'o';
}
if(PlayerO == 4){
board[1][0] = 'o';
}
if(PlayerO == 5){
board[1][1] = 'o';
}
if(PlayerO == 6){
board[1][2] = 'o';
}
if(PlayerO == 7){
board[0][0] = 'o';
}
if(PlayerO == 8){
board[0][1] = 'o';
}
if(PlayerO == 9){
board[0][2] = 'o';
}
for(char[] x1 : board){
for(char x2 : x1){
System.out.print(x2 + "\t");
}
System.out.println();
}
}
}
}
I am trying to make a simple tictactoes program in java. I am already done in placing the X and O, but I am struggling on checking of wether there is a winner or not.
I am confused on what code I will type o check the winner of the program.
You simply just need to write some code to check if there are 3 matches in each row column and diagonal.
You can utilise for loops to do this more efficiently
public static char checkWinner(char[][] board) {
// Check rows
for (int i = 0; i < 3; i++) {
if (board[i][0] != '?' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
return board[i][0];
}
}
// Check columns
for (int j = 0; j < 3; j++) {
if (board[0][j] != '?' && board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
return board[0][j];
}
}
// Check diagonal
if (board[0][0] != '?' && board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
return board[0][0];
}
// Check anti-diagonal
if (board[0][2] != '?' && board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
return board[0][2];
}
// No winner
return '?';
}
If you havent come accross for loops yet, there are plenty of good tutorials out there such as https://www.w3schools.com/java/java_for_loop.asp
(Note, you can also use loops to clean up some of your pre-existing code)

How can I keep it running after checking the if condition?

This is a program tic tac toe. It's a computer operation. I want it to check all conditions. If it meets the condition, it will check again if the position of the computer to work. Can add O or not if it can't add O. had the computer check the next condition completely, if it didn't meet the condition it would randomly add O, but now it doesn't work because it happens that sometimes the computer randomly added it in the first place. and then when the players Played the condition that the computer had to prevent the player from winning, but it had a random O In the previous round, it was unable to fill the O at all, thus preventing it from continuing.
private static void computerNormalTurn(char[][] board) {
Random rand = new Random();
int computerMove;
while (true) {
if(board [2][0] == 'X' && board [2][1] == 'X' ||
board [1][1] == 'X' && board [0][0] == 'X' ||
board [1][2] == 'X' && board [0][2] == 'X'){
if(board[2][2] != ' ') {
continue;
}else{
computerMove = 3;
}
} else if (board [2][0] == 'X' && board [2][2] == 'X' ||
board [1][1] == 'X' && board [0][1] == 'X') {
if(board[2][1] != ' ') {
continue;
}else{
computerMove = 2;
}
} else if (board [2][1] == 'X' && board [2][2] == 'X' ||
board [1][0] == 'X' && board [0][0] == 'X' ||
board [1][1] == 'X' && board [0][2] == 'X' ) {
if(board[2][0] != ' ') {
continue;
}else{
computerMove = 1;
}
} else if (board[2][0] == 'X' && board[0][0] == 'X' ||
board [1][1] == 'X' && board [1][2] == 'X' ) {
if(board[1][0] != ' ') {
continue;
}else{
computerMove = 4;
}
} else if (board [2][0] == 'X' && board [0][2] == 'X' ||
board [2][1] == 'X' && board [0][1] == 'X' ||
board [2][2] == 'X' && board [0][0] == 'X' ||
board [1][0] == 'X' && board [1][2] == 'X' ) {
if(board[1][1] != ' ') {
continue;
}else{
computerMove = 5;
}
} else if (board[2][2] == 'X' && board[0][2] == 'X' ||
board [1][0] == 'X' && board [1][1] == 'X') {
if(board[1][2] != ' ') {
continue;
}else{
computerMove = 6;
}
} else if (board[2][0] == 'X' && board[1][0] == 'X' ||
board [2][2] == 'X' && board [1][1] == 'X' ||
board [0][1] == 'X' && board [0][2] == 'X') {
if(board[0][0] != ' ') {
continue;
}else{
computerMove = 7;
}
} else if (board [2][1] == 'X' && board [1][1] == 'X' ||
board [0][0] == 'X' && board [0][2] == 'X' ) {
if(board[0][1] != ' ') {
continue;
}else{
computerMove = 8;
}
} else if (board[2][0] == 'X' && board[1][1] == 'X' ||
board [2][2] == 'X' && board [1][2] == 'X' ||
board [0][0] == 'X' && board [0][1] == 'X' ) {
if(board[0][2] != ' ') {
continue;
}else{
computerMove = 9;
}
}else {
computerMove = rand.nextInt(9) + 1;
}
if (isValidMove(board, Integer.toString(computerMove))) {
break;
}
}
placeMove(board, Integer.toString(computerMove), 'O');
System.out.println("Computer chose " + computerMove);
}
I think the problem is that if your board is empty the computer will still have a move because of the else condition else { computerMove = rand.nextInt(9)+1; }
Then the following if statement will give a valid move and you will break the while loop and place the move on the board.
So if you want to prevent the computer from playing first, you should make a function that checks if the board is empty and if it is then do nothing.
public boolean isEmpty(){
for(int i = 0; i<3; i++)
for(int j = 0; j<3; j++)
if(board[i][j] != ' ') return false;
return true
}
If needed you can pass the board as a parameter in the function.
Hope I helped. Good luck!
There's a problem with the continues. The continue causes the next iteration. Because nothing changed, the game stays in the same state, the same condition will be met and the loop will continue endless.
Rewrite your conditions, so instead of e.g.
if(board [2][0] == 'X' && board [2][1] == 'X' ||
board [1][1] == 'X' && board [0][0] == 'X' ||
board [1][2] == 'X' && board [0][2] == 'X'){
if(board[2][2] != ' ') {
continue;
}else{
computerMove = 3;
}
} else ...
write
if((board [2][0] == 'X' && board [2][1] == 'X' ||
board [1][1] == 'X' && board [0][0] == 'X' ||
board [1][2] == 'X' && board [0][2] == 'X') &&
board [2][2] == ' '){
computerMove = 3;
} else ...

Nested loop infinitely looping after random interval?

I am programming a connect 4 game using Java for an assignment. However, whenever player 2 makes a move about 5 moves in, the player 2 loop will infinitely loop. There is some sort of logic error that I cannot find, and it is frustrating. What is the logic error, and what is a good way to avoid future mistakes of the same vain?
I have tried changing the variables for the do > while loop where player 1 and player two attempt their moves. However that has no affect on it.
import java.util.Arrays;
public class Lab6Shell {
public static void main(String args[]) {
// variables
Scanner input = new Scanner(System.in);
char[][] board = new char[7][8];
boolean finished = false;
boolean gameOver = false;
int width = 7;
int height = 8;
char currentPlayer = 'X';
int numMoves = 0;
int bottom_row = width - 1;
// loop until user wants to stop
for (int row = 0; row < board.length; row++) {
java.util.Arrays.fill(board[row], 0, board[row].length, '*');
}
do {
// display the board
DisplayBoard(board);
// loop until this game is over
do {
// get the next move for the current player
int columnChosen = 0;
do {
if (currentPlayer == 'X') {
int counter = 1;
System.out.println("Player 1 turn");
System.out.println("Enter the column you want to place your piece.");
columnChosen = input.nextInt();
input.nextLine();
while (true) {
if (columnChosen > width) {
System.out.println("That's not a valid column");
break;
}
if ((board[bottom_row][columnChosen] == '*')) {
board[bottom_row][columnChosen] = 'X';
break;
} else if ((board[bottom_row][columnChosen] == 'X')
|| (board[bottom_row][columnChosen] == 'O')) {
if (board[bottom_row - counter][columnChosen] == '*') { // puts X if blank
board[bottom_row - counter][columnChosen] = 'X';
break;
}
counter += 1;
if (counter == width) {
System.out.println("That column is full");
break;
}
}
}
}
if (currentPlayer == 'O') {
int counter = 1;
System.out.println("Player 2's turn");
System.out.println("Enter the column you want to place your piece.");
columnChosen = input.nextInt();
input.nextLine();
while (true) {
if (columnChosen > width) {
System.out.println("That's not a valid column");
break;
}
if ((board[bottom_row][columnChosen] == '*')) {
board[bottom_row][columnChosen] = 'O';
break;
} else if ((board[bottom_row][columnChosen] == 'X')
|| (board[bottom_row][columnChosen] == 'O')) {
if (board[bottom_row - counter][columnChosen] == '*') { // puts O
board[bottom_row - counter][columnChosen] = 'O';
break;
}
counter += 1;
if (counter == width) {
System.out.println("That column is full");
break;
}
}
}
}
} while (columnChosen < 0 || columnChosen > 8 || board[1][columnChosen] != '*');
// place piece
// increment number of moves
numMoves++;
// display the board
DisplayBoard(board);
// check for win
if (checkWin(board)) {
// if winner, display congratulations and set gameOver true
System.out.println("Congratulations! You won!");
gameOver = true;
} else if (numMoves == 42) {
// if tie, display result and set gameOver true
DisplayBoard(board);
System.out.println("Tie Game! Game over");
gameOver = true;
} else if (checkWin(board) == false) {
if (currentPlayer == ('X')) {
currentPlayer = ('O');
} else {
currentPlayer = ('X');
}
}
} while (!gameOver);
// ask if user wants to play again, set finished accordingly
System.out.println("Would you like to play again?");
input.nextLine();
String decision = input.nextLine();
if (decision.toLowerCase().equals("yes")) {
finished = false;
}
else if (decision.toLowerCase().equals("no")) {
finished = true;
}
} while (finished == false);
}
// this method displays the board passed in
public static void DisplayBoard(char[][] board) {
for (int i = 0; i < board.length; i++) {
System.out.print("|");
for (int j = 0; j < board[i].length; j++) {
System.out.print(" " + board[i][j] + "|");
}
System.out.println("");
}
}
public static boolean checkWin(char[][] board) {
final int HEIGHT = board.length;
final int WIDTH = board[0].length;
final int EMPTY_SLOT = '*';
for (int r = 0; r < HEIGHT; r++) { // iterate rows, bottom to top
for (int c = 0; c < WIDTH; c++) { // iterate columns, left to right
char player = board[r][c];
if (player == EMPTY_SLOT)
continue; // don't check empty slots
if (c + 3 < WIDTH && player == board[r][c + 1] && // look right
player == board[r][c + 2] && player == board[r][c + 3])
return true;
if (r + 3 < HEIGHT) {
if (player == board[r + 1][c] && // look up
player == board[r + 2][c] && player == board[r + 3][c])
return true;
if (c + 3 < WIDTH && player == board[r + 1][c + 1] && // look up & right
player == board[r + 2][c + 2] && player == board[r + 3][c + 3])
return true;
if (c - 3 >= 0 && player == board[r + 1][c - 1] && // look up & left
player == board[r + 2][c - 2] && player == board[r + 3][c - 3])
return true;
}
}
}
return false; // no winner found
}
}
The expected result is that each player will play a piece until four of the same piece are in a row. Then the first to reach four in a row is declared the winner, and the game ends. However, once the game gets in about 5 loops, the player 2 loop infinitely loops until a column is full, and does not print out the board.
Your infinite loop is caused by checking the condition board[1][columnChosen] != '*' in your do ... while loop. The program will continue to ask the current user for a new move as long as the second to top row of the selected column is occupied.
Replace:
do
{
...
} while (columnChosen < 0 || columnChosen > 8 || board[1][columnChosen] != '*');
With:
do
{
...
} while (columnChosen < 0 || columnChosen > 8)
This should get you to a point where you can tackle the remaining issues.

How to increase efficiency by using for loops?

I am a beginner java programmer and I am making a simple TicTacToe game using 2D arrays and these are my if statements to check if player 1, or player 2 has won. I believe that this can be simplified by using for loop(s) however I do not understand how to use that method.
if ((grid[0][0] == 1 && grid[0][1] == 1 && grid[0][2] == 1)
|| (grid[1][0] == 1 && grid[1][1] == 1 && grid[1][2] == 1)
|| (grid[2][0] == 1 && grid[2][1] == 1 && grid[2][2] == 1)
|| (grid[0][0] == 1 && grid[1][1] == 1 && grid[2][2] == 1)
|| (grid[0][2] == 1 && grid[1][1] == 1 && grid[2][0] == 1)
|| (grid[0][0] == 1 && grid[1][0] == 1 && grid[2][0] == 1)
|| (grid[0][1] == 1 && grid[1][1] == 1 && grid[2][1] == 1)
|| (grid[0][2] == 1 && grid[1][2] == 1 && grid[2][2] == 1)
&& won == false) {
title.setText("X wins!");
won = true;
} else if ((grid[0][0] == 2 && grid[0][1] == 2 && grid[0][2] == 2)
|| (grid[1][0] == 2 && grid[1][1] == 2 && grid[1][2] == 2)
|| (grid[2][0] == 2 && grid[2][1] == 2 && grid[2][2] == 2)
|| (grid[0][0] == 2 && grid[1][1] == 2 && grid[2][2] == 2)
|| (grid[0][2] == 2 && grid[1][1] == 2 && grid[2][0] == 2)
|| (grid[0][0] == 2 && grid[1][0] == 2 && grid[2][0] == 2)
|| (grid[0][1] == 2 && grid[1][1] == 2 && grid[2][1] == 2)
|| (grid[0][2] == 2 && grid[1][2] == 2 && grid[2][2] == 2)
&& won == false) {
title.setText("O wins!");
won = true;
}
Below is the modified code that uses far less if statments and conditions.
public static boolean hasWon(int[][] grid) {
for (int a = 1; a <= 2; a++) {
for (int b = 0; b < grid.length; b++) {
// Checking for win in horizontal, then vertical, then diagonal
if (grid[b][0] == a && grid[b][1] == a && grid[b][2] == a) {
won = true;
} else if (grid[0][b] == a && grid[1][b] == a && grid[2][b] == a) {
won = true;
} else if ((grid[0][0] == a && grid[1][1] == a && grid[2][2] == a
|| (grid[0][2] == a && grid[1][1] == a && grid[2][0] == a))) {
won = true;
}
}
}
}
In order to help you reach a solution on your own I'll give you some hints for now.
Hint #1: Think about what it means to win. A player must get 3 of their tokens in a row - horizontal, vertical, or diagonal. Think about how that can be represented in your program.
Hint #2: Think about how you can break the problem into smaller more manageable pieces. Think about what each winning scenario has in common and separate that logic into a method that you can call multiple times.
Hint #3: Consider what makes each winning scenario unique and how you might use your grid to produce a representation of the spaces you want to examine that is easier to check for a win.
If you're not sure about how for loops work or other aspects of the Java Language you can find tutorials on Oracle's site
Yes you are right. For loops are the way to go. Here is one way you could implement it.
public class tictactoe {
public static void main(String[] args) {
int[][] grid = {{1, 2, 1},
{1, 2, 1},
{2, 0, 1}};
boolean won = hasWon(grid);
}
public static boolean hasWon(int[][] grid){
for (int player = 1; player <= 2; player++){
boolean playerWon = false;
for(int i = 0; i < 3; i++){
//Horizonal win
playerWon = (grid[i][0] == player && grid[i][1] == player && grid[i][2] == player) || playerWon;
//Vertical Win
playerWon = (grid[0][i] == player && grid[1][i] == player && grid[i][2] == player) || playerWon;
}
//Diagonal Win
playerWon = (grid[0][0] == player && grid[1][1] == player && grid[2][2] == player) || playerWon;
playerWon = (grid[0][2] == player && grid[1][1] == player && grid[2][0] == player) || playerWon;
if(playerWon){
if(player == 1){
System.out.println("X wins!");
return true;
}
else{
System.out.println("O wins!");
return true;
}
}
}
//neither have won
return false;
}
}
Not a direct answer for the question. (as this is not "check all at once" style)
To simplify,
1. Check when a cell is clicked.
2. Condition depends on the place of a cell which is clicked and who clicked the cell.
3. If someone wins, end the game.
code sample
// Part of codes.(not tested.)
// Each cell has three states (0, 1, or 2)
int player = 1; // (Not written here but) switch this each turn (1 or 2)
// In some place (activity.onCreate() etc)
{
// For on click event(0, 0)
cell_0_0.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
grid[0][0] = player;
final boolean isEnd = checkEnd_0_0();
if (isEnd) {
// Call some function to end the game.
// Calling title.setText() in game end function maybe good.
// (as not needed to write many times.)
if (player == 1) {
title.setText("X wins!");
} else {
title.setText("O wins!");
}
} else {
switchPlayer(); // Not written in this code.
}
}
};
);
...
}
// Call this on cell(0, 0) click event
// Returns true if someone wins.
boolean checkEnd_0_0() {
// Omit checking grid[0][0] is 1 or 2 as it is clear.
// Check horizontal.
if (grid[0][1] == player) {
if (grid[0][2] == player) {
return true; // This is the case shown in question.
}
}
// Check other cases (vertical, diagonal)
...
// No match.
return false;
}

Tic Tac Toe in Java printing error

I've almost got this homework assignment finished, but I'm having some printing errors with the output.
The game is functional, but there's a problem with methods printOBoard and printXBoard where it messes up the game board when a move is made. The problem becomes worse the longer the game goes on. Thanks for your help.
import java.util.Scanner;
public class TicTacToe {
private enum Tiles {
X, O, EMPTY;
}
public static void main(String[] args) {
int i;
int j;
//initialize 2d array of enum types called "board"
Tiles[][] board = new Tiles[3][3];
for (i=0; i<board.length; i++)
for (j=0; j<board.length; j++)
board[i][j] = Tiles.EMPTY;
//print out an empty board as a 2d array, with each tile set as "EMPTY"
printBoard(board);
int row, col;
int countEmpty=0;
//initial countEmpty count, if it's less than 1, the board is full and the game is over.
for (i=0; i<board.length; i++)
for (j=0; j<board.length; j++)
if (board[i][j] == Tiles.EMPTY)
countEmpty++;
while (countEmpty > 0) {
//Player O enters the row coordinate
System.out.println("Player O's turn.");
System.out.println("Player O: Enter row (0, 1, or 2):");
Scanner stdin1 = new Scanner(System.in);
row = stdin1.nextInt();
//Player O enters the column coordinate
System.out.println("Player O: Enter column (0, 1, or 2):");
Scanner stdin2 = new Scanner(System.in);
col = stdin2.nextInt();
//If the tile is empty, it was a valid move, and an 'O' is placed on the spot.
if (board[row][col] == Tiles.EMPTY) {
board[row][col] = Tiles.O;
//MOVE FOR O ********************
printOBoard(board, row, col);
checkWin(board);
if (checkWin(board) == 2)
;
else
break;
}
//If the tile is not empty, it was not a valid move, and Player O is prompted to try again.
else {
System.out.println("Space already occupied. Please choose another.");
System.out.println("Player O's turn.");
//Player 0 enters the row coordinate
System.out.println("Player O: Enter row (0, 1, or 2):");
stdin1 = new Scanner(System.in);
row = stdin1.nextInt();
//Player O enters the column coordinate
System.out.println("Player O: Enter column (0, 1, or 2):");
stdin2 = new Scanner(System.in);
col = stdin2.nextInt();
//ERROR MOVE FOR O********************
board[row][col] = Tiles.O;
printOBoard(board, row, col);
checkWin(board);
if (checkWin(board) == 2)
;
else
break;
}
//Player X enters the row coordinate
System.out.println("Player X's turn.");
System.out.println("Player X: Enter row (0, 1, or 2):");
Scanner stdin3 = new Scanner(System.in);
row = stdin3.nextInt();
//Player X enters the column coordinate
System.out.println("Player X: Enter column (0, 1, or 2):");
Scanner stdin4 = new Scanner(System.in);
col = stdin4.nextInt();
if (board[row][col] == Tiles.EMPTY) {
board[row][col] = Tiles.X;
printXBoard(board, row, col);
//MOVE FOR X *************************************************
checkWin(board);
if (checkWin(board) == 2)
;
else
break;
}
else {
System.out.println("Space already occupied. Please choose another.");
System.out.println("Player O's turn.");
System.out.println("Player O: Enter row (0, 1, or 2):");
stdin3 = new Scanner(System.in);
row = stdin3.nextInt();
//Player O enters the column coordinate
System.out.println("Player O: Enter column (0, 1, or 2):");
stdin4 = new Scanner(System.in);
col = stdin4.nextInt();
board[row][col] = Tiles.O;
//ERROR MOVE FOR X ****************************************
printXBoard(board, row, col);
checkWin(board);
if (checkWin(board) == 2)
;
else
break;
}
//After both players move, we check to see if the board is full.
countEmpty = 0;
for (i=0; i<board.length; i++)
for (j=0; j<board.length; j++)
if (board[i][j] == Tiles.EMPTY)
countEmpty++;
}
}
//method printBoard prints out a grid of EMPTY's and returns nothing
private static void printBoard(Tiles board[][]) {
int i, j;
System.out.println(" -----------------------------");
System.out.println("| | | |");
for (i=0; i<board.length; i++){
for (j=0; j<board.length; j++){
System.out.printf("| " + board[i][j] + " ");
}
System.out.println("|");
System.out.println("| | | |");
System.out.println(" -----------------------------");
if (i<2)
System.out.println("| | | |");
}
return;
}
//method printXBoard prints out the grid modified with the addition of an X after Player X's turn
private static void printXBoard(Tiles board[][], int curRow, int curCol) {
int i, j;
System.out.println(" -----------------------------");
System.out.println("| | | |");
for (i=0; i<board.length; i++){
for (j=0; j<board.length; j++){
if (i == curRow && j == curCol)
board[i][j] = Tiles.X;
else
;
System.out.printf("| " + board[i][j] + " ");
}
System.out.println("|");
System.out.println("| | | |");
System.out.println(" -----------------------------");
if (i<2)
System.out.println("| | | |");
}
return;
}
//method printOBoard prints out the grid modified with the addition of an X after Player X's turn
private static void printOBoard(Tiles board[][], int curRow, int curCol) {
int i, j;
System.out.println(" -----------------------------");
System.out.println("| | | |");
for (i=0; i<board.length; i++){
for (j=0; j<board.length; j++){
if (i == curRow && j == curCol)
board[i][j] = Tiles.O;
else
;
System.out.printf("| " + board[i][j] + " ");
}
System.out.println("|");
System.out.println("| | | |");
System.out.println(" -----------------------------");
if (i<2)
System.out.println("| | | |");
}
return;
}
//method checkWin checks all possible winning combinations for both players.
private static int checkWin(Tiles board[][]) {
if (board[0][0] == Tiles.X && board[0][1] == Tiles.X && board[0][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[0][0] == Tiles.X && board[1][1] == Tiles.X && board[2][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[0][0] == Tiles.X && board[1][0] == Tiles.X && board[2][0] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[1][0] == Tiles.X && board[1][1] == Tiles.X && board[1][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[2][0] == Tiles.X && board[2][1] == Tiles.X && board[2][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[0][1] == Tiles.X && board[1][1] == Tiles.X && board[2][1] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[0][2] == Tiles.X && board[1][2] == Tiles.X && board[2][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
else if (board[2][0] == Tiles.X && board[1][1] == Tiles.X && board[0][2] == Tiles.X){
System.out.println("Player X wins!");
return 1;
}
//check if player O wins
else if (board[0][0] == Tiles.O && board[0][1] == Tiles.O && board[0][2] == Tiles.O){
System.out.println("Player O wins!");
return 0;
}
else if (board[0][0] == Tiles.O && board[1][1] == Tiles.O && board[2][2] == Tiles.O){
System.out.println("Player O wins!");
return 0;
}
else if (board[0][0] == Tiles.O && board[1][0] == Tiles.O && board[2][0] == Tiles.O){
System.out.println("Player O wins!");
return 0;
}
else if (board[1][0] == Tiles.O && board[1][1] == Tiles.O && board[1][2] == Tiles.O){
System.out.println("Player O wins!");
return 0;
}
else if (board[2][0] == Tiles.O && board[2][1] == Tiles.O && board[2][2] == Tiles.O) {
System.out.println("Player O wins!");
return 0;
}
else if (board[0][1] == Tiles.O && board[1][1] == Tiles.O && board[2][1] == Tiles.O) {
System.out.println("Player O wins!");
return 0;
}
else if (board[0][2] == Tiles.O && board[1][2] == Tiles.O && board[2][2] == Tiles.O){
System.out.println("Player O wins!");
return 0;
}
else if (board[2][0] == Tiles.O && board[1][1] == Tiles.O && board[0][2] == Tiles.O) {
System.out.println("Player O wins!");
return 0;
}
else
return 2;
}
}
There is a problem in 2nd attempt to place X (if space is occupied by O), you copy pasted code from O and haven't changed player & tile.
System.out.println("Player O's turn.");
board[row][col] = Tiles.O;
It was pain to read this code -_- but you'll get better eventually ;) .
The reason as to why this is happening when printing out the Letters onto your board(which I've run on my mac) is that when you're printing the letters, you're using println...since you're accompanying a certain amount of space per block you should be using printf...for example:
System.out.printf("%10s", LetterVariableForTurn);
This will give the LetterVariableForTurn 10 spaces of text to write within.
here is a link to help you more: printf
Hope this helps!

Categories