Nested for loops don't work correctly - java

I am currently writing a game engine for a game I'm making.
I'm writing a Map Object which uses Cell objects. A Cell is supposed to be a 128x128 area, which is represented by an array. Each int represents a object. However, when I run the following code for Cell generation:
private int[][] cellGen() {
int[][] tempMap = new int[128][128];
for (int x = 0; x < 128; x++) {
int y = 0;
for (y = 0; y < 128; y++) {
tempMap[y][x] = itemGen();
}
}
return tempMap;
}
However, it only generates one line of 128 ints, and doesn't fill the entire array. What am I missing that does this?
Here's itemGen():
private int itemGen(){
switch(biome){
case 0: return (int)(5*Math.random());
case 1: return (int)(5*Math.random())+5;
case 2: return (int)(5*Math.random())+10;
case 3: return (int)(5*Math.random())+15;
case 4: return (int)(5*Math.random())+20;
default: return 100;
}
}
Here's the code I'm checking the entries with:
public class main {
public static void main(String[] args) {
Cell c = new Cell();
System.out.println(Arrays.toString(c.rawCell()));
}
}
Here's the complete code of my Cell class:
import java.util.Arrays;
public class Cell {
private int[][] cell;
private int biome;
public Cell(){
this.cell = cellGen();
this.biome = biomeGen();
}
private int itemGen() {
switch(biome) {
case 0:
return (int)(5*Math.random());
case 1:
return (int)(5*Math.random())+5;
case 2:
return (int)(5*Math.random())+10;
case 3:
return (int)(5*Math.random())+15;
case 4:
return (int)(5*Math.random())+20;
default:
return 100;
}
}
private int biomeGen() {
return (int)(5*Math.random());
}
private int[][] cellGen() {
int[][] tempMap = new int[128][128];
for(int x = 0;x<128;x++) {
for(int y = 0;y<128;y++) {
tempMap[y][x] = itemGen();
}
}
return tempMap;
}
public int[][] rawCell() {
return cell;
}
public String toString(){
return Arrays.toString(cell);
}
}

There are two problems with this loop first you have the condition set incorrectly. x < 127 and y < 127. It should be x < 128 and y < 128 or more generally and correctly x < tempMap.length and y < tempMap[i].length:
private int[][] cellGen(){
int[][] tempMap = new int[128][128];
for(int x = 0;x<tempMap.length;x++){ //loop over rows x is the row number
for(int y = 0;y<tempMap[i].length;y++){ //loop over columns y is the column number
tempMap[x][y] = itemGen();
}
}
return tempMap;
}

for (int x = 0; x < 128; x++) {
for (int y = 0; y < 128; y++) {
tempMap[x][y] = itemGen();
}
}
try this
I am not sure that < 127 was right i think you wanted < 128
Also tempMap[y][x] = itemGen(); seems counter intuitive, unless otherwise needed perhaps you should do tempMap[x][y] = itemGen();
Right now you are filling a whole column before moving to the next column, where as it seems more intuitive to fill a whole row, before moving on to the next row.
Finally it makes sense to move the int y = 0 to inside the for loop like so for (int y = 0; y < 128; y++) as you are recreating y every time x iterates anyways.
otherwise you may do it like so
int x = 0;
int y = 0;
for (x = 0; x < 128; x++) {
for (y = 0; y < 128; y++) {
tempMap[x][y] = itemGen();
}
}
you can say it does not work, but having run this code
int[][] table = new int[128][128];
int x = 0;
int y = 0;
for (x = 0; x < 128; x++) {
for (y = 0; y < 128; y++) {
table[x][y] = 1;
}
}
for (x = 0; x < 128; x++) {
String line = "";
for (y = 0; y < 128; y++) {
line += ", " + table[x][y];
}
out.println(line);
}
I know that it does work.

