I am a beginner java student writing a gui tic-tac-toe program for my class. (No players, just computer generated).
Everything in my program works as expected, except for one thing; it seems that the placement of my method call for checkWinner is not place correctly, because the assignment for the X's and O's always finish. Why won't the loop end as soon as there is a winner?
It will return the correct winner based on the method call, but the for-loop will continue to iterate and fill in the rest (so sometimes it looks like both the x and o win or one wins twice). I've been going crazy, thinking it might be the placement of my checkWinner method call and if statement. When I set the winner = true; shouldn't that cancel the loop? I have tried putting it between, inside and outside each for-loop with no luck :(
I have marked the area I think is the problem //What is wrong here?// off to the right of that part the code. Thank you for any input!! :)
public void actionPerformed(ActionEvent e)
{
int total = 0, i = 0;
boolean winner = false;
//stop current game if a winner is found
do{
// Generate random # 0-1 for the labels and assign
// X for a 0 value and O for a 1 value
for (int row = 0; row < gameboard.length; row++) //rows
{
for (int col = 0; col < gameboard[row].length; col++) //columns
{
//Generate random number
gameboard[row][col] = (int)(Math.random() * 2);
//Assign proper values
if(gameboard[row][col] == 0)
{
labels[i].setText("X");
gameboard[row][col] = 10; //this will help check for the winner
}
else if(gameboard[row][col] == 1)
{
labels[i].setText("O");
gameboard[row][col] = 100; //this will help check for winner
}
/**Send the array a the method to find a winner
The x's are counted as 10s
The 0s are counted as 100s
if any row, column or diag = 30, X wins
if any row, column or diag = 300, Y wins
else it will be a tie
*/
total = checkWinner(gameboard); **//Is this okay here??//**
if(total == 30 || total == 300) //
winner = true; //Shouldn't this cancel the do-while?
i++; //next label
}
}//end for
}while(!winner);//end while
//DISPLAY WINNER
if(total == 30)
JOptionPane.showMessageDialog(null, "X is the Winner!");
else if(total == 300)
JOptionPane.showMessageDialog(null, "0 is the Winner!");
else
JOptionPane.showMessageDialog(null, "It was a tie!");
}
The easiest way would be to break all loops at once. (Even if some people dont like this)
outerwhile: while(true){
// Generate random # 0-1 for the labels and assign
// X for a 0 value and O for a 1 value
for (int row = 0; row < gameboard.length; row++) //rows
{
for (int col = 0; col < gameboard[row].length; col++) //columns
{
total = checkWinner(gameboard);
if(total == 30 || total == 300)
break outerwhile; //leave outer while, implicit canceling all inner fors.
i++; //next label
}
}//end for
}//end while
This However would not allow for the "tie" option, because the while will basically restart a game, if no winner has been found. To allow tie, you dont need the outer while at all, and can leave both fors at once, when a winner is found:
Boolean winner = false;
outerfor: for (int row = 0; row < gameboard.length; row++) //rows
{
for (int col = 0; col < gameboard[row].length; col++) //columns
{
total = checkWinner(gameboard);
if(total == 30 || total == 300){
winner = true;
break outerfor; //leave outer for, implicit canceling inner for.
}
i++; //next label
}
}//end for
if (winner){
//winner
}else{
//tie.
}
First of all, your code iterates through a board and generates random marks of X and O. This leads to some very odd board states, being always filled row-by-row, and possibly with unbalanced number of X and O marks.
IMHO you should organize your code in opposite manner to fill a board similary to a true game. I mean a series of 9 marks 'XOXOXOXOX' spreaded over the board.
Let Labels labels be a nine-character array, initialized to 9 spaces.
public int doGame( Labels labels)
{
labels = " ";
int itisXmove = true; // player X or O turn
for( int movesLeft = 9; movesLeft > 0; movesLeft --)
{
int position = // 0 .. movesLeft-1
(int) Math.floor(Math.random() * movesLeft);
for( int pos = 0; pos < 9; pos ++) // find position
if( labels[ pos] == " ") // unused pos?
if( position-- == 0) // countdown
{
if( itisXmove) // use the pos
labels[ pos] = "X"; // for current player
else
labels[ pos] = "O";
break;
}
int result = checkWinner( labels); // who wins (non-zero)?
if( result != 0)
return result;
itisXmove = ! itisXmove; // next turn
}
return 0; // a tie
}
then
public void actionPerformed(ActionEvent e)
{
Labels labels;
int result = doGame( labels);
if( result == valueForX)
JOptionPane.showMessageDialog(null, "X is the Winner!");
else if( result == valueForO)
JOptionPane.showMessageDialog(null, "O is the Winner!");
else
JOptionPane.showMessageDialog(null, "It's a tie!");
for( int rowpos = 0; rowpos < 9; rowpos += 3)
{
for( int colpos = 0; colpos < 3; colpos ++)
/* output (char)label[ rowpos + colpos] */;
/* output (char)newline */;
}
}
I think you should change your loop condition and add one more bool.
You have a "tie" condition but currently you only check for winner. The only explanation without the checkWinner code is that you are encountering a tie every time.
So...
boolean tie;
boolean winner;
do {
//your stuff
}
while(!(tie || winner))
Edit: I didn't realize you put the while loop outside your for loop, you will need to break out of your for loops in order for the while condition to be checked.
//stop current game if a winner is found
do{
for (int row = 0; row < gameboard.length; row++) //rows
{
for (int col = 0; col < gameboard[row].length; col++) //columns
{
if(winner || tie)
break;
}//end for
if(winner || tie)
break;
}//end for
}while(!(winner || tie));//end while
//the rest of your stuff here
You're not checking the value of winner until both for loops complete. Add a break right after you set winner = true, and add an
if (winner)
{
break;
}
to the beginning or end of your outer for loop.
Your issue is that your do/while statement is wrapped around the for statements. So the for statements end up running their entire cycle before it ever reaches the while statement. A solution to get around this is checking for a winner in the for statements and breaking:
//stop current game if a winner is found
do {
for (int row = 0; row < gameboard.length; row++) //rows
{
for (int col = 0; col < gameboard[row].length; col++) //columns
{
// ... your other code ...
total = checkWinner(gameboard);
if(total == 30 || total == 300) {
winner = true;
break; // end current for-loop
}
i++; //next label
}
if (winner) break; // we have a winner so we want to kill the for-loop
} //end for
} while(!winner); //end while
So you should be able to just loop through the two for-statements and break upon a winner. Your code also does not seem to handle a tied case, but I am guessing you already know that.
Related
So I created a checkWinner method, using 'row' and 'col' private variables so I can locate the 'curPlayer' position in the 2D array.
import java.util.Scanner;
public class TicTacBoard
{
private char[][] board; // 2-D array of characters
private char curPlayer; // the player whose turn it is (X or O)
// added so I can locate the current player location in the board
private int row;
private int col;
// Constructor: board will be size x size
public TicTacBoard(int size)
{
board = new char[size][size];
// initialize the board with all spaces:
for(row=0; row < board.length; row++)
for(col=0; col < board[row].length; col++)
board[row][col] = ' ';
curPlayer = 'X'; // X gets the first move
}
public void playGame()
{
display();
do
{
takeTurn();
display();
}while(!checkWinner(row, col));
}
/////// display ////////
// Display the current status of the board on the
// screen, using hyphens (-) for horizontal lines
// and pipes (|) for vertical lines.
public void display()
{
System.out.println();
dispRow(0);
System.out.println("-----");
dispRow(1);
System.out.println("-----");
dispRow(2);
System.out.println();
}
// Display the current status of row r of the board
// on the screen, using hyphens (-) for horizontal
// lines and pipes (|) for vertical lines.
private void dispRow(int r)
{
System.out.println(board[r][0] + "|" + board[r][1]
+ "|" + board[r][2]);
}
/////// takeTurn ////////
// Allow the curPlayer to take a turn.
// Send output to screen saying whose turn
// it is and specifying the format for input.
// Read user's input and verify that it is a
// valid move. If it's invalid, make them
// re-enter it. When a valid move is entered,
// put it on the board.
public void takeTurn()
{
Scanner scan = new Scanner(System.in);
int row, col;
boolean invalid;
do{
invalid = false; // assume correct entry
System.out.println("It is now " + curPlayer + "'s turn.");
System.out.println("Please enter your move in the form row column.");
System.out.println("So 0 0 would be the top left, and 0 2 would be the top right.");
row = scan.nextInt();
col = scan.nextInt();
if(row < 0 || col < 0 || row > 2 || col > 2)
{
System.out.println("Invalid entry: row and column must both be between 0 and 2 (inclusive).");
System.out.println("Please try again.");
invalid = true;
}
else if(board[row][col] != ' ')
{
System.out.println("Invalid entry: Row " + row + " at Column " + col
+ " already contains: " + board[row][col]);
System.out.println("Please try again.");
invalid = true;
}
}while(invalid);
// Now that input validation loop is finished, put the move on the board:
board[row][col] = curPlayer;
// Switch to the other player (take turns):
if(curPlayer == 'X')
curPlayer = 'O';
else
curPlayer = 'X';
}
// If the game is over, print who won (if anyone),
// and return true. If the game is not over, return false.
public boolean checkWinner(int row, int col)
{
// YOUR CODE GOES HERE
int x = row;
int y = col;
// board length is always 3 here
// check winner on column
for (int i = 0; i < board.length; i++) {
if (board[x][i] != curPlayer)
break;
if (i == board.length - 1)
System.out.println("Player " + curPlayer + " wins!");
return true;
}
//check winner on row
for (int i = 0; i < board.length; i++) {
if (board[i][y] != curPlayer)
break;
if (i == board.length - 1)
System.out.println("Player " + curPlayer + " wins!");
return true;
}
// checks winner on diagonal up
if (x == y) {
for (int i = 0; i < board.length; i++) {
if (board[i][i] != curPlayer)
break;
if (i == board.length - 1)
System.out.println("Player " + curPlayer + " wins!");
return true;
}
}
// check winner on diagonal down
if (x + y == board.length - 1){
for (int i = 0; i < board.length; i++) {
if (board[i][(board.length-1)-i] != curPlayer)
break;
if (i == board.length - 1)
System.out.println("Player " + curPlayer + " wins!");
return true;
}
}
// checks if board is full
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
if (board[i][j] == '-')
System.out.println("Nobody won, game ends in a draw!");
return true;
}
}
return false;
}
}
The code works but I while I was checking I got this:
| |
-----
| |
-----
| |
It is now X's turn.
Please enter your move in the form row column.
So 0 0 would be the top left, and 0 2 would be the top right.
2 0
| |
-----
| |
-----
X| |
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at TicTacBoard.checkWinner(TicTacBoard.java:126)
at TicTacBoard.playGame(TicTacBoard.java:43)
at Main.main(Main.java:14)
I thought the board length is always 3 with the location ranging from 0 to 3. Any solutions to this error? Any more efficient ways to do this? Please let me know!
You have a "shadowing" problem - that is, you're shadowing the instance fields row and col with local variables in your takeTurn method.
In it's current state...
// Constructor: board will be size x size
public TicTacBoard(int size) {
board = new char[size][size];
// initialize the board with all spaces:
for (row = 0; row < board.length; row++) {
for (col = 0; col < board[row].length; col++) {
board[row][col] = ' ';
}
}
curPlayer = 'X'; // X gets the first move
}
after the constructor has run, row and col will be 3, but in takeTurn, you define row and col as local variables...
public void takeTurn() {
Scanner scan = new Scanner(System.in);
int row, col;
boolean invalid;
This means, that when you call checkWinner in the playGame method...
public void playGame() {
display();
do {
takeTurn();
display();
} while (!checkWinner(row, col));
}
You're passing the instance field values (of 3/3) and everything breaks.
So, the "quick" solution would be to remove the local declaration of row/col from takeTurn
public void takeTurn() {
Scanner scan = new Scanner(System.in);
//int row, col;
boolean invalid;
You could also fix this in the constructor, but making row/col local variables
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
board[row][col] = ' ';
}
}
but at some point, you need to update the row/col value for the player, but I might consider passing this information back from takeTurn rather than trying to use instance fields.
You also have a subtle, but common bug in your if statements. Without brackets, { and }, only the line IMMEDIATELY following the if statement will be executed when the conditional statement above is true. Your INDENTATION, however, indicates that you expected a different behavior.
For instance, your very first for loop is:
for (int i = 0; i < board.length; i++) {
if (board[x][i] != curPlayer)
break;
if (i == board.length - 1)
System.out.println("Player " + curPlayer + " wins!");
return true;
}
Here, only the System.out.println() line is executed when the if statement is true. The indentation of the return true; statement indicates that you expect it to only run with the println(), only when the conditional is true.
The return true; line is NOT dependent upon the preceding if statement, though, because it is not within brackets and the if statement only runs the line immediately following it. This means that the for loop is only ever running ONE ITERATION because the return line is STAND-ALONE and executes every single time, regardless of how those if statements evaluate.
You should ALWAYS, ALWAYS, ALWAYS add brackets to your if statements, even if they are "one-liners". With that in mind, I'd expect it to look more like:
for (int i = 0; i < board.length; i++) {
if (board[x][i] != curPlayer) {
break;
}
if (i == board.length - 1) {
System.out.println("Player " + curPlayer + " wins!");
return true;
}
}
Now the return line is only executed when the preceding if statement is true.
So I am currently coding Connect 4 on Netbeans. I have the vertical and horizontal check already made but I am having trouble with the diagonal check, specifially the for loops. Currently my code for this,
public static boolean checkDiagnol(String[][] board, int counter, String playerMoving, int lastPlacedTileRow, int col) {
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
for (int i = lastPlacedTileRow + 1, q = col +1; i < board.length, q < board[0].length; i++,q++) {
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
return false;
}
lastPlacedTileRow is the row of the last placed tile, col is the column chosen by the user, counter is a counter used to check if there are 4 tiles in a row, and playerMoving is the current players tile.
The current problem I have is that my for loops give errors. This is my first time using two variables in a single for loop so I am not sure how it is supose to be arranged.
Thanks for the help
Syntax
You have put a semicolon instead of a comma in the first for loop.
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
this should be
for (int i = lastPlacedTileRow-1, q = col-1; i >= 0, q >=0; i--,q--){
Logic
I think variable i should be counted down (or up) in both the loops because we have to check below the lastPlacedTileRow in both cases.
I have a recursion method for a mineSweeper but I would like to write a loop for when the cell is empty, which should reveal the 8 cells surrounding the empty one by recursion, how do I do it?
This is the reveal method I have:
void reveal(int x,int y,char[][] mineField,boolean[][] isVisible){
System.out.println(x + " " + y);
if(x<0 || x>=mineField.length || y<0 || y>mineField[0].length){
return;
}
if(mineField[x][y] == '*'){
isGameOver = true; // there is a bomb, stop game.
return;
}
if(mineField[x][y] == '1'||mineField[x][y] == '2'){ // how do I make it any number (1-8) instead of 1 or 2
isVisible[x][y] = true;
return;
}
if(mineField[x][y] == '.'){
isVisible[x][y] = true;
reveal(i,j, mineField, isVisible); // how do I write a method here to reveal the 8 surrounding cells?
}
}
and this is my print method:
void printMineMap(char[][] mineField,boolean[][] isVisible){
for(int i=0; i<mineField.length; i++){
for(int j=0; j<mineField[0].length; j++){
if(isVisible[i][j]=true)
System.out.println(" "+mineField[i][j]+" ");
else if(isVisible[i][j]=false)
System.out.println("[ ]");
}
System.out.println(" ");
}
}
You can loop over all fields with a coordinate difference of at most 1 in x and y direction to the current field.
for (int i = x-1; i <= x+1; i++) {
for (int j = y-1; j <= y+1; j++) {
reveal(i,j, mineField, isVisible);
}
}
However, you don't want to reveal fields that are already visible in order to avoid an infinite recursion. So add this at the beginning of the reveal method but after the check if x and y is in range:
if (isVisible[x][y]) {
return;
}
My brother offered me a challege to help my studies by making a game that only runs in the main method instead of using other classes to make sure I still remember my old stuff. Bases off that I went with a cat and mouse game where the player is the mouse looking for the cheese while avoiding all the cats. When you enter an empty "room" (cell) the game is supposed to give you a clue at how far you are from the cheese. Now the game runs but my clues just keep going higher and higher to the point where it over the amount of rooms in the maze. I am stumpped on where the problem is.
Here's the code
import java.util.Scanner;
import java.util.Random;
public class CatAndMouse
{
public static final int MAX = 10;
public static void main(String args[ ])
{
Scanner mouse = new Scanner(System.in);
Random placement = new Random();
boolean check = true, gameOver = false, win = false, lose = false;
final int row = MAX;
final int col = MAX;
final int page = MAX;
int cheeseX, cheeseY, cheeseZ;
int cheese = 1;
int catX, catY, catZ;
int cat = 2;
int mouseRow;
int mouseCol;
int mousePage;
int mouseMove;
int empty = 0;
int clue = 0;
int clueCount = 0;
int winQuotes;
int loseQuotes;
int [][][]maze = new int [row][col][page];
for(int i = 0; i < MAX; i++)
{
for(int j = 0; j < MAX; j++)
{
for(int k = 0; k < MAX; k++)
{
maze[i][j][k] = empty;
}//page
}//col
}//row
cheeseX = placement.nextInt(row);
cheeseY = placement.nextInt(col);
cheeseZ = placement.nextInt(page);
maze[cheeseX][cheeseY][cheeseZ] = cheese;
for (int i = 0; i < 500; i++)
{
catX = placement.nextInt(row);
catY = placement.nextInt(col);
catZ = placement.nextInt(page);
maze[catX][catY][catZ] = cat;
if ((maze[catX][catY][catZ]) == (maze[cheeseX][cheeseY][cheeseZ]))
{
catX = placement.nextInt(row);
catY = placement.nextInt(col);
catZ = placement.nextInt(page);
maze[catX][catY][catZ] = cat;
}//if place with cheese
}//cat placement loop
System.out.println("Hello there, my name is Q, do you like it? it's short for Q. So you're probably asking yourself \"why am I now a mouse?\"");
System.out.println("The answer is simple, I was bored and you humans are so much fun to play with, but don't worry I can change you back.");
System.out.println("All you have to do is win my little game and you'll be back to your old self again, loose and...well just don't lose.");
System.out.println("In this maze there is a piece of cheese, find it and you win. But be careful now, I added a \'few\' cats to hunt you.");
System.out.println("Can't make this too easy now can we? But don't worry, you'll be given clues if you're close to the cheese or not");
System.out.println("The maze itself is 10*10*10 and to move through it enter an integer between 0-9.");
System.out.println("Now then, let the game begin.");
System.out.println();
do
{
System.out.print("Enter row: ");
mouseRow = mouse.nextInt();
if((mouseRow < 0) || (mouseRow > 9))
{
while (check == true)
{
System.out.print("I said, it needs to be an integer between 0-9. Try again: ");
mouseRow = mouse.nextInt();
if((mouseRow >= 0) && (mouseRow <= 9))
check = false;
}//while closer
}//row check
check = true;
System.out.print("Enter column: ");
mouseCol = mouse.nextInt();
if((mouseCol < 0) || (mouseCol > 9))
{
while (check == true)
{
System.out.print("I said, it needs to be an integer between 0-9. Try again: ");
mouseCol = mouse.nextInt();
if((mouseCol >= 0) && (mouseCol <= 9))
check = false;
}//while closer
}//column check
check = true;
System.out.print("Enter page: ");
mousePage = mouse.nextInt();
if((mousePage < 0) || (mousePage > 9))
{
while (check == true)
{
System.out.print("I said, it needs to be an integer between 0-9. Try again: ");
mousePage = mouse.nextInt();
if((mousePage >= 0) && (mousePage <= 9))
check = false;
}//while closer
}//page check
check = true;
mouseMove = maze[mouseRow][mouseCol][mousePage];
System.out.println();
/*================[Win/Lose]===============*/
if (mouseMove == 2)
{
gameOver = true;
lose = true;
}//loser
if (mouseMove == 1)
{
gameOver = true;
win = true;
}//winner
/*===============[Win/Lose]===============*/
/*=================[Clue]=================*/
if(mouseRow == cheeseX)
{
System.out.println("In same row as cheese!");
}//if same row
else if (mouseRow > cheeseX)
{
for(int i = cheeseX; i <= mouseRow; i++)
{
clueCount++;
}//for loop closer
}//if mouse is larger
else
{
for(int i = mouseRow; i <= cheeseX; i++)
{
clueCount++;
}//for loop closer
}//else cheese is larger
clue = clue + clueCount;
if(mouseCol == cheeseY)
{
System.out.println("In same column as cheese!");
}//if same colum
if (mouseCol > cheeseY)
{
for(int i = cheeseY; i <= mouseCol; i++)
{
clueCount++;
}//for loop closer
}//if mouse is larger
else
{
for(int i = mouseCol; i <= cheeseY; i++)
{
clueCount++;
}//for loop closer
}//else cheese is larger
clue = clue + clueCount;
if(mousePage == cheeseZ)
{
System.out.println("In same page as cheese!");
}//if same page
if (mousePage > cheeseZ)
{
for(int i = cheeseZ; i <= mousePage; i++)
{
clueCount++;
}//for loop closer
}//if mouse is larger
else
{
for(int i = mousePage; i <= cheeseZ; i++)
{
clueCount++;
}//for loop closer
}//else cheese is larger
clue = clue + clueCount;
System.out.println("You are " + clue + " cells away from the cheese.");
System.out.println();
/*=================[Clue]=================*/
}while (gameOver == false);
if (win == true)
{
winQuotes = (int)(3 * Math.random()) + 1;
switch (winQuotes)
{
case 1:
System.out.println("You found the cheese! Now it's time to send you back, but don't worry. I'm sure we'll meet again soon.");
break;
case 2:
System.out.println("An excellent job, maybe you were meant to be a mouse all long. What, change you back? Oh fine.");
break;
default:
System.out.println("Congradulation, I don't think Captian Picard couldn't have done it better. Maybe I should pay him a visit.");
break;
}//win switch
}//if you won
if (lose == true)
{
loseQuotes = (int)(3 * Math.random()) + 1;
switch(loseQuotes)
{
case 1:
System.out.println("Well at least you fed a hungry cat right? Star Fleet would be so proud to have you on one of their ships.");
break;
case 2:
System.out.println("Oh come on, don't tell me you wore a red shirt before I brought you here.");
break;
default:
System.out.println("Maybe I should have brought Captian Janeway here instead, I still owe her for that punch to my face.");
break;
}//lose switch
}//if you lose
}//main closer
} //class closer
You never reinitialize your clue variable to 0 in your do/while loop. So, everytime you run through the loop, instead of setting clue to the current clue value, you keep adding to it (clue = clue + clueCount).
You aren't resetting clue to zero in the big do-while loop
So it's seems logical to me that the clues can't do anything but go higher, because it keep adding the new count to itself (clue = clue + clueCount)
What I am doing is creating a command line "game" where there is a 3x3 grid (Array) where you can move a "1" through it by typing the direction (up, down, left, right).
For example:
0 0 0
0 1 0
0 0 0
I've made it so if the 1 is on the edge of the array it is not allowed to move out of the boundaries (read: resulting in an out of index error).
I'm completely lost as whenever I try to move right, I receiving the following:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at Logic.setMove(Logic.java:87)
at Logic.getMove(Logic.java:10)
at GridGameMain.main(GridGameMain.java:13)
Here's my code:
public class GridGameMain {
static int[][] board = new int[3][3];
public static void main(String[] args){
board[(int) (Math.random() * 2.5)][(int) (Math.random() * 2.5)] = 1;
for (int i =0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(" " + board[j][i]);
}
System.out.println("");
}
Logic l = new Logic();
l.getMove();
}
}
import java.util.Scanner;
public class Logic extends GridGameMain{
void getMove(){ //takes user input then calls setMove
String direction; //string to hold the direction
Scanner user_input = new Scanner(System.in);
direction = user_input.next();
Logic l = new Logic();
l.setMove(direction);
}
void setMove(String direction){ //called when user presses enter upon typing a move
Logic l = new Logic();
if(direction.equals("up")){
if(board[0][0] == 1 || board[1][0] == 1 || board[2][0] == 1 ){
System.out.println("Invalid move!");
l.getMove();
}else{
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a][b-1] = 1;
board[a][b] = 0;
break;
}
}
}
l.printBoard();
System.out.println("you moved up");
l.getMove();
}
}
if(direction.equals("down")){
if(board[0][2] == 1 || board[1][2] == 1 || board[2][2] == 1 ){
System.out.println("Invalid move!");
l.getMove();
}else{
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a][b+1] = 1;
board[a][b] = 0;
break;
}
}
}
l.printBoard();
System.out.println("you moved down");
l.getMove();
}
}
if(direction.equals("left")){
if(board[0][0] == 1 || board[0][1] == 1 || board[0][2] == 1 ){
System.out.println("Invalid move!");
l.getMove();
}else{
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a-1][b] = 1;
board[a][b] = 0;
break;
}
}
}
l.printBoard();
System.out.println("you moved left");
l.getMove();
}
}
if(direction.equals("right")){
if(board[2][0] == 1 || board[2][1] == 1 || board[2][2] == 1 ){
System.out.println("Invalid move!");
l.getMove();
}else{
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a+1][b] = 1;
board[a][b] = 0;
break;
}
}
}
l.printBoard();
System.out.println("you moved right");
l.getMove();
}
}
}
void printBoard(){
for (int i =0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(" " + board[j][i]);
}
System.out.println("");
}
}
}
I'm just not sure why I can't move right when I can move up, down, and left just fine. Please tell me I'm not crazy!
I think the trouble is, you check to make sure the 1 is not on the far right, and then you start shifting things right. That means that, if your 1 was on the column 0, it's moved to column 2, then at the next and last iteration, it's moved to column 3.
Also, are you sure this doesn't happen when you go down?
This doesn't happen going down because, as #Keppil says, you break out of the "rows" (relevant) loop, while going right, you break out of the columns one, which is not what you wanted.
Also, you can use tags to break out of whatever loop you want. Here's how.
The problem is that you are moving the "1" from left to right, so since you break the first for, you don't break the second one, so it keep moving the "1", until it is put outside the array (ArrayIndexOutOfBoundsException).
An example to solve it:
boolean found = false;
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a+1][b] = 1;
board[a][b] = 0;
found = true;
break;
}
if(found){
break;
}
}
}
On your move right:
for(int a = 0; a < 3; a++){
for(int b = 0; b < 3; b++){
if(board[a][b] == 1){
board[a+1][b] = 1; // what if a is 2??
board[a][b] = 0;
break;
}
}
When a is 2, accessing board[a+1][b] is accessing board[3][b]. On a 3*3 board, that's beyond bounds.
Edit: the problem is due to the fact that after you move the 1, you continue the outer loop - but without the initial bounds check. So after the 1 is moved from the central column to the right one, you try to move it again. This only happens on a right move due to the why you loop.
There are two easy solutions:
Use some flag to make sure you break out of the outer loop as well, or better yet -
Change the bounds of the fors according to what you're actually going to check. If you're not going to move a 1 that is on column #2, you can have a loop between 0 and 1. No reason to go up to 2, if you're never going to make it move from that point. Same goes to all other moves - change the appropriate bounds from < 3 to < 2.
The break; inside your for-loops seems to interrupt only the inner for-loop. after breaking the for(int b = 0; b < 3; b++){ .. }, there is no reason for the outer loop to stop.
Your loop finds the 1 at [1][1] and shifts it to the right. then it breaks the inner loop. Nevertheless it calls the inner loop for a=2, where your 1 is now. He tries to shift again.. and fails with exception.
I believe you should be getting an error when you go to the right. The reason is because when you shift one to the right, you break and then you increment a, but you do not check that it went out of bounds again. Once the 'b' loop finishes and then increments 'a' then it will register it as having a value of 1 and move it once more to the right. This keeps going until it is out of bounds. An easy way to correct your code is to just reverse your loops so the outer loop is incrementing 'b' and the inner loop is incrementing 'a'.