I've tried to create a Tic Tac Toe game class with the play and hasWon methods.
public class TicTacToe {
private enum State{Blank, X, O}
private int grid;
private State[][] board = new State[grid][grid];
private int moves;
//Default Constructor
public TicTacToe(int grid){
board = new State[grid][grid];
moves = 0;
}
public void play(State s, int m, int n){
if (board[m][n] == State.Blank){
board[m][n] = s;
}
moves++;
}
public boolean hasWon(State[][] board){
//check winner in rows
boolean state = false;
int j = 0;
int i = 0;
while(j <= grid) {
for (i = 0; i <= grid; i++) {
if (board[j][i] == board[j][i + 1])
state = true;
else state = false;
break;
}
if(state == false)
j++;
else return true;
}
//check winner in columns
while(j <= grid) {
for (i = 0; i < grid; i++) {
if (board[i][j] == board[i + 1][j])
state = true;
else state = false;
break;
}
if (state == true)
j++;
else return true;
}
//check winner in top diagonal
while(j <= grid && i <= grid){
if (board[i][j] == board[i+1][j+1])
state = true;
else state = false;
break;
i++;
j++;
return true;
}
//check winner in bottom diagonal
int k = grid;
int l = grid;
while(k >= 0 && l >= 0){
if (board[k][l] == board[k-1][l-1])
state = true;
else state = false;
break;
k--;
l--;
return true;
}
return false;
}
}
However when called in the Main class the program behaves erratically. Is there a logical problem in the code.
When checking your rows with
for (i = 0; i < n; i++) {
if (board[j][i] == board[j][i + 1])
state = true;
}
this code always sets the state to true if the last two chars in the row are the same, independently of the chars previous in that row.
The same thing for columns and the diagonal (of which you are checking only as Todd said).
You want to stop comparing values for that row if you find some values that are not equal:
for (i = 0; i < n; i++) {
if (board[j][i] == board[j][i + 1]) {
state = true;
} else {
state = false;
break;
}
}
Same for rows and diagonal(s).
Edit:
Furthermore: You are not setting your field grid in the constructor, so it always is 0 and you are not checking your complete rows, columns, diagonals
Missing:
this.grid = grid;
Related
I coded this to check if someone won, but it looks like it will only check for if someone won by horizontal, any ideas to check if someone won by vertical and diagonal?
public boolean checkForVictory() {
int xInRow = 0;
int oInRow = 0;
boolean playerOneWins = false;
boolean playerTwoWins = false;
//loop through the map and check if every cell contains x or o and then add the number. If in the next cell is another character, then put it back to 0
for(int i=0; i<7; i++){
for(int j=0; j<6; j++){
if(j == 0){
xInRow = 0;
oInRow = 0;
}
if(Map.getInstance().map[i][j].contains("x")){
xInRow++;
oInRow = 0;
}
if(Map.getInstance().map[i][j].contains("o")){
oInRow++;
xInRow = 0;
}
if(xInRow == 4)
playerOneWins = true;
if(oInRow == 4)
playerTwoWins = true;
}
}
if(playerOneWins){
GameModel.getInstance().player1.playerVictory = true;
return true;
}
if(playerTwoWins){
GameModel.getInstance().player2.playerVictory = true;
return true;
}
return false;
}
I've been working on for awhile but i can't seem to fix it and get it to wrong correctly. It tells me where the exception is but I don't see any problems.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at TicTacToe.displayWinner(TicTacToe.java:243)
at TicTacToe.playerMove(TicTacToe.java:151)
at TicTacToe.playGame(TicTacToe.java:303)
at TicTacToeTester.main(TicTacToeTester.java:20)
Java Result: 1
import java.util.Scanner; //Used for player's input in game
public class TicTacToe
{
//instance variables
private char[][] board; //Tic Tac Toe Board, 2d array
private boolean xTurn; // true when X's turn, false if O's turn
private Scanner input; // Scanner for reading input from keyboard
//Constants for creation of gameboard
public final int ROWS = 3; //total rows
public final int COLS = 3; //total columns
public final int WIN = 3; //amount needed to win
public TicTacToe()
{
//creates the board
board = new char[ROWS][COLS];
for(int r = 0; r < ROWS; r++)
{
for(int c = 0; c < COLS; c++)
{
board[r][c] = ' ';
}
}
//X's turn when game starts
xTurn = true;
//creates our input object for the turn player
input = new Scanner(System.in);
}
//shows game board
public void displayBoard()
{
int colNum = 0; //number of columns
int rowNum = 0; //number of rows
//creates column labels
System.out.println(" \n");
System.out.println(" Columns ");
for (int num = 0; num < COLS; num++)
{
System.out.print(" " + colNum);
colNum++;
}
//creates vertical columns and spaces between each spot
System.out.println(" \n");
for (int row = 0; row < ROWS; row++)
{
//numbers rows
System.out.print(" " + rowNum + " ");
rowNum++;
for (int col = 0; col < COLS; ++col)
{
System.out.print(board[row][col]); // print each of the cells
if (col != COLS - 1)
{
System.out.print(" | "); // print vertical partition
}
}
System.out.println();
//creates seperation of rows
if (row != ROWS - 1)
{
System.out.println(" ------------"); // print horizontal
partition
}
}
//labels row
System.out.println("Rows \n");
}
//displays turn player
public void displayTurn()
{
if (xTurn)
{
System.out.println("X's Turn");
}
else
{
System.out.println("O's Turn");
}
}
//allows you to make move
public boolean playerMove()
{
boolean invalid = true;
int row = 0;
int column = 0;
while(invalid)
{
System.out.println("Which row (first) then column (second)
would you like to \n"
+ "play this turn? Enter 2 numbers between 0-2 as \n"
+ "displayed on the board, seperated by a space to
\n"
+ "choose your position.");
row = input.nextInt();
column = input.nextInt();
//checks if spot is filled
if (row >= 0 && row <= ROWS - 1 &&
column >= 0 && column <= COLS - 1)
{
if (board[row][column] != ' ')
{
System.out.println("Spot is taken \n");
}
else
{
invalid = false;
}
}
else
{
System.out.println("Invalid position");
}
//fills spot if not taken
if (xTurn)
{
board[row][column] = 'X';
}
else
{
board[row][column] = 'O';
}
}
return displayWinner(row,column);
}
public boolean displayWinner(int lastR, int lastC)
{
boolean winner = false;
int letter = board[lastR][lastC];
//checks row for win
int spotsFilled = 0;
for (int c = 0; c < COLS; c++)
{
if(board[lastR][c] == letter)
{
spotsFilled++;
}
}
if (spotsFilled == WIN)
{
winner = true;
if (xTurn)
{
System.out.println("X won");
displayBoard();
}
else
{
System.out.println("O won");
displayBoard();
}
}
//checks columns for win
spotsFilled = 0;
for (int r = 0; r < ROWS; r++)
{
if(board[r][lastC] == letter)
{
spotsFilled++;
}
}
if (spotsFilled == WIN)
{
winner = true;
if (xTurn)
{
System.out.println("X won");
displayBoard();
}
else
{
System.out.println("O won");
displayBoard();
}
}
//checks diagonals for win
spotsFilled = 0;
for (int i = 0; i < WIN; i++)
{
if(board[i][i] == letter)
{
spotsFilled++;
}
}
if(spotsFilled == WIN)
{
winner = true;
if (xTurn)
{
System.out.println("X won");
displayBoard();
}
else
{
System.out.println("O won");
displayBoard();
}
}
//checks other diagonal
spotsFilled = 0;
for(int i = 0; i < WIN; i++)
{
if(board[i][COLS-i] == letter)
{
spotsFilled++;
}
}
if(spotsFilled == WIN)
{
winner = true;
if (xTurn)
{
System.out.println("X won");
displayBoard();
}
else
{
System.out.println("O won");
displayBoard();
}
}
return winner;
}
//checks if board is full
public boolean fullBoard()
{
int filledSpots = 0;
for(int r = 0; r < ROWS; r++)
{
for (int c = 0; c < COLS; c++)
{
if (board[r][c] == 'X' || board[r][c] == 'O')
{
filledSpots++;
}
}
}
return filledSpots == ROWS*COLS;
}
//plays game
public void playGame()
{
boolean finish = true;
System.out.println("Are your ready to start?");
System.out.println("1 for Yes or 0 for No? : ");
int choice = input.nextInt();
if (choice == 1)
{
while (finish)
{
displayBoard();
displayTurn();
if (playerMove())
{
displayBoard();
}
else if (fullBoard())
{
displayBoard();
System.out.println("Draw");
}
else
{
xTurn=!xTurn;
}
}
}
}
}
my tester
public class TicTacToeTester {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
TicTacToe tictactoe = new TicTacToe();
tictactoe.playGame();
}
}
Your Player Move method has an issue take a look at this if you notice you have commented saying "// fills spot when not taken" but you misplaced the while loop bracket and included move part inside it so it threw that exception, just close the while loop bracket before moving as follows (also follow #oblivion Creations Answer these are the two issues with your code) :-
public boolean playerMove()
{
boolean invalid = true;
int row = 0;
int column = 0;
while (invalid)
{
System.out.println("Which row (first) then column (second)" + "would you like to \n"
+ "play this turn? Enter 2 numbers between 0-2 as \n"
+ "displayed on the board, seperated by a space to" + "\n" + "choose your position.");
row = input.nextInt();
column = input.nextInt();
// checks if spot is filled
if (row >= 0 && row <= ROWS - 1 && column >= 0 && column <= COLS - 1)
{
if (board[row][column] != ' ')
{
System.out.println("Spot is taken \n");
}
else
{
invalid = false;
}
}
else
{
System.out.println("Invalid position");
}
} // close while loop here
// fills spot if not taken
if (xTurn)
{
board[row][column] = 'X';
}
else
{
board[row][column] = 'O';
}
return displayWinner(row, column);
}
The reason you are getting your exception is this section of code inside your displayWinner method:
//checks other diagonal
spotsFilled = 0;
for(int i = 0; i < WIN; i++)
{
if(board[i][COLS-i] == letter)
{
spotsFilled++;
}
}
When i = 0 then COLS-i will be 3. This is outside the bounds of your array.
There are multiple ways to solve this, one would be to increase i by 1 during comparison.
//checks other diagonal
spotsFilled = 0;
for(int i = 0; i < WIN; i++)
{
if(board[i][COLS-(i+1)] == letter)
{
spotsFilled++;
}
}
Edit: also make sure you check out Null Saints answer, as it will cause you headaches later if you don't address it now.
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).
This is a class that creates the game connect four in console and drawing panel, and I am having trouble in the connectedFour method where it determines if someone has gotten 4 discs in a row. The problem is, is that I am not sure how to set up my for loops to check through the array for four discs in a row
Here is my code:
import java.util.*;
import java.awt.*;
public class ConnectFour{
public static void main(String[] args){
//board
DrawingPanel panel = new DrawingPanel(550,550);
int rowAvailable;
Graphics g = panel.getGraphics();
g.drawLine(0,0,0,500);
g.drawLine(0,0,500,0);
g.drawLine(500,0,500,427);
g.drawLine(0,427,500,427);
for(int i = 0; i< 6; i++){
for(int j= 0; j<= 6; j++){
g.setColor(Color.YELLOW);
g.fillRect(j*71,i*71,71,71);
g.setColor(Color.WHITE);
g.fillOval(j*71,i*71,71,71);
}
}
//setBlankArray
Scanner console = new Scanner(System.in);
char[][] board = new char[6][7];
for(int j = 0;j <= 6; j++){
for(int i= 0; i < 6; i++){
board[i][j] = ' ';
}
}
boolean isBlack = true;
boolean isRed = false;
int column = 0;
boolean playersTurn = true;
boolean rightNum = false;
//oneTurn
while(getWinner(board, playersTurn)){
//while(playersTurn == true){
rightNum = false;
if(isBlack == true){
// displayCurrentPlayer
System.out.println("Black's Turn");
g.setColor(Color.WHITE);
g.drawString("Red Disc's Turn",200, 450);
g.setColor(Color.BLACK);
g.drawString("Black Disc's Turn",200, 450);
}
else{
// displayCurrentPlayer
System.out.println("Red's Turn");
g.setColor(Color.WHITE);
g.drawString("Black Disc's Turn",200, 450);
g.setColor(Color.RED);
g.drawString("Red Disc's Turn",200, 450);
}
System.out.print("Choose a column to place your disk (1-7): ");
while(rightNum == false){
column = (console.nextInt()) -1;
if(column >= 0 && column < 7 && board[0][column] == ' '){
rightNum = true;
}
else{
System.out.print("Try again: ");
}
}
drawBoard(column, board, isBlack, isRed, board, g);
isBlack = !isBlack;
}
if(isBlack == false){System.out.println("Congratulations Black Player");}
else{System.out.println("Congratulations Red Player");}
// use the while loop to say try again if the column is filled.
}
public static void drawBoard(int column, char[][] board, boolean isBlack, boolean isRed, char[][] availability,Graphics g){
char player = ' ';
if(isBlack == true){
g.setColor(Color.BLACK);
player = 'b';
}
else{
g.setColor(Color.RED);
player = 'r';
}
int x = 0;
int row = 5;
while(board[row-x][column] != ' '){
x++;
}
row = row-x;
g.fillOval((column * 71),(row * 71), 71,71);
board[row][column] = player;
}
public static boolean getWinner(char[][] board, boolean playersTurn){
int verticalCount = 0;
boolean isVertical = false;
for(int i = 6; i >= 0; i--){
verticalCount = 0;
for(int j = 5; j > 0; j--){
if(board[j][i] == board[j-1][i] && board[j][i] != ' '){
verticalCount++;
}
if(verticalCount == 4){
isVertical = true;
}
}
}
int horizontalCount = 0;
boolean isHorizontal = false;
for(int i =1; i <= 5; i++){
for(int j =1; j<6; j++){
if(board[j][i] == board[j][i+1] && board[j][i] != ' '){
horizontalCount++;
}
if(horizontalCount == 3){
isHorizontal = true;
}
}
}
int diagonalCount = 0;
boolean isDiagonal = false;
// for(int i = 0; i<=6; i++){
// for(int j =0; j<6; j++){
// if(board[i][j-1] == board[i][j]){
// diagonalCount++;
// }
// }
// }
if(isVertical || isHorizontal || isDiagonal){
playersTurn = false;
}
else{
playersTurn = true;}
return playersTurn;
}
}
I would implement this by checking if the game-winning condition is met after a disc has been placed. This way you aren't iterating over the entire board after each move.
Regardless, try this:
replace
while (gameWon == false ){
with
while (!connectedFour(board, playersTurn)) {
I don't think this will completely fix your problems as it looks like there are a handful of other things wrong with the code you've posted.
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.