In class, our assignment is to create a two-dimensional array and create a tic-tac-toe game around it. I have everything done except displaying when the whole board is full and the game is a draw. I have tried a few things but I have not found the solution and I need some help... Here is my code:
import java.util.Scanner;
public class TicTacToe {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int row, column;
char player = 'X';
//create 2 dimensional array for tic tac toe board
char[][] board = new char[3][3];
char ch = '1';
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++) {
board[i][j] = ch++;
}
}
displayBoard(board);
while(!winner(board) == true){
//get input for row/column
System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
row = in.nextInt();
column = in.nextInt();
//occupied
while (board[row][column] == 'X' || board[row][column] == 'O') {
System.out.println("This spot is occupied. Please try again");
}
//place the X
board[row][column] = player;
displayBoard(board);
if (winner(board)){
System.out.println("Player " + player + " is the winner!");
}
//time to swap players after each go.
if (player == 'O') {
player = 'X';
}
else {
player = 'O';
}
if (winner(board) == false) {
System.out.println("The game is a draw. Please try again.");
}
}
private static void displayBoard(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (j == board[i].length - 1) System.out.print(board[i][j]);
else System.out.print( board[i][j] + " | ");
}
System.out.println();
}
}
//method to determine whether there is an x or an o in the spot
public static Boolean winner(char[][] board){
for (int i = 0; i< board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == 'O' || board[i][j] == 'X') {
return false;
}
}
}
return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
(board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
(board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
(board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
(board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
(board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
(board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
(board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}
}
I want output saying that the board is full when it's full but I get nothing. This is the last line of my output and as you can see, my current strategy is not working as it continues to ask for input. -->
Enter a row and column (0, 1, or 2); for player X:
2 0
X | O | X
O | O | X
X | X | O
Enter a row and column (0, 1, or 2); for player O:
First off:
while (board[row][column] == 'X' || board[row][column] == 'O') {
System.out.println("This spot is occupied. Please try again");
}
This will create a infinite loop because row and column shouldn't change you should ask for new input!
Also
public static Boolean winner(char[][] board){
for (int i = 0; i< board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == 'O' || board[i][j] == 'X') {
return false;
}
}
}
As soon you hit 'O' or 'X' you will exit the Method with a false (no winner)
What you probably want to check is if every spot is occupied
public static Boolean winner(char[][] board){
//Boolean which is true until there is a empty spot
boolean occupied = true;
//loop and check if there is empty space or if its a draw
for (int i = 0; i< board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
//Check if spot is not 'O' or not 'X' => empty
if (board[i][j] != 'O' || board[i][j] != 'X') {
occupied = false;
}
}
}
if(occupied)
return false;
//Check if someone won
return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
(board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
(board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
(board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
(board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
(board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
(board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
(board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}
This would now check if there is a winner or its a tie
Occupied == true == tie == return false
Winner == return true
But you have three states:
Win
Tie
NotFinished
With the changed Method you will NOT finish the game until you win.
Reason:
while(!winner(board) == true)
This makes the game run as long as there is NO winner
(winner() will be false because everything is occupied or there is no winner)
while(!false==true) => while(true)
You could write a method similar to winner but it only checks if the board has empty spots:
public static Boolean hasEmptySpot(char[][] board){
//loop and check if there is empty space
for (int i = 0; i< board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] != 'O' && board[i][j] != 'X') {
return true;
}
}
}
return false;
}
//New code
while(hasEmptySpot(board) || !winner(board)){
//Your code for the game here
....
}
this would end the game when there is no empty spot left
After you finished the game you can call winner(board) and it will return if you tied or won!
By creating hasEmptySpot() you could change your winner method to
public static Boolean winner(char[][] board){
return (board[0][0] == board [0][1] && board[0][0] == board [0][2]) ||
(board[0][0] == board [1][1] && board[0][0] == board [2][2]) ||
(board[0][0] == board [1][0] && board[0][0] == board [2][0]) ||
(board[2][0] == board [2][1] && board[2][0] == board [2][2]) ||
(board[2][0] == board [1][1] && board[0][0] == board [0][2]) ||
(board[0][2] == board [1][2] && board[0][2] == board [2][2]) ||
(board[0][1] == board [1][1] && board[0][1] == board [2][1]) ||
(board[1][0] == board [1][1] && board[1][0] == board [1][2]);
}
Why?
Because you finished the game and you know there are only two possible outcomes Win or Tie.
I hope this helped you a little bit.
EDIT
Had a logic error myself!
First mistake:
you still need to check if there is a winner while the game is running forgot that point!
while(hasEmptySpot(board) || !winner(board)){
}
Now this will quit the game loop when there is a winner or no empty spots is left
Second mistake:
In hasEmptySpot()
if (board[i][j] != 'O' && board[i][j] != 'X') {
return true;
not
if (board[i][j] != 'O' || board[i][j] != 'X') {
return true;
Fixed it in the upper examples.
I'm sorry for the inconvenience!
The most efficient way to do this is to keep a running count of how many spaces have been filled previously and increment that count each time a space is occupied. The board can be considered full when that count reaches 9.
If you're familiar with object-oriented programming, I think you'll find this easier to implement if you wrap your 2D array in a Board class.
Example:
public static class Board {
private char[][] spaces = new char[3][3];
private int numMoves = 0;
public void makeMove(int row, int col, char player) {
if (spaces[row][col] == 'X' || spaces[row][col] == 'O') {
System.out.println("This spot is occupied. Please try again");
} else {
spaces[row][col] = player;
numMoves++;
}
}
public boolean isFull() {
return numMoves == 9;
}
public boolean hasWinner() {
...
}
public void display() {
...
}
}
You could try to incorporate a new method such as the following:
public Boolean boardFull()
{
short count = 0;
for(short i = 0; i < 3; i++){
for(short j = 0; j < 3; j++){
if(board[i][j] == ‘O’ || board[i][j] == ’X’){
count++;
} else {
continue;
}
}
}
if(count == 9){
return true;
} else {
return false;
}
}
You could use an if statement to see if it returns true and then print something out if it does.
Solution
The code that's not working is your winner() method. It is always returning false if there is at least one cell occupied. You could proceed based on the last part of Nordiii's answer.
Extra problems
Cell-checking loop
Your code to check if a cell is occupied is going infinitely. You need to use an 'if' statement instead of a 'while' loop:
if(board[row][column] == 'X' || board[row][column] == 'O'){
System.out.println("This spot is occupied. Please try again");
continue;
}
Your old code got stuck always checking if 1 cell was occupied and it always returned true, which kept the loop alive and flooded your console. The continue statement will exit the current iteration of your other 'while' loop and start a new iteration, thus asking for new input.
Exceptions
Man, that's a lot of uncaught exceptions! If I mess up my input, pow! The whole thing fails. Just put a try block for your input-checking code:
try {
row = in.nextInt();
column = in.nextInt();
// Attempt to place player (an ArrayOutOfBoundsException could be thrown)
if(board[row][column] == 'X' || board[row][column] == 'O'){
System.out.println("This spot is occupied. Please try again");
continue;
}
board[row][column] = player;
} catch(Exception e){
System.out.println("I'm sorry, I didn't get that.");
continue;
}
This attempts to execute the code inside the try statement, and if someone inputs something incorrect, the exception gets 'caught' and a new iteration is created. Genius!
Although there are already some great answers I'd like to post another solution that is more generic in its logic to determine the winner. Currently you've hard-coded your some of the possible winning scenarios when you could write more generic logic for this.
As other answers have pointed out you want a method to check for unoccupied spaces in the board and this will tell you if there is a tie. I have implemented such a method in the code below along with the more generic winner logic.
Note that some methods are public to make it easier to test, they do not necessarily have to remain public.
import java.util.Scanner;
public class TicTacToe {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int row, column;
char player = 'X';
//create 2 dimensional array for tic tac toe board
char[][] board = new char[3][3];
char ch = '1';
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++) {
board[i][j] = ch++;
}
}
displayBoard(board);
while(!winner(board) == true){
//get input for row/column
System.out.println("Enter a row and column (0, 1, or 2); for player " + player + ":");
row = in.nextInt();
column = in.nextInt();
//occupied
while (board[row][column] == 'X' || board[row][column] == 'O') {
System.out.println("This spot is occupied. Please try again");
}
//place the X
board[row][column] = player;
displayBoard(board);
if (winner(board)){
System.out.println("Player " + player + " is the winner!");
}
//time to swap players after each go.
if (player == 'O') {
player = 'X';
}
else {
player = 'O';
}
if (winner(board) == false && !hasFreeSpace(board)) {
System.out.println("The game is a draw. Please try again.");
}
}
//Don't forget to close the scanner.
in.close();
}
public static void displayBoard(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (j == board[i].length - 1) System.out.print(board[i][j]);
else System.out.print( board[i][j] + " | ");
}
System.out.println();
}
}
/**
* Determines whether the board is completely occupied by X and O characters
* #param board the board to search through
* #return true if entire board is populated by X or O, false otherwise.
*/
public static boolean hasFreeSpace(char[][] board){
for (int i = 0; i< board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] != 'O' && board[i][j] != 'X') {
return true;
}
}
}
return false;
}
//method to determine whether there is a winner
public static boolean winner(char[][] board){
return isHorizontalWin(board) || isVerticalWin(board) || isDiagonalWin(board);
}
/**
* Determines if there is a winner by checking each row for consecutive
* matching tokens.
* #return true if there is a winner horizontally, false otherwise.
*/
private static boolean isHorizontalWin(char[][] board) {
for(int row = 0; row < board.length; row++){
if(isWin(board[row]))
return true;
}
return false;
}
/**
* Determines whether all of the buttons in the specified array have the
* same text and that the text is not empty string.
* #param lineToProcess an array of buttons representing a line in the grid
* #return true if all buttons in the array have the same non-empty text, false otherwise.
*/
private static boolean isWin(char[] lineToProcess) {
boolean foundWin = true;
char prevChar = '-';
for(char character: lineToProcess) {
if(prevChar == '-')
prevChar = character;
if ('O' != character && 'X' != character) {
foundWin = false;
break;
} else if (prevChar != character) {
foundWin = false;
break;
}
}
return foundWin;
}
/**
* Determines whether there is a winner by checking column for consecutive
* matching tokens.
* #return true if there is a vertical winner, false otherwise.
*/
private static boolean isVerticalWin(char[][] board) {
char[] column = null;
//assuming all rows have same legnth (same number of cols in each row), use first row
for(int col = 0; col < board[0].length; col++){
column = new char[board[0].length];
for(int row = 0; row < column.length; row++){
column[row] = board[row][col];
}
if(isWin(column))
return true;
}
return false;
}
/**
* Determines if there is a winner by checking each diagonal for consecutive
* matching tokens.
* #return true if a diagonal winner exists, false otherwise.
*/
private static boolean isDiagonalWin(char[][] board) {
int row = 0, col = 0;
int cols = board.length;
int rows = board[0].length; //assuming all rows are equal length so just use the first one
//Create a one-dimensional array to represent the diagonal. Use the lesser
// of the rows or columns to set its size. If the grid is rectangular then
// a diagonal will always be the size of the lesser of its two dimensions.
int size = rows < cols ? rows : cols;
char[] diagonal = new char[size];
//Since we know the grid is a square we really could just check one of
// these - either row or col, but I left both in here anyway.
while (row < rows && col < cols) {
diagonal[col] = board[row][col];
row++;
col++;
}
if (isWin(diagonal)) {
return true;
}
row = rows - 1;
col = 0;
diagonal = new char[size];
while (row >=0 && col < cols) {
diagonal[col] = board[row][col];
row--;
col++;
}
return isWin(diagonal);
}
}
Related
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.
This question already has answers here:
How do you stop a loop from running in Java
(3 answers)
Closed 4 years ago.
I'm working on a simple tic-tac-toe 4x4 game. I have input() function where user enters his data, printBoard() which prints the board itself, analyzeBoard() where are all the calculations for choosing the winner and done() which simply returns status. My problem is that even when I find the winner I can't stop input() working and it keeps printing board over and over. For the first time, I thought that problem is in analyzeBoard() but then I figured out that it actually returns everything I need and the problem is in input(). When I try to return from input, it either says missing return statement either just doesn't stop even though it can see the winner.
public char input ()
{
while (status == false || numberOfMovesLeft > 0)
{
System.out.println("User "+ whoseTurn + " enter your move: "); //prompt user to make a move
char userInput = reader.next().charAt(0); // local variable to hold user input
// validation of user input
while (userInput != 'a' && userInput != 'b' && userInput != 'c'
&& userInput != 'd' && userInput != 'e' && userInput != 'f'
&& userInput != 'g' && userInput != '1' && userInput != '2'
&& userInput != '3' && userInput != '5' && userInput != '6'
&& userInput != '6' && userInput != '7' && userInput != '8'
&& userInput != '9')
{
System.out.println("Try again, user "+ whoseTurn + " enter your move: ");
userInput = reader.next().charAt(0);
}
// places user input into a board cell
for (int row = 0; row < board.length; row++)
{
for (int col = 0; col < board[row].length; col++)
{
if (board[row][col] == userInput)
{
board[row][col] = whoseTurn;
}
}
}
// check for tie result
numberOfMovesLeft--;
if (numberOfMovesLeft==0)
{
System.out.println("Tie!");
winner = 'T';
System.out.println(winner);
}
analyzeBoard();
printBoard();
done();
whoseTurn = (whoseTurn == 'X') ? '0' : 'X';
}
return winner;
}
public void analyzeBoard()
{
// row winner algoritm
for (int row = 0; row <=3; row++)
{
for (int col = 0; col < 2; col++)
{
if (board[row][col] == board[row][col + 1]
&&
board[row][col] == board[row][col + 2])
{
System.out.println("winner");
winner = whoseTurn;
System.out.println("winner "+ winner);
System.out.println("whoseTurn "+ whoseTurn);
status = true;
System.out.println("status "+status);
done();
}
else
{
//System.out.println("status "+status);
}
}
}
//column winner algoritm
for (int row = 0; row <2; row++)
{
for (int col = 0; col <= 3; col++)
{
if (board[row][col] == board[row+1][col] &&
board[row][col] == board[row+2][col])
{
System.out.println("winner");
winner = whoseTurn;
System.out.println("winner "+ winner);
System.out.println("whoseTurn "+ whoseTurn);
status = true;
//System.out.println("status "+status);
}
}
}
//diagonal winner algoritm
for (int row = 0; row <2; row++)
{
for (int col = 0; col <2; col++)
{
if (board[row][col] == board[row+1][col+1] &&
board[row][col] == board[row+2][col+2])
{
System.out.println("winner");
winner = whoseTurn;
System.out.println("winner "+ winner);
System.out.println("whoseTurn "+ whoseTurn);
status = true;
//System.out.println("status "+status);
}
}
}
//diagonal winner algoritm
for (int row = 0; row <2; row++)
{
for (int col = 2; col <=3; col++)
{
if (board[row][col] == board[row+1][col-1])
{
System.out.println("winner");
winner = whoseTurn;
System.out.println("winner "+ winner);
System.out.println("whoseTurn "+ whoseTurn);
status = true;
//System.out.println("status "+status);
}
}
}
}
you can use break; to terminate current loop or return; to terminate entire function call.
UPDATE: I found that the problem is in the Mouse() method. It will run and take values until you let go of the mouse. I need a way to pause the program or stop it until someone releases the mouse.
I'm working on a Tic Tac Toe game and I think I got it to only one problem left. I got it to work perfect, but then I messed with it to try and make the messages appear on the actual game instead of just the java interaction pane(excuse me if these aren't the right terms to use)
For some reason when I run, it will take the first move correctly and then it acts as if someone keeps clicking on the same place on the board and gives me an invalid input error multiple times. I'm not sure what to do to fix this problem, but I'm guessing the error is in the Fill() method. Any tips or hints would be greatly appreciated.
Thanks!
/*
* Tic Tac Toe Game
*/
import java.util.*;
import java.awt.*;
public class Game {
//Create Variables
public static int x;
public static int y;
public static double a;
public static double b;
public static int empty = 0;
public static int Cross = 1;
public static int Oh = -1;
public static double[][] board = new double[3][3];
public static int currentPlayer;
public static int p = 1;
//public static boolean v = false;
//Main method: draws the board and then begins game
public static void main(String args[]) {
initalize();
drawBoard();
// System.out.println("X's turn.");
for(int w = 0; w < 9; w++) {
turn();
Fill();
}
}
/*
* this method creates the graphic as a 9x9 board with the 'hashtag' for playing
*/
public static void drawBoard() {
StdDraw.setXscale(0, 9);
StdDraw.setYscale(0, 9);
StdDraw.setPenRadius(.01);
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(0, 3, 9, 3);
StdDraw.line(0, 6, 9, 6);
StdDraw.line(3, 0, 3, 9);
StdDraw.line(6, 0, 6, 9);
} //end draw board
public static void initalize() {
for(int j = 0; j <= 2; j++) {
for(int k = 0; k <= 2; k++) {
board[j][k] = 0;
}
}
}
/*
* this method will take the coordinates of the mouse when clicked as a,b coordinates
* the it will take the a,b coordinates and turn them into an x,y board position (0-2)
*/
public static void Mouse() {
while(true) {
if(StdDraw.mousePressed()) {
a = StdDraw.mouseX();
b = StdDraw.mouseY();
//System.out.println( a + " " + b);
//board location
//set column
if(0 <= a && a < 3) {
x = 0;
}
if(3 <= a && a < 6) {
x = 1;
}
if(6 <= a && a < 9) {
x = 2;
}
//set row
if(0 <= b && b < 3) {
y = 0;
}
if(3 <= b && b < 6) {
y = 1;
}
if(6 <= b && b < 9) {
y = 2;
}
//System.out.println("You clicked in Row" + x + "and column" +y);
break;
}
}
}//ends Mouse
/*
* Runs CurrentPlayer() to deicde who the current player is and then prints a message with whose turn it is
*/
public static void turn() {
CurrentPlayer();
if(currentPlayer != Cross) {
System.out.println("O's turn.");
}
if(currentPlayer != Oh) {
System.out.println("X's turn.");
}
}
/*
* this method determines if it is player X or player O
* it flip flops each time it is called and reurns the value of the 'currentPlayer' (-1 or 1)
*/
public static int CurrentPlayer() {
if(p % 2 == 0) {
currentPlayer = Oh;
} else {
currentPlayer = Cross;
}
return currentPlayer;
}//ends CurrentPlayer
/*
* this method is the actual 'playing'
* it calls Mouse() to get coordinates/board location
* determines if it is a valid move by making sure its within the board range and also checking to make sure that array spot of the board it empty(0)
* it then fills the array with the value of the currentplayer, prints the board, checks the game status for a win, adds a turn, and restarts if it is valid.
* if its not vaild it will tell you and then restart to get a valid move
*/
public static void Fill() {
Mouse();
//check if valid
if(0 <= x && x <= 2 && 0 <= y && y <= 2 && board[x][y] == 0) {
//switch player
p++;
//fill array spot
board[x][y] = currentPlayer;
//check game status and print board
PrintBoard();
GameStatus();
return;//exit method
}
//move is not valid
else {
System.out.println("Invalid. Try again.");
Fill();
}
}//ends Fill()
/*
*scrolls through board array to check for moves.
* if array value=0, its empty and does nothing
* if array value=1, its X and prints an X in that board position
* if array value=-1, its O and prints an O in that board position
*/
public static void PrintBoard() {
for(int j = 0; j <= 2; j++) {
for(int k = 0; k <= 2; k++) {
if(board[j][k] == 0) {
//do nothing leave empty
}
Font mark = new Font("Arial", Font.BOLD, 60);
if(board[j][k] == 1) {
double l = ((j + 1) * 3) - 1.5;
double m = ((k + 1) * 3) - 1.5;
//print x
StdDraw.setFont(mark);
StdDraw.setPenColor(StdDraw.RED);
StdDraw.text(l, m, "X");
}
if(board[j][k] == -1) {
double l = ((j + 1) * 3) - 1.5;
double m = ((k + 1) * 3) - 1.5;
//print O
StdDraw.setFont(mark);
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.text(l, m, "O");
}
}
}
return;
}//Ends PrintBoard()
/*
* this method checks if there is a win, cats game, or if the game is still in play
* if its a win it determines if it is an X win or O win and prints out a winners message coorespondingnto who won
* if its a cats game, it prints out cats game
* it the game is still in play it says keep playing and goes back to the Fill() method
*/
public static void GameStatus() {
Font win = new Font("Arial", Font.BOLD, 100);
Font cat = new Font("Arial", Font.BOLD, 80);
//check for win
if(// First column
board[0][0] == currentPlayer && board[0][1] == currentPlayer && board[0][2] == currentPlayer
//second column
|| board[1][0] == currentPlayer && board[1][1] == currentPlayer && board[1][2] == currentPlayer
//third column
|| board[2][0] == currentPlayer && board[2][1] == currentPlayer && board[2][2] == currentPlayer
//first row
|| board[0][0] == currentPlayer && board[1][0] == currentPlayer && board[2][0] == currentPlayer
//second row
|| board[0][1] == currentPlayer && board[1][1] == currentPlayer && board[2][1] == currentPlayer
//third row
|| board[0][2] == currentPlayer && board[1][2] == currentPlayer && board[2][2] == currentPlayer
//diagonal 1
|| board[0][2] == currentPlayer && board[1][1] == currentPlayer && board[2][0] == currentPlayer
// diagonal 2
|| board[2][2] == currentPlayer && board[1][1] == currentPlayer && board[0][0] == currentPlayer) {
//X win
while(currentPlayer == 1) {
StdDraw.setFont(win);
StdDraw.setPenColor(StdDraw.GREEN);
StdDraw.text(4.5, 4.5, "X Won!");
}
//O win
while(currentPlayer == -1) {
StdDraw.setFont(win);
StdDraw.setPenColor(StdDraw.GREEN);
StdDraw.text(4.5, 4.5, "O Won!");
}
return;
}
//cats game
else if(board[0][0] != 0 && board[0][1] != 0 && board[0][2] != 0 && board[1][0] != 0 && board[1][1] != 0 && board[1][2] != 0 && board[2][0] != 0 && board[2][1] != 0 && board[2][2] != 0) {
StdDraw.setFont(cat);
StdDraw.setPenColor(StdDraw.YELLOW);
StdDraw.text(4.5, 4.5, "Cat's Game!");
return;
}
//still playing
else {
System.out.println("Keep Playing.");
return;
}
}//Ends GameStatus
}// End Class Game
I'm working in artificial intelligence project to develop a TicTacToe 4X4 using Minimax algorithm
I have this existing program that run Minimax algorithm in 3x3 TicTacToe board.
I want to extend it to 4x4 TicTacToe
but I couldn't any idea how I can do it ??
import java.util.*;
//defines the point where to place 1 or 2
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "[" + x + ", " + y + "]";
}
}
//defines the score per point -1,0,1
class PointsAndScores {
int score;
Point point;
PointsAndScores(int score, Point point) {
this.score = score;
this.point = point;
}
}
//defince the game board
class Board {
List<Point> availablePoints;
Scanner scan = new Scanner(System.in);
int[][] board = new int[3][3];
public Board() {
}
public boolean isGameOver() {
//Game is over is someone has won, or board is full (draw)
return (hasXWon() || hasOWon() || getAvailableStates().isEmpty());
}
//check if X have won represented by 1
public boolean hasXWon() {
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) {
//System.out.println("O Diagonal Win");
return true;
}
for (int i = 0; i < 3; ++i) {
if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
// System.out.println("O Row or Column win");
return true;
}
}
return false;
}
//check if O has won represented by 2
public boolean hasOWon() {
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) {
// System.out.println("X Diagonal Win");
return true;
}
for (int i = 0; i < 3; ++i) {
if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2)) {
// System.out.println("X Row or Column win");
return true;
}
}
return false;
}
//check available states in the board
public List<Point> getAvailableStates() {
availablePoints = new ArrayList<>();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[i][j] == 0) {
availablePoints.add(new Point(i, j));
}
}
}
return availablePoints;
}
//put player move in the board
public void placeAMove(Point point, int player) {
board[point.x][point.y] = player; //player = 1 for O, 2 for X..
}
//get best movement according to the board state
public Point returnBestMove() {
int MAX = -100000;
int best = -1;
for (int i = 0; i < rootsChildrenScores.size(); ++i) {
if (MAX < rootsChildrenScores.get(i).score) {
MAX = rootsChildrenScores.get(i).score;
best = i;
}
}
return rootsChildrenScores.get(best).point;
}
//accepts input from user
void takeHumanInput() {
System.out.println("Your move: ");
int x = scan.nextInt();
int y = scan.nextInt();
Point point = new Point(x, y);
placeAMove(point, 2);
}
//display current board
public void displayBoard() {
System.out.println();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
//get min value
public int returnMin(List<Integer> list) {
int min = Integer.MAX_VALUE;
int index = -1;
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) < min) {
min = list.get(i);
index = i;
}
}
return list.get(index);
}
//get max value
public int returnMax(List<Integer> list) {
int max = Integer.MIN_VALUE;
int index = -1;
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) > max) {
max = list.get(i);
index = i;
}
}
return list.get(index);
}
//declares a list for scores
List<PointsAndScores> rootsChildrenScores;
//excutes minimax algorithm
public void callMinimax(int depth, int turn){
rootsChildrenScores = new ArrayList<>();
minimax(depth, turn);
}
//minimax algorithm
public int minimax(int depth, int turn) {
if (hasXWon()) return +1;
if (hasOWon()) return -1;
//get available states from the board
List<Point> pointsAvailable = getAvailableStates();
if (pointsAvailable.isEmpty()) return 0;
//stores scores
List<Integer> scores = new ArrayList<>();
for (int i = 0; i < pointsAvailable.size(); ++i) {
Point point = pointsAvailable.get(i);
if (turn == 1) { //O's turn select the highest from below minimax() call
placeAMove(point, 1);
int currentScore = minimax(depth + 1, 2);
scores.add(currentScore);//add scores to the list
if (depth == 0)
rootsChildrenScores.add(new PointsAndScores(currentScore, point));
} else if (turn == 2) {//X's turn select the lowest from below minimax() call
placeAMove(point, 2);
scores.add(minimax(depth + 1, 1));
}
board[point.x][point.y] = 0; //Reset this point
}
return turn == 1 ? returnMax(scores) : returnMin(scores);
}
}
//main class
public class TicTacToe {
public static void main(String[] args) {
Board b = new Board();//instantiate board
Random rand = new Random();//instantiate random value
b.displayBoard();//display board
System.out.println("Who's gonna move first? (1)Computer (2)User: ");
int choice = b.scan.nextInt();
if(choice == 1){
Point p = new Point(rand.nextInt(3), rand.nextInt(3));
b.placeAMove(p, 1);
b.displayBoard();
}
while (!b.isGameOver()) {
System.out.println("Your move: ");
Point userMove = new Point(b.scan.nextInt(), b.scan.nextInt());
b.placeAMove(userMove, 2); //2 for X and X is the user
b.displayBoard();
if (b.isGameOver()) {
break;
}
b.callMinimax(0, 1);
for (PointsAndScores pas : b.rootsChildrenScores) {
System.out.println("Point: " + pas.point + " Score: " + pas.score);
}
b.placeAMove(b.returnBestMove(), 1);
b.displayBoard();
}
if (b.hasXWon()) {
System.out.println("Unfortunately, you lost!");
} else if (b.hasOWon()) {
System.out.println("You win! This is not going to get printed.");
} else {
System.out.println("It's a draw!");
}
}
}
You need to introduce an integer variable, let's say n, which will contain the size of the board(i.e. # of cells = n*n). Before a game starts, the player will be asked for the preferred board size, 3 or 4, and the corresponding board will be created. In order for your program to work with 4x4 like it did with 3x3, we will need to place the variable n wherever we have a method or loop that needs to traverse through the board. In other words, instead of 3 we will place n. This will "generalize" our program. For example, within the display method we have 2 for loops that run as long as i and j are smaller than 3. To "generalize" our program to a semi-arbitrary board size(3 or 4), we place an n in place of the 3 so that the loop will run as long as i and j are smaller than n(3 or 4). This change from 3 to n will apply wherever we have a 3 that indicates the size of the board. Another thing we will need to change are the checking methods hasXWon() and hasOWon(). Here, we will need to add an extra section for when the board size is 4 and not 3. This will look more or less the same as it's counterpart with the only difference being that it will check the extra row, column and longer diagonals that exist in a 4x4 board. After inserting these changes, the program now looks like this:
import java.util.*;
//defines the point where to place 1 or 2
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "[" + x + ", " + y + "]";
}
}
//defines the score per point -1,0,1
class PointsAndScores {
int score;
Point point;
PointsAndScores(int score, Point point) {
this.score = score;
this.point = point;
}
}
//defince the game board
class board {
List<Point> availablePoints;
Scanner scan = new Scanner(System.in);
public int n;
int[][] board;
public board(int n) {
this.n = n;
board = new int[n][n];
}
public boolean isGameOver() {
//Game is over is someone has won, or board is full (draw)
return (hasXWon() || hasOWon() || getAvailableStates().isEmpty());
}
//check if X have won represented by 1
public boolean hasXWon() {
if(n==3){
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) {
//System.out.println("O Diagonal Win");
return true;
}
for (int i = 0; i < n; ++i) {
if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
// System.out.println("O Row or Column win");
return true;
}
}
return false;
}
else {
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == board[3][3]&& board[0][0] == 1) || (board[0][3] == board[1][2] && board[0][3] == board[2][1] && board[0][3] == board[3][0] && board[0][3] == 1)) {
//System.out.println("O Diagonal Win");
return true;
}
for (int i = 0; i < n; ++i) {
if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
// System.out.println("O Row or Column win");
return true;
}
}
return false;
}
}
//check if O has won represented by 2
public boolean hasOWon() {
if(n==3){
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) {
//System.out.println("O Diagonal Win");
return true;
}
for (int i = 0; i < n; ++i) {
if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2))) {
// System.out.println("O Row or Column win");
return true;
}
}
return false;
}
else {
if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == board[3][3]&& board[0][0] == 2) || (board[0][3] == board[1][2] && board[0][3] == board[2][1] && board[0][3] == board[3][0] && board[0][3] == 2)) {
//System.out.println("O Diagonal Win");
return true;
}
for (int i = 0; i < n; ++i) {
if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
|| (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2))) {
// System.out.println("O Row or Column win");
return true;
}
}
return false;
}
}
//check available states in the board
public List<Point> getAvailableStates() {
availablePoints = new ArrayList<>();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (board[i][j] == 0) {
availablePoints.add(new Point(i, j));
}
}
}
return availablePoints;
}
//put player move in the board
public void placeAMove(Point point, int player) {
board[point.x][point.y] = player; //player = 1 for O, 2 for X..
}
//get best movement according to the board state
public Point returnBestMove() {
int MAX = -100000;
int best = -1;
for (int i = 0; i < rootsChildrenScores.size(); ++i) {
if (MAX < rootsChildrenScores.get(i).score) {
MAX = rootsChildrenScores.get(i).score;
best = i;
}
}
return rootsChildrenScores.get(best).point;
}
//accepts input from user
void takeHumanInput() {
System.out.println("Your move: ");
int x = scan.nextInt();
int y = scan.nextInt();
Point point = new Point(x, y);
placeAMove(point, 2);
}
//display current board
public void displayboard() {
System.out.println();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
//get min value
public int returnMin(List<Integer> list) {
int min = Integer.MAX_VALUE;
int index = -1;
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) < min) {
min = list.get(i);
index = i;
}
}
return list.get(index);
}
//get max value
public int returnMax(List<Integer> list) {
int max = Integer.MIN_VALUE;
int index = -1;
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) > max) {
max = list.get(i);
index = i;
}
}
return list.get(index);
}
//declares a list for scores
List<PointsAndScores> rootsChildrenScores;
//excutes minimax algorithm
public void callMinimax(int depth, int turn){
rootsChildrenScores = new ArrayList<>();
minimax(depth, turn);
}
//minimax algorithm
public int minimax(int depth, int turn) {
if (hasXWon()) return +1;
if (hasOWon()) return -1;
//get available states from the board
List<Point> pointsAvailable = getAvailableStates();
if (pointsAvailable.isEmpty()) return 0;
//stores scores
List<Integer> scores = new ArrayList<>();
for (int i = 0; i < pointsAvailable.size(); ++i) {
Point point = pointsAvailable.get(i);
if (turn == 1) { //O's turn select the highest from below minimax() call
placeAMove(point, 1);
int currentScore = minimax(depth + 1, 2);
scores.add(currentScore);//add scores to the list
if (depth == 0)
rootsChildrenScores.add(new PointsAndScores(currentScore, point));
} else if (turn == 2) {//X's turn select the lowest from below minimax() call
placeAMove(point, 2);
scores.add(minimax(depth + 1, 1));
}
board[point.x][point.y] = 0; //Reset this point
}
return turn == 1 ? returnMax(scores) : returnMin(scores);
}
}
//main class
public class TicTacToe {
public static void main(String[] args) {
//board b = new board();//instantiate board
Random rand = new Random();//instantiate random value
Point p;
Scanner s = new Scanner(System.in);
System.out.println("Choose board size: 3 or 4?");
int n=s.nextInt();
board b = new board(n); //Instantiating board after value of n has been read. This is important because the value of n is required for the instantiation to take place.
System.out.println(b.n);
b.displayboard();//display board
System.out.println("Who's gonna move first? (1)Computer (2)User: ");
int choice = b.scan.nextInt();
if(choice == 1){
if(b.n==3)
p = new Point(rand.nextInt(3), rand.nextInt(3));
else
p = new Point(rand.nextInt(4), rand.nextInt(4));
b.placeAMove(p, 1);
b.displayboard();
}
while (!b.isGameOver()) {
System.out.println("Your move: ");
Point userMove = new Point(b.scan.nextInt(), b.scan.nextInt());
b.placeAMove(userMove, 2); //2 for X and X is the user
b.displayboard();
if (b.isGameOver()) {
break;
}
b.callMinimax(0, 1);
for (PointsAndScores pas : b.rootsChildrenScores) {
System.out.println("Point: " + pas.point + " Score: " + pas.score);
}
b.placeAMove(b.returnBestMove(), 1);
b.displayboard();
}
if (b.hasXWon()) {
System.out.println("Unfortunately, you lost!");
} else if (b.hasOWon()) {
System.out.println("You win! This is not going to get printed.");
} else {
System.out.println("It's a draw!");
}
}
}
Your program is now able to create 4x4 games. There are however two things that you need to do. First, your placeAMove(...) method doesn't check if a cell is occupied before filling it. This may lead to cells being overwritten, so you must change that by checking if a cell is occupied before trying to fill it. The second and more important thing is that although the program is now able to create 4x4 games, it will not be able to carryout a proper game. The reason for this is that the number of nodes(states) created by minimax to find the next move, although manageable in 3x3 games, rises dramatically for 4x4 games. This means that it would take your computer A LOT of time, and by a lot I mean hours, to calculate the computer's second move. Even when I rigged the game(i.e. manually inserted random 1s and 2s in the cells before allowing minimax to be called to choose the computer's move) it still took the computer over 30 seconds to calculate it's move. This renders your game, of course, unplayable in 4x4 mode. There are, of course, ways, such as Memoization or Alpha-Beta Pruning or both together, to overcome this and speed up your algorithm. Here is a previously asked question to get you started on these topics. The chess programming wiki is also a good source of information on such topics, if a bit more complex in it's structure. Here's their entry on Memoization(Here called transposition tables).
So I did a Tic Tac Toe assignment for my class. I have successfully created a simple Tic Tac Toe program but somehow the method to check for draw sometimes doesn't come out right. If everything is filled but there's no winner, then it's a draw. But if everything else is filled except for row 0 column 1, it will still show "draw" even if that box is still blank. If you don't get what I mean, just try filling out everything but the middle box on the top row but don't win, it will say "draw" even though that last box is not filled. What did I do wrong in my code???? Here's the driver:
import javax.swing.JOptionPane;
public class TwoDimensionalArray_Driverr
{
public static void main(String[]args)
{
char player = 'o';
TwoDimensionalArrayy game = new TwoDimensionalArrayy();
while (game.checkGame() == "PLAY")
{
if (player == 'o') player = 'x';
else player = 'o';
System.out.println(game);
String input = JOptionPane.showInputDialog("Enter Position of Row for player "+ player +" or press Cancel to exit");
if (input == null)
System.exit(0);
int row = Integer.parseInt(input);
input = JOptionPane.showInputDialog("Enter Position of Column for player " + player);
int column = Integer.parseInt(input);
game.set(row,column,player);
game.isDraw();
game.hasWon(row,column,player);
game.checkGame();
System.out.println(game.checkGame());
}
if (game.checkGame()=="DRAW"){
System.out.println(game);
System.out.println("It's a draw.");
}
else {
System.out.println(game);
System.out.println(player + " has won.");}
}
}
And here is the Object:
public class TwoDimensionalArrayy
{
private String currentState = "GO";
private char[][] board;
private static final int ROWS = 3;
private static final int COLUMNS = 3;
public TwoDimensionalArrayy(){
board = new char[ROWS][COLUMNS];
for(int i=0;i<ROWS;i++) //always do ROWS first!!!!
for(int j = 0;j<COLUMNS;j++)
board[i][j]=' ';
}
public void set(int i, int j, char player)
{
if(board[i][j] != ' ' )
throw new IllegalArgumentException("Position Occupied");
board[i][j] = player;
}
public String toString()
{
System.out.println("This is the board. 3x3");
System.out.println("Position start # row[0]col[0],row[0]col[1],row[0]col[2]");
String dString= "";
for (int row = 0; row<ROWS; row++)
{
if (COLUMNS>0)
dString += board[row][0];
for (int col = 1; col<COLUMNS; col++)
{
dString+= "|" + board[row][col];
} //end 2nd for
dString += "\n";
}//end first for
return dString;
}
public String checkGame(){
if (currentState=="Win"){
return "END";}
else if (currentState=="Draw"){
return "DRAW";}
else return "PLAY";
}
public void hasWon(int i,int j,char player){
if (board[i][0] == player // 3-in-the-row
&& board[i][1] == player
&& board[i][2] == player
|| board[0][j] == player // 3-in-the-column
&& board[1][j] == player
&& board[2][j] == player
|| i == j // 3-in-the-diagonal
&& board[0][0] == player
&& board[1][1] == player
&& board[2][2] == player
|| i + j == 2 // 3-in-the-opposite-diagonal
&& board[0][2] == player
&& board[1][1] == player
&& board[2][0] == player)
currentState = "Win";
}
public void isDraw(){
for ( int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLUMNS; col++) {
if (board[row][col] == ' ') {
currentState = "Play";
break;
}
else {currentState = "Draw";} // no empty cell, it's a draw}
}
}
}
}
public void isDraw(){
for ( int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLUMNS; col++) {
if (board[row][col] == ' ') {
currentState = "Play";
break;
} else {
currentState = "Draw"; // no empty cell, it's a draw
}
}
}
}
The break here will escape the inner for loop, but not the outer one. Essentially isDraw only considers the last row. You should try using return instead.