Your code is working exactly the way you want it to - apart from your Cell.toString() method. If you have a look at that, you call Arrays.toString(int[][] cell), which will of course give you a string representation of the two(!)-dimensional array Cell.cell. Now, what's in a two dimensional array? A bunch of one dimensional arrays! So what your Cell.toString() method (as well as your test code) does is print the addresses of the arrays in Cell.cell, which are of course not at all what you want. You want a matrix representation of Cell.cell, and since Java 1.5, we have Arrays.deepToString(Object[] a) to do that for us. But that'll put all of the string in one line, and you probably want the output string for your square matrix to be square, so you'll have to iterate yourself. Here's code to compare outputs.
import java.util.Arrays;
public class main {
public static void main(String[] args) {
Cell c = new Cell();
int[][] cell = c.rawCell();
System.out.println("Arrays.toString:");
System.out.println(Arrays.toString(cell)); // ugly, ugly object addresses
System.out.println("\n\n");
System.out.println("Arrays.deepToString:");
System.out.println(Arrays.deepToString(cell)); // well this is basically alright, but it's all in one line
System.out.println("\n\n");
//now there's a pretty matrix! look at you, all filled with numbers
System.out.println("Going down the levels by hand:");
for(int i = 0; i < cell.length; i++) {
System.out.print("[");
for(int j = 0; j < cell[i].length; j++) {
System.out.print(cell[i][j]);
if(j != cell[i].length - 1) {
System.out.print(", ");
}
}
System.out.println("]");
}
System.out.println("\n\n\n\n\n\n\n\n");
// if you're dead set on using Arrays.toString(),
// you'll have to go down to the very lowest level by hand
System.out.println("Arrays.toString for each one-dimensional array:");
for(int i = 0; i < cell.length; i++) {
System.out.println(Arrays.toString(cell[i]));
}
}
}
Now this wasn't really a difficult problem to figure out, except that it was way tougher than it should've been. There's a bunch of things you should take away from this:
Post ALL relevant code. That means all code that actually plays
any part in what comes out at your end that doesn't look the way it
should (and certainly the output statements if you see numbers with #
symbols in them, which should make you curious).
Please try not to make people ask multiple times. The very first comment was asking "is that the entire [..] code?" - that should not have to be repeated.
Look at the Javadocs of stuff you're using where you're not entirely, positively sure how they play along with your code if something doesn't work the way it should.
Actually check your output, don't just gloss over it - you will immediately see that there are # symbols in the output, and that never happens with ints.
I hope I'm not sounding too condescending, that is not the intention - to make this site work smoothly, communication is key. To become a better programmer, no one can do without attentiveness regarding their own code.

Related

Why are my arrays returned blank from a method but the code works fine when running in the main-Method?

