Minimax algorithm in 4x4 TicTacToe board - java

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).

Related

my do-while loop seems to be running forever even though i change the value of the condition

boolean onGoing = true;
do {
String p1 = "playing";
while (p1.equals("playing")) {
System.out.println("Player 1, enter hit row/column:");
int a = sc.nextInt();
int b = sc.nextInt();
if (a >= 0 && a < 5 && b >= 0 && b < 5) {
if (history1[a][b] == '-') {
p1 += " no more";
if (board2[a][b] == '#') {
history1[a][b] = 'X';
board2[a][b] = 'X';
String status = check(board2);
if (status.equals("win")) {
System.out.println("PLAYER 1 WINS! YOU SUNK ALL OF YOUR OPPONENT'S SHIPS!");
onGoing = false;
printBattleShip(board1);
printBattleShip(board2);
break;
} else {
System.out.println("PLAYER 1 HIT PLAYER 2's SHIP!");
}
} else if (board2[a][b] == '-') {
System.out.println("PLAYER 1 MISSED!");
history1[a][b] = 'O';
board2[a][b] = 'O';
}
} else {
System.out.println("You already fired on this spot. Choose different coordinates.");
}
} else {
System.out.println("Invalid coordinates. Choose different coordinates.");
}
}
String p2 = "playing";
while (p2.equals("playing")) {
System.out.println("Player 2, enter hit row/column:");
int c = sc.nextInt();
int d = sc.nextInt();
if (c >= 0 && c < 5 && d >= 0 && d < 5) {
if (history2[c][d] == '-') {
p2 += " no more";
if (board1[c][d] == '#') {
history2[c][d] = 'X';
board1[c][d] = 'X';
String status = check(board1);
if (status.equals("win")) {
System.out.println("PLAYER 2 WINS! YOU SUNK ALL OF YOUR OPPONENT'S SHIPS!");
onGoing = false;
printBattleShip(board2);
printBattleShip(board1);
break;
} else {
System.out.println("PLAYER 2 HIT PLAYER 1's SHIP!");
}
} else if (board1[c][d] == '-') {
history2[c][d] = 'O';
board1[c][d] = 'O';
System.out.println("PLAYER 2 MISSED!");
}
} else {
System.out.println("You already fired on this spot. Choose different coordinates.");
}
} else {
System.out.println("Invalid coordinates. Choose different coordinates.");
}
}
} while (onGoing);
private static String check(char[][] arr1) {
int sum = 0;
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1.length; j++) {
if (arr1[i][j] == '#') {
sum += 1;
}
}
}
if (sum == 0) {
return "win";
} else {
return "keep playing";
}
}
// I declared and initialized a boolean variable called ongoing before a do-while loop. Then I create a while loop inside the do while loop. And inside the while loop, there are a series of conditional statement. Eventually, I changed the value of the boolean variable and feed it back to the while statement, letting it evaluate it. But it doesn't seem to change the value. Is it because the scope of the variable? How can I fix it?
edit: check method added

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.

Weird behavior of for loops in specific conditions. Processing

I'm learning how to use processing and tried to make a simple snake game, while doing it it does show (although it was cntrl+c cntrl+v from the first one, which was up) a Weir behavior in for loops specifically for going right or down.
i managed to fix the 'down' problem by simply changing
for(int k=0;k<56;k++)
to
for(int k=55;k<=0;k--)
which is exactly the same thing, isn't it? i am i missing something?
int [][] snakeHead = new int[60][60];
int game = 1;
int value = 0;
String s = "You lost\nPress SHIFT to Restart";
void setup(){
size(600,600);
frameRate(10);
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
snakeHead[i][k] = 0;
}
}
snakeHead[1][22] = 1;
game = 1;
value = 0;
}
void draw(){
background(0);
fill(255);
rect(20, 20, 560, 560);
if(game == 1){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1){
fill(0,255,0);
rect(20+i*10, 20+k*10, 10,10);
}
}
}
if(value == 1){
up();
}else if(value == 2){
down();
}else if(value == 3){
left();
}else if(value == 4){
right();
}
}
else{
textSize(32);
textAlign(CENTER);
fill(0,0,255);
text(s, 300, 300);
}
}
void keyPressed(){
if(key == CODED){
if(keyCode == UP){
value = 1;
}
else if(keyCode == DOWN){
value = 2;
}
else if(keyCode == LEFT){
value = 3;
}
else if(keyCode == RIGHT){
value = 4;
}else if(keyCode == SHIFT){
setup();
}
}
}
void up(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && k == 0){
game = 0;
}else if(snakeHead[i][k] == 1){
snakeHead[i][k-1] = 1;
snakeHead[i][k]=0;
}
}
}
}
void down(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && k == 55){
game = 0;
}else if(snakeHead[i][k] == 1 && k != 55){
snakeHead[i][k+1] = 1;
snakeHead[i][k] = 0;
}
}
}
}
void right(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && i == 55){
game = 0;
}else if(snakeHead[i][k] == 1 && i != 55){
snakeHead[i+1][k] = 1;
snakeHead[i][k]=0;
}
}
}
}
void left(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && i == 0){
game = 0;
}else if(snakeHead[i][k] == 1){
snakeHead[i-1][k] = 1;
snakeHead[i][k]=0;
}
}
}
}
Your problem in the right and down that in both you update the head down the loop (with i+1 or j+1) so the else block get execute more then once (in the up and left you doing i-1 and j-1 so it doesn't happens there).
Let look at the right function to demonstrate:
void right(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && i == 55){
game = 0;
} else if(snakeHead[i][k] == 1 && i != 55){
snakeHead[i+1][k] = 1; // update the sankeHead to i+1 which will be reached in the next iteration in i so basiclly keep moving right till reach if block
snakeHead[i][k]=0;
}
} // end k loop
} // end i loop
}
To fix this all you need to do is add return because you only want to move the snakeHead once!
so:
void right(){
for(int i=0;i<56;i++){
for(int k=0;k<56;k++){
if(snakeHead[i][k] == 1 && i == 55){
game = 0;
return;
} else if(snakeHead[i][k] == 1 && i != 55){
snakeHead[i+1][k] = 1;
snakeHead[i][k]=0;
return;
}
} // end k loop
} // end i loop
}

Tic Tac Toe Loop/Method running too many times

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

Tic Tac Toe java draw game

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.

Categories