Hi just attempted a TicTacToe project and was stuck about an error. My error has to do with checking for win solutions specifically diagonals.
What I need:
Create nested loop to loop down the array diagonally, then incrementing it so it would scan diagonally under or to the size until eventually scanning the entire array.
What I did:
I tried to make a nested for loop that would loop through the rows and add the to the counter until the end of the row then check if the counter was equal to the inline (amount in a row needed to win). I believe it works for the rows and columns.
Problem:
But for diagonals, I get an array out of bounds exception and I think it's because my a or b is added to i which could be gameBoard[3][4] when speaking of a 3x3 game board.
Attempt to solve:
I attempted a solution which you can see is the oddly placed for loop with j. So that i would only go to j and not go past the array limits.
I'm wondering if the logic behind this would work?
Sorry if the code is messy especially with the added for loops contain j
/*
* Method winner will determine if the symbol (X or O) wins
*
* #param symbol will be either X or O
* #return will return true if the symbol has won from any of the methods
*/
public boolean winner(char symbol) {
int counter = 0;
/* Scan from ROWS for any symbols inline to win */
for (int i = 0; i < gameBoard.length; i++) { // loop through the rows
for (int j = 0; j < gameBoard.length; j++) { // Loop through the columns
if (gameBoard[i][j] == symbol) {
counter++;
}
if (gameBoard[i][j] != symbol) { // If the next one in the row is not equal then reset counter to 0
counter = 0;
}
if (counter == inline) { // Counter will only equal inline if there is amount of inliine in a row
return true;
}
}
}
/* Scan and search for winning conditions in COLUMNS */
for (int i = 0; i < gameBoard.length; i++) { // loop through the rows
for (int j = 0; j < gameBoard.length; j++) { // Loop through the columns
if (gameBoard[j][i] == symbol) {
counter++;
}
if (gameBoard[j][i] != symbol) { // Reset counter to 0 if not equal to symbol
counter = 0;
}
if (counter == inline) { // If counter reached amount of inline then it must have had amount of inline in a row to win
return true;
}
}
}
/* Scan for RIGHT DIAGONALS for winning conditions */
// a shifts the position of diagonal to the right by one
// after diagonally looping through the board
for (int a = 0; a < gameBoard.length; a++) {
// i loops diagonally through the board
for (int j = gameBoard.length; j < 0; j--) {
for (int i = 0; i < j; i++) {
if (gameBoard[i][i + a] == symbol) {
counter++;
}
if (gameBoard[i][i + a] != symbol) {
counter = 0;
}
if (counter == inline) {
return true;
}
}
}
}
// b shifts the position of the diagonal down by one
for (int b = 1; b < gameBoard.length; b++) {
for (int j = gameBoard.length - 1; j < 0; j--)
// i loops diagonally through the board
for (int i = 0; i < j; i++) {
if (gameBoard[i + b][i] == symbol) {
counter++;
}
if (gameBoard[i + b][i] != symbol) {
counter = 0;
}
if (counter == inline) {
return true;
}
}
}
/* Scan for LEFT DIAGONALS for winning conditions */
// a shifts the position of diagonal to the left by one
for (int a = gameBoard.length; a >= 0; a--) {
for (int j = gameBoard.length; j < 0; j--) {
// i loops diagonally through the board
for (int i = 0; i < j; i++) {
if (gameBoard[i][a - i] == symbol) {
counter++;
}
if (gameBoard[i][a - i] != symbol) {
counter = 0;
}
if (counter == inline) {
return true;
}
}
}
}
// b shifts the position of the diagonal down by one
for (int b = 0; b < gameBoard.length; b++) {
for (int j = gameBoard.length - 1; j < 0; j--) {
// i loops diagonally in the left direction of through the board
for (int i = 0; i < j; i++) {
if (gameBoard[i + b][gameBoard.length - i] == symbol) {
counter++;
}
if (gameBoard[i + b][gameBoard.length - i] != symbol) {
counter = 0;
}
if (counter == inline) {
return true;
}
}
}
}
return false; // If it reaches here then no one has won yet and the game is ongoing
}
As far as i see in your code you must get Array Index Out Of Bounds Exception. I assume you try to implement classic tic-tac-toe, so we are dealing with 3x3 matrix. Here is how your game board is indexed:
[0.0] [1.0] [2.0]
[0.1] [1.1] [2.1]
[0.2] [1.2] [2.2]
So this is what happens in your loop with Right Diagonals:
int a increments 0 --> 2
int j decrements 2 --> 0
int i increments 0 --> 2
So your loop goes like this:
[0.0+0] --> i++ [1.1+0] --> i++ [2.2+0] j--
[0.0+0] --> i++ [1.1+0] j--
[0.0+0] a++
[0.0+1] --> i++ [1.1+1] --> i++ [2.2+1] j-- <--Here you get out of Array.
Additionally after checking through main diagonal, you go through [0.0] [1.1] which is not diagonal at all and you already did this in loops for rows. Even shifting through bottom diagonal is not needed ([0.1][1.2]) as you already did this in loops before. So checking through [0.0] [1.1] [2.2] will do work for you.
I believe that this is ineffective way to check for win condition. You can get rid of 3 loops, just by storing position of found element.
Sorry couldn't get the format for the comments so I'll post what I got here
/* Scan for RIGHT DIAGONALS for winning conditions */
int j = gameBoard.length
for (int a = 0; a < gameBoard.length; a++) {
// i loops diagonally through the board
for (int i = 0; i < j; i++) {
if (gameBoard[i][i + a] == symbol) {
counter++;
}
if (gameBoard[i][i + a] != symbol) {
counter = 0;
}
if (counter == inline) {
return true;
}
} j--; // Incrementing after the i for loop.
}
output:
a:0 i:0 j:3
[0.0+0] --> i++ [1.1+0] --> i++ [2.2+0] /*end for loop. i:2 j:3 a: 0 */
j-- a++
[0.0+1] --> i++ [1.1+1] /*end for loop. i:1 j:2 a: 1*/
j-- a++
[0.0+2] /* end for loop. i:0 j: 1 a:2 */
and the array stays in bounds while checking the diagonals. So I think think can work on a larger scale.
Related
How do I stop the loop if the number reaches the n? i tried the break; but the loop still doesn't stop.
Scanner in = new Scanner(System.in);
int i, j;
int n = in.nextInt();
int number = 1;
for(i = 1; i <= n; ++i) {
for(j = 1; j <= i; ++j) {
System.out.print(number);
++number;
if(number >= n){
break;
}
}
System.out.println();
}
input: 9
expected output:
1
23
456
789
or
input: 12
expected output:
1
23
456
78910
1112
Break and Labeled break should be avoided in code. So you can use loops as below:
public static void main(final String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Please enter input number:");
int n = in.nextInt();
System.out.println("You have entered : " + n);
for (int i = 1, k = 1; k <= n; i++) {
for (int j = 0; j < i && k <= n; j++, k++) {
System.out.print(k);
}
System.out.println();
}
}
Printing k variable which is initialized in outer and updated in inner loop.
Putting condition to break inner and outer loop to check k with input variable
EDITED : To understand it better:
i variable is used to maintain the number of rows we need to print.
j variable is used to maintain the number to elements to print in each row.
In most of placed the value which is being print is in context with either row number or element number in row, but here print value is not in sync with it, so we are maintaining it in 2rd variable k.
Use the labeled break statement and you can break from the nested loop:
loop:
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= i; ++j)
{
System.out.print(number);
++number;
if (number > n) //not (number >= n)
{
break loop;
}
}
System.out.println();
}
There are many ways of doing this. The most straightforward one is to use a label to break out of several loops at once:
outer: for(i = 1; i <= n; ++i) { // a label is a word followed by :
inner: for(j = 1; j <= i; ++j) { // you can declare labels without using them
System.out.print(number);
++number;
if(number >= n){
break outer; // break inner would be equivalent to what you had
}
}
System.out.println();
}
However, these break statements with labels look suspiciously similar to gotos, and gotos are frowned upon. A more teacher-friendly version would be to use a boolean flag, and check the flag in each loop:
boolean finished = false;
for(i = 1; i <= n && ! finished; ++i) {
for(j = 1; j <= i && ! finished; ++j) {
System.out.print(number);
++number;
if (number >= n) {
finished = true; // no need to break - loops condition will now be false
}
}
System.out.println();
}
Note that this introduces an extra newline, which you generally want to make sure that whatever you print next appears on a different line.
Another option is to simply complicate your initial condition, without any flags:
for(i = 1; i <= n && number < n; ++i) {
for(j = 1; j <= i; ++j) {
System.out.print(number);
++number;
}
System.out.println();
}
I would recommend, for readability purposes, version 2. Additionally, I would write it as follows:
boolean finished = false;
for(int i = 0; i < n && ! finished; ++i) {
for(j = 0; j < i && ! finished; ++j) {
System.out.print(number++);
if (number >= n) {
finished = true;
}
}
System.out.println();
}
The key differences are using 0 to n-1 counting to repeat something n times (most programmers are very accustomed to that, instead of counting from 1 to n), and defining loop variables within the for, so that trying to use them outside of their loops is an error. This helps to avoid accidental reuse of variables.
import java.util.Scanner;
public class Tester{
public static void main(String []args){
Scanner in = new Scanner(System.in);
int i, j;
int n = in.nextInt();
int number = 1;
loop:
for ( i = 1; i <= n; ++i){
for ( j = 1; j <= i; ++j){
System.out.print(number);
++number;
if (number > n)
{
break loop;
}
}
System.out.println();
}
}
}
by using a for loop with a nested one you can achieve it like this:
you have a row which is incremented by 1 on each row (line)
you have a column variable which is increasing by one on each line or row
you have a number with start to print from 1 till the inputed number for example it was entered 12.
in inner loop you need to check the column be less or equal to row and the incremented number be less the entered number.
Scanner in = new Scanner(System.in);
System.out.print("Enter a Number: ");
int n = in.nextInt();
int number = 1;
for (int row = 1; row <= n && number <= n; row++) {
for (int column = 1; column <= row && number <= n; column++) {
System.out.print((number++) + " ");
}
System.out.println();
}
This is supposed to prevent ship edges from touching other ships, but for some reason it doesn't work. Specially for my T shaped ship.
I think this has to do with the condition in the for loops, probably the boat.getLength()+1 is not enough there, but i don't know what else to try.
My mainBoard length is 10x10 and the line and col parameters are supposed to be what we get from the user scanner. My board in its natural state is initialized with character '~'. Each boat when its positioned successfully it changes the '~' with the character appointed to that specific boat.
public boolean validateSurrounding(Boat boat, int line, int col) {
int i = line;
int j = col;
for (i = i - 1; i < boat.getLength()+1; i++) {
for (j = j - 1; j < boat.getLength()+1; j++) {
if (i < 0 || i >= mainBoard.length || j < 0 || j >= mainBoard[0].length) {
continue;
}
if (mainBoard[i][j] != '~') {
return false;
}
}
}
return true;
}
You are damaging your inner loop starting condition.
int i = line;
int j = col;
for (i = i - 1; i < boat.getLength()+1; i++) {
for (j = j - 1; j < boat.getLength()+1; j++) {
The second iteration of the outer loop, j will start at boat.getLength()+1, which is the last value it had during the outer loop's first execution.
Instead, use:
int i;
int j;
for (i = line - 1; i < boat.getLength()+1; i++) {
for (j = col - 1; j < boat.getLength()+1; j++) {
The duty of this method is to increment or add 1 to, the largest element in the array arr. If the same largest element is present more than once in the array, the last occurrence should be incremented. ("Last" means the one in the row with the largest subscript, and the one with the largest column subscript if there is more than one occurrence of the largest element in that row.) The method should not do any unnecessary work or computation. Note that the array's rows may have different numbers of elements.
Solution:
public static void incrMax(int[][] arr) {
int maxRow = 0;
int maxCol = 0;
boolean found = false;
for(int row = 0; row < arr.length; row++) {
for(int col = 0; col < arr[row].length; col++) {
if(!found || arr[row][col] >= arr[maxRow][maxCol] {
maxRow = row;
maxCol = col;
found = true;
}
if(found) {
arr[maxRow][maxCol] += 1;
}
}
}
}
What I understand is that we would want to create two int's to store the maximum elements for horizontal rows and vertical columns. In order to seek those values out we need to loop the 2D-array. I am particularly confused by nested for-loops and 2d arrays. And the line:
if(!found || arr[row][col] >= arr[maxRow][maxCol]
Can someone please walk through the logic of this code?
Thank you
void increment(int[][] mat) {
//increment the max of every row by one
for (int i = 0; i < mat.length; i++) {
int maxRow = 0, maxIndex = -1;
for (int j = 0; j < mat[i].length; j++) {
if (maxRow <= mat[i][j]) { // to allow multiple occurences of the same value i used <=
maxRow = mat[i][j];
maxIndex = j;
}
}
//we check if a max is found
if (maxIndex != -1) {
mat[i][maxIndex]++;
}
}
}
this will do the work you are asking for
I have game of life exercise, I wrote the whole game only remains for me to write the function that checks the cell and decides whether he lives or dies.
the code:
public class lifeGame1 {
public static void main(String[]args){
gameOfLife(4, 5, 0.3);
}
public static void gameOfLife(int n, int m, double p){
int[][] matrix = new int[n][n];
// Random each matrix[i][j]
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(Math.random() < p)
matrix[i][j] = 1;
else
matrix[i][j] = 0;
} // for j
} // for i
System.out.println("The board is: ");
printMatrix(matrix);
int steps = 0;
while(steps < m){
int[][] newMatrix = new int[n][n];
for(int i = 0; i < newMatrix.length; i++){
for(int j = 0; j < newMatrix[i].length; j++){
newMatrix[i][j] = checkTheNewValueOfCell(matrix, i, j);
}
}
matrix = newMatrix;
System.out.println("The new board: ");
printMatrix(matrix);
steps++;
} // while
}
public static void printMatrix(int[][] matrix){
// Random each matrix[i][j]
for(int i = 0; i < matrix.length; i++){ // for each row
for(int j = 0; j < matrix[i].length; j++){ // print one row
System.out.print(matrix[i][j] + " ");
} // for j
System.out.println();
} // for i
}
}
Cell can make the dead or make a life according to the following rules:
1. Live cell can become dead as a result of:
A. If it has a density of more than three live neighbors.
B. Solitude if it has fewer than two live neighbors.
Hence the cell life continues to be my life if and only if it has two or three live neighbors.
2 dead cell can turn the cheek if it has exactly three live neighbors.
While the volume chamber has five neighbors) if Angular three (but also for work the same rules.
Code that checks the cell:
private static int checkTheNewValueOfCell(int[][] matrix, int i, int j) {
// check how much active neighbors
int countActiveNeighbors = 0;
for(int k = i-1; k <= i+1; k++){
for(int m = j-1; m <= j+1; m++){
if(k >= 0 && k < matrix.length && m >= 0 && m < matrix[0].length){ // אם בתחום
if(k != i || m != j)
if(matrix[k][m] == 1)
countActiveNeighbors++;
} // if
} // for m
} // for k
if(matrix[i][j] == 1){ // pail
if(countActiveNeighbors == 2 || countActiveNeighbors == 3)
return 1;
else
return 0;
}else{ // savil
if(countActiveNeighbors == 3)
return 1;
else
return 0;
}
}
I was helped by a lecturer who register their function and indeed work, but I did not realize it until the end and it's really important for me to understand it.
I do not understand the loop Four run from i-1 to i + 1 and the loop Four which run from j-1 to j + 1.
If I am in the first cell so I should get an error that the i-1 is equal to -1 and it is beyond the scope of the array does not it?
Can help writing a simple function so we can understand it better?
thank's
You get an ArrayIndexOutOfBoundsException only when you try to ACCESS an non-valid array index. But in the nested for loops, you have the following if statements:
if(k >= 0 && k < matrix.length && m >= 0 && m < matrix[0].length){ // אם בתחום
if(k != i || m != j)
if(matrix[k][m] == 1)
countActiveNeighbors++;
} // if
the top if tests that k and m are within the matrix (they are both positive and less than the length/width of the matrix). The bottom if then actually accesses the array at index k,m. Since you check for valid indices before you access, you won't get an Exception
I've commented the function to try and make it clearer. Paired with my comment hopefully it helps you understand!
private static int checkTheNewValueOfCell(int[][] matrix, int i, int j) {
// check how much active neighbors
int countActiveNeighbors = 0; // Neighbor count starts at 0
for(int k = i-1; k <= i+1; k++){ // Loop from 1 before the cell to 1 after the cell
for(int m = j-1; m <= j+1; m++){ // Loop from 1 above the cell to 1 below it
if(k >= 0 && k < matrix.length && m >= 0 && m < matrix[0].length){ // אם בתחום // This if statement skips out of bounds in case we are on an edge cell
if(k != i || m != j) // This if statement skips the current cell we are looking at
if(matrix[k][m] == 1)
countActiveNeighbors++; // Finally we increment if we find a neighbor cell
} // if
} // for m
} // for k
I am trying to traverse a 2D array, first printing out a random array of 0s and 1s and then looping through that same array to change the 0s to 2s showing the path that is being taken to get from the top to the bottom. It compiles, but I can't quite figure out to get it to change the variables without forgetting about the random array. I tried using another set of for loops, which probably isn't the right way to do it...
Here is what I have come up with.
import java.util.*;
public class SearchMaze{
//Variables to set the values of the 2 arrays
private static int n = 8;
private static int m = 7;
private static int[][] maze = new int[n][m];
private static int i = 0;
private static int j = 0;
public static void main(String [] args){
//Randomly select 0s and 1s for the array
Random rand = new Random();
System.out.print(n + "\t" + m);
System.out.println("");
//creates the random array of 0s and 1s
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
maze[i][j] = rand.nextInt(2);
System.out.print(maze[i][j]);
}System.out.println("");
}
//here I was trying to loop through the array again while changing the 0s to 1s
//to show if a "path" from the top to the bottom exists
//but in doing this I am really just creating a different array of random 0s and 1s..
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
maze[i][j] = rand.nextInt(2);
while(i < n - 1 && j < m - 1){
if(maze[i+1][j] == 0)
{
maze[i+1][j] = 2;
i++;
}
else if(maze[i-1][j] == 0)
{
maze[i-1][j] = 2;
i++;
}
else if(maze[i][j+1] == 0)
{
maze[i][j+1] = 2;
j++;
}
else if(maze[i][j-1] == 0)
{
maze[i][j-1] = 2;
j++;
}
else
{
maze[i][j] = 1;
}
System.out.print(maze[i][j]);
}System.out.println();
}//end second for loop
}//end first for loop
}//end main method
}//end searchmaze
It will either change a few of the numbers at the bottom to 2s, just throw an error or generate an enormous amount of 1s without stopping.
Some of the errors I have come across...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at SearchMaze.main(SearchMaze.java:52)
Exception in thread "main"java.lang.ArrayIndexOutOfBoundsException: -1
at SearchMaze.main(SearchMaze.java:42)
I think this is what you need.
import java.util.*;
public class SearchMaze{
//Variables to set the values of the 2 arrays
private static int n = 8;
private static int m = 7;
private static int[][] maze = new int[n][m];
private static int i = 0;
private static int j = 0;
/*
* This function is used for searching a way from top to bottom exist or not.
*/
public static boolean searchMaze(int maze[][], int i, int j, int n, int m) {
if(i == n-1 && j > 0 && j < m && maze[i][j] == 0) {
// This is the condition when there is a way to the bottom.
return true;
} else if(i < 0 || i > m-1 || j < 0 || j > m-1 || maze[i][j] == 1) {
// This is the condition when path is end in some where in middle.
return false;
} else {
// There is three way to go bottom
return searchMaze(maze, i+1, j-1, n, m) || searchMaze(maze, i+1, j, n, m) || searchMaze(maze, i+1, j+1, n, m);
}
}
public static void main(String [] args){
//Randomly select 0s and 1s for the array
Random rand = new Random();
System.out.print(n + "\t" + m);
System.out.println("");
//creates the random array of 0s and 1s
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
maze[i][j] = rand.nextInt(2);
System.out.print(maze[i][j]);
}
System.out.println("");
}
//here I was trying to loop through the array again while changing the 0s to 1s
//to show if a "path" from the top to the bottom exists
//but in doing this I am really just creating a different array of random 0s and 1s..
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
// This is used to search a path from i,j to the bottom.
if(searchMaze(maze, i, j, n, m)) {
System.out.println("There is a way from "+i+" & "+j);
}
}//end second for loop
}//end first for loop
}//end main method
}//end searchmaze