I'm having following problem with my program.
It's a "connect four" Java console application.
When starting my program, I reset 3 things.
A multi-dimensional char array
public final int rows = 8, columns = 8;
public char[][] board = new char[rows][columns];
I reset it with a for-loop, overwriting every array field with the character '.', which is my default board texture.
public char[][] resetBoard() {
// for loops cycle through every array field
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
board[i][j] = '.';
}
}
return board;
}
An integer-array
public int[] nums = new int[columns];
I reset it with a for-loop using the variable i, since I just need an array with the length of columns, which just counts up from 1. It is used so the user know which column he's choosing. Like in chess "A6" e.g., except without letters.
public int[] resetNums() {
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
return nums;
}
An integer
public int roundCounter = 0;
The integers keeps track of how many rounds there have been in the current game. I want it to be printed while playing.
public int resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
return roundCounter = 0;
}
I reset these looking like this:
gameMain main = new gameMain();
gameMode mode = new gameMode();
gameCheck check = new gameCheck();
main.board = main.resetBoard();
main.nums = main.resetNums();
check.roundCounter = check.resetRoundCounter();
My problem is when printing the game board, the nums-array and the round counter none seem to work.
The game board is just completely blank. The nums-array is only 0's and the round counter stays at 0.
When running the code in the main-method it worked better than running it through classes etc.
My print method:
public void printBoard() {
gameMain main = new gameMain();
gameCheck check = new gameCheck();
// Printing number array with space in between the elements
for (int i = 0; i < main.nums.length; i++) {
System.out.print(main.nums[i] + " ");
}
// Printing the round count next to the number array
System.out.println(" Round " + check.getRoundCounter());
for (int i = 0; i < main.rows; i++) {
for (int j = 0; j < main.columns; j++) {
System.out.print(main.board[i][j] + " ");
}
System.out.println();
}
for (int i = 0; i < main.nums.length; i++) {
System.out.print(main.nums[i] + " ");
}
System.out.println("\n");
}
I could really use some help, since I've been up all night. Originally due to how much fun I was having programming this, now it has become frustrating.
Thanks for reading and thanks in advance!
I think what is happening to you is related to the references of the objects you are using. You are mixing two different ways of working, I give you an example:
You can use the reference of 'roundCounter' and work on it:
public void resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
roundCounter = 0;
}
or you can return it, like this:
public int resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
return 0;
}
In the first case, you will have to call the function like this:
resetRoundCounter(); //this function changes the value of your variable.
In the second case, you will have to call the function like this:
roundCounter = resetRoundCounter();
You can choose the way you like to work but I recomend you not working with global variables especially working with methods. I hope it helps you.
Do it as
public void resetBoard() {
// for loops cycle through every array field
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
board[i][j] = '.';
}
}
}
public void resetNums() {
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
}
public void resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
roundCounter = 0;
}
Finally, call them as follows:
gameMain main = new gameMain();
gameCheck check = new gameCheck();
main.resetBoard();
main.resetNums();
check.resetRoundCounter();
I also recommend you follow Java Naming Convention e.g. gameMain should be GameMain and gameCheck should be GameCheck.

Printing 2d array in app gives blank screen

i made 2d array that contains names and task.
the function give random task to the users.
when i try to print the array that contain the users and the random tasks i get a blank screen.
public String[][] start() {
int[] taken = new int[this.numberOfRowsT()];
String[][] h = new String[numberOfRowsN()][(numberOfRowsT()) / (numberOfRowsN()) + 1];
int a = 1;
int x;
for(int b = 0; b < this.numberOfRowsN(); b++){
h[b][0] = this.getUsersByID(b+1).toString();
}
while (a != this.numberOfRowsT()) {
x = (int) Math.random() * ((this.numberOfRowsT()) + 1);
for (int j = 0; j < taken.length; j++) {
if (x == taken[j]) {
j = -1;
x = (int) Math.random() * ((this.numberOfRowsT()) + 1);
}
}
taken[a] = x; // acceptable num from here
h[((a % this.numberOfRowsN()) + 1)][this.numberOfRowsN() % a] = this.getTaskByID(x).toString();
a++;
}
return h;
}
public void onClick(View v) {
String[][] h = mydb.start();
for (int i = 0; i < mydb.numberOfRowsN(); i++) {
for (int j = 0; j < mydb.numberOfRowsT() /
mydb.numberOfRowsN(); j++)
if (h[i][j] != null)
l.append(h[i][j]);
l.append("\n"); // Append newline after every row
}
}
});
}
Here:
String[][] h = mydb.start();
I guess you want to use that 2D array to collect all the strings to print.
Thing is: you only declare and fill that array.
But it is a local variable, and it goes out of scope as soon as onClick() has run.
Thus: if you want to print things, then you need to do something with the data you collected. Either put into some UI element, or at least log it, or send to System.out.printn() (that of course only works when you have a console, and isn't a viable thing for an Android app).

2D array or matrix from int to string in Java

Ok, so i want to create an integer matrix, say with 9 integers some positive and some negative like
int[][] myMatrix = {{1,5,-2},{7,9,3},{-4,-7,6}}
but i want to declare a String matrix of size 3 x 3. then Iterate through the integer matrix and if the current element has a positive integer put the word POSITIVE in the corresponding element in the String matrix, otherwise put NEGATIVE. my code prints fine when i run the matrix for integers but i'm confused how to write the condition for matrix. I already tried googling but nothing. here's my code:
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
public class 2D_Matrix {
public static void main(String[] args) throws IOException {
int [][] firstMatrix = {{1, 5, -2},{7, 9, 3},{-4 , -7, 6}};
String[][] secondMatrix = new String[3][3];
for (int x = 0; x < 3; ++x) {
for (int y = 0; y < 3; ++y) {
System.out.print(myMatrix[x][y] + "\t");
}
System.out.println();
}
}
}
i tried many different combinations but nothing works or throws errors. for example:
if(x < 0){
System.out.print("Negative");
}
else if(y < 0){
System.out.print("Negative");
}
else
{System.out.print("positive");
}
but it throws error stating y cannot resolve to a variable. Any help would be much appreciated.
I think what you want is
for (int x = 0; x < 3; ++x) {
for (int y = 0; y < 3; ++y) {
if(firstMatrix[x][y] < 0)
secondMatrix[x][y] = "NEGATIVE";
else
secondMatrix[x][y] = "POSITIVE";
}
}
About your validations
if(x < 0){
}
else if(y < 0){
}
else
{
}
You were validating the index, but index of an array can't be negative. According to your request, you want to validate if the value is negative or positive. Refer to my snippet for how to retrieve value and validate them.

Sudoku Algorithm generates 0 values

So I have a sudoku algorithm for a generating a completed game board. The problem is that the algorithm in some instances runs out of possible values to place in the grid, so by default it places a 0.
Here's the code:
public void generateBoard() {
// Determine values for board
int r, d;
// For every slot in grid
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
// Create HashSet with values 1-9
for (int k = 1; k <= 9; k++) {
set.add(k);
}
checkRow(i);
checkCol(j);
checkBox(i, j);
// Create an iterator
Iterator<Integer> iterator = set.iterator();
// Add HashSet values to ArrayList via Iterator
while (iterator.hasNext()) {
d = iterator.next();
values.add(d);
}
try {
// Randomly choose from list of viable values to be put into slot
r = new Random().nextInt(values.size());
slots[i][j] = (Integer) values.get(r);
} catch (Exception e) {
e.printStackTrace();
//resetBoard();
//continue;
}
// Clear HashSet and ArrayList after slot is assigned value
values.clear();
set.clear();
}
}
}
public void checkRow(int i) {
for (int c = 1; c <= 9; c++) {
for (int a = 0; a < 9; a++) {
// If c value is already in row remove from HashSet
if (c == slots[i][a]) {
set.remove(c);
}
}
}
}
public void checkCol(int j) {
for (int c = 1; c <= 9; c++) {
for (int a = 0; a < 9; a++) {
// If c value is already in column remove from HashSet
if (c == slots[a][j]) {
set.remove(c);
}
}
}
}
public void checkBox(int i, int j) {
int xSet = (i - (i % 3));
int ySet = (j - (j % 3));
for (int c = 1; c <= 9; c++) {
for (int x = xSet; x < xSet + 3; x++) {
for (int y = ySet; y < ySet + 3; y++) {
// If c value is already in box remove from HashSet
if (c == slots[x][y]) {
set.remove(c);
}
}
}
}
}
And this is what the generated board looks like: http://imgur.com/2cWh61j
The reason why your algorithm fails is because it's inherently wrong. Generating a Sudoku puzzle is more complicated than that.
A shortcut sometimes used to create a puzzle is to hardcode a few correct puzzles, picking one at random, shuffling the digits (swap all Xs with Ys and vice versa, and so on) shuffling the rows/columns (without moving any number outside its old box) and shuffling the 3x9 and 9x3 areas along the box borders. Doing so will create a puzzle that's TECHNICALLY the same as the original from a mathematical standpoint but should "feel" unique enough to a human.
Also keep in mind that even when you have a complete board, figuring out which tiles you can safely remove without creating an ambiguous puzzle is a bit tricky as well. The naive "remove x tiles at random" solution often fails.
Another question (with some useful answers) about how to create Sudokus can be found here: How to generate Sudoku boards with unique solutions

Putting random numbers randomly into 2d array

I have a 2d array, and I've set all the cells to a enum type State.SAFE. Now I want to place, lets say 5, of those cells, randomly to State.HIT. So I have:
Random objrandom = new Random();
State[][] playField = new State[5][5];
int w;
for (w = 0; w < 5; w++) { // set all states to SAFE first
int h = 0;
playField[w][h] = State.SAFE;
for (h = 0; h < 5; h++) {
playField[w][h] = State.SAFE;
}
}
for (int i = 0; i < 5; i++) { // try and set 5 states, randomly, to HIT
playField[objrandom.nextInt(5)][objrandom.nextInt(5)] = State.HIT;
}
The problem is every time I run it, all the cells are either still in SAFE state or the Hit states are distributed non randomly, i.e the first row of every column or there are more than 5 HIT states.
If you need exactly 5 cells to be set to HIT you can't use random like that because you may get the same number more than once. This is how I would do it:
public static void main(String[] args) {
State[][] playField = new State[5][5];
setStateToSafe(playField);
List<Integer> hits = getRandomIndices(5);
applyHitStateToIndices(hits, playField);
System.out.println(Arrays.deepToString(playField));
}
private static void setStateToSafe(State[][] playField) {
for (int w = 0; w < playField.length; w++) {
Arrays.fill(playField[w], State.SAFE);
}
}
private static List<Integer> getRandomIndices(int n) {
List<Integer> hits = new ArrayList<>();
for (int i = 0; i < n * n; i++) hits.add(i);
Collections.shuffle(hits);
return hits.subList(0, n);
}
private static void applyHitStateToIndices(List<Integer> hits, State[][] playField) {
for (int i = 0; i < hits.size(); i++) {
int hitIndex = hits.get(i);
int row = hitIndex / playField.length;
int column = hitIndex % playField.length;
playField[row][column] = State.HIT;
}
}
There's a problem with your solution, since the line playField[objrandom.nextInt(5)][objrandom.nextInt(5)]=... might result in the same cell being references twice. I can't be sure if this is the cause of your problem, but it might be at least part of it.
If you wanted to fix that, you'd have to check each random number against the history of already changed cells, and request for a different random in case of double hits.
What I suggest is a completely different approach. Instead of requesting the indices of the row and column of the cell in which to change the value, the random should represent the probability that the values will change.
In other words:
Go over all the cells in the array, generate a random value between 0 and 1 (using nextDouble())
If the value is below the probability that this cell should change (5 cells out of 25 means 5/25 = 0.2 probability = 20%), if so, set the value to State.HIT, otherwise set it to State.SAFE
The code should look something like this:
Random objrandom = new Random();
State[][] playField = new State[5][5];
for (int w = 0; w < 5; w++) {
for (int h = 0; h < 5; h++) {
playField[w][h] = (objrandom.nextDouble() < 0.2d) ? State.HIT : State.SAFE;
}
}
If the small overhead doesn't cause much trouble, then you could do something like this:
Create a class for representing a point on your field.
final class Point {
public final int x;
public final int y;
public Point(final int x, final int y) {
this.x = x;
this.y = y;
}
}
Fill a list with all the possible points, and shuffle it.
List<Point> points = new ArrayList<>();
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
points.add(new Point(x, y));
}
}
Collections.shuffle(points);
Now the first N (5 in your case) points will be randomized, and 100% not the same.
for (int i = 0; i < 5; i++) {
Point p = points.get(i);
playField[p.x][p.y] = State.HIT;
}

Categories

Resources