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;
}
Related
Hi i am new at java coding and am trying to create random numbers(which i have done) and i am trying to assign this random numbers as coordinates into the 2D array and print 'A' at the coordinates. Any help is appreciated.
package training;
import java.util.Random;
public class Training {
public static void main(String[] args) {
char[][] values = new char[10][10];
int foodX[] = new int[15];
for (int i = 1; i < foodX.length + 1; i++) {
int minFood = 0;
int maxFood = 10;
int randNum1 = minFood + (int) (Math.random() * (maxFood - minFood) + 1);
int minFoodY = 0;
int maxFoodY = 10;
int randNum2 = minFoodY + (int) (Math.random() * (maxFoodY - minFoodY) + 1);
for (int j = 1; j < foodX.length + 1; j++) {
values[randNum1][randNum2] = 'A';
}
}
// Assign three elements within it.
// Loop over top-level arrays.
for (int i = 0; i < values.length; i++) {
// Loop and display sub-arrays.
char[] sub = values[i];
for (int x = 0; x < sub.length; x++) {
System.out.print(sub[x] + " ");
}
System.out.println();
}
}
}
Arrays in Java are zero-indexed. What this means is that if you declare an array myArray as follows:
final int[] myArray = new int[10];
then you are creating a 10-element array which contains values in myArray[0], myArray[1], ..., myArray[9]. This also holds true for two-dimensional arrays, such as the values array in your code. However, you have defined randNum1 and randNum2 to return values in the range 1 to 10. When either of those values is set to 10, then values[randNum1][randNum2] will throw an ArrayIndexOutOfBoundsException, because you are trying to reference the array using indices that are out of its range.
In addition to this, you have created an array, foodX, which you do nothing with beyond determining its length. It's better in this case to declare an constant int value for this purpose. Finally, although you have imported the java.util.Random class, you are using Math.random() to generate random variables, which doesn't rely on this. You could alternatively use Random.nextDouble(), which would be useful if using a random number seed, but that's an aside.
Without following any additional considerations and to get your output simply to work as I believe is intended, I would therefore re-write your class in the following way:
package training;
public class Training {
public static void main(String[] args) {
char[][] values = new char[10][10];
int foodSize = 15
for (int i = 1; i <= foodSize; i++) {
int minFood = 0;
int maxFood = 10;
int randNum1 = minFood + (int) (Math.random() * (maxFood - minFood));
int minFoodY = 0;
int maxFoodY = 10;
int randNum2 = minFoodY + (int) (Math.random() * (maxFoodY - minFoodY));
values[randNum1][randNum2] = 'A';
// I've removed the for loop in the line above since it simply does the same thing 15 times and is inefficient
}
// Assign three elements within it.
// Loop over top-level arrays.
for (int i = 0; i < values.length; i++) {
// Loop and display sub-arrays.
char[] sub = values[i];
for (int x = 0; x < sub.length; x++) {
System.out.print(sub[x] + " ");
}
System.out.println();
}
}
}
I had to do a program that would generate 30 graphs in total, with 5 having 10 unique edges, 5 having 20 unique edges, etc up to 60. I then had to take the average amount of components across in each of the 5 graphs. However, my program is hanging consistently in the same spot. It is when it is trying to do the 16th graph and the 11th edge that it fails, all the time. I left out the connected components static method since that is irrelevant to the problem, I believe. Note this is a rough draft of an earlier optimized copy, both get hung at the same place.
First, I make one graph with the 26 vertices required and then put that same graph into each of the 30 spots in the array and then I put the unique edges into each graph.
The edgeIs method and the indexIs method are in the graph ADT I am using.
Here is the code:
import ch05.queues.LinkedUnbndQueue;
import ch05.queues.UnboundedQueueInterface;
import java.util.Random;
public class UniqueEdgeGraph2 {
public static void main (String[] args) {
final int numGraphs2 = 5;
int numEdges = 10;
double sum = 0;
int index = 0;
Random rand = new Random();
int randomNum1 = 0, randomNum2 = 0, flag = 0;
UnweightedGraph<Integer>[] graphArray = (UnweightedGraph<Integer>[]) new UnweightedGraph[30];
UnweightedGraph<Integer> graph;
for (int i = 0; i < 30; i++)
graphArray[i] = new UnweightedGraph<Integer>();
for (int i = 0; i < 30; i++)
for (int j = 0; j < 26; j++)
graphArray[i].addVertex(j);
for (int i = 0; i < 6; i++) { // it is done 6 times because 30 graphs are needed in total and numGraphs is 5
for (int j = 0; j < numGraphs2; j++) {
for (int k = 0; k < numEdges; k++) {
while (flag == 0) {
randomNum1 = rand.nextInt(26);
randomNum2 = rand.nextInt(26);
if (graphArray[index].edgeIs(randomNum1, randomNum2) == false) {
graphArray[index].addEdge(randomNum1, randomNum2);
flag = 1;
}
}
flag = 0;
}
sum += CountConnectedComponents(graphArray[index]);
index++;
}
System.out.println("Average # of Connected Components for five graphs with " + numEdges + " unique edges is: "
+ sum/5.0);
sum = 0;
numEdges += 10;
}
}
public boolean edgeIs(T fromVertex, T toVertex)
// If edge from fromVertex to toVertex exists, returns true
// otherwise, returns false.
{
int row;
int column;
row = indexIs(fromVertex);
column = indexIs(toVertex);
return (edges[row][column]);
}
private int indexIs(T vertex)
// Returns the index of vertex in vertices.
{
int index = 0;
while (!vertex.equals(vertices[index]))
index++;
return index;
}
I figured out what the error was. I was pointing to the same graph for all 30 array indices. So instead of making 30 different graphs, I pointed the entire array to one graph. This made it impossible to eventually find a unique edge to put in, which caused an infinite loop instead of it just hanging like I thought it was.
I edited the code to reflect the changes I made to make it work. It is still in rough shape but it just needs to be cleaned up.
Thanks to everybody who commented.
I am trying to fill an array with random int values from 0 to 6. To control my code i am printing out the random values I generate. I try to exclude duplicates in the nested if-statement inside the for-loop, but when I run the code I get my seven values, but some of them are still duplicated. Can someone please help me?
Here is my code:
import java.util.Random;
public class TesterArrayer
{
public static void main(String[] args)
{
int size = 7;
Random randomNumber = new Random();
int randomArray[] = new int[size];
for(int x =0; x < size; x++)
{
int randomValue = randomNumber.nextInt(6);
if (randomValue != randomArray[x])
{
randomArray[x] = randomValue;
}
}//End for-loop
for (int y = 0; y < size; y++)
{
System.out.println(randomArray[y]);
}
}
}
public static void main(String[] args) {
int size = 7;
boolean add = true;
int counter = 0;
Random randomNumber = new Random();
int randomArray[] = new int[size];
for(int j = 0; j < size; j++)
{
randomArray[j] = -1;
}
while (counter < size) {
add = true;
int randomValue = randomNumber.nextInt(7);
for (int x = 0; x < size; x++) {
if (randomValue == randomArray[x]) {
add = false;
}
}// End for-loop
if(add)
{
randomArray[counter] = randomValue;
counter++;
}
}
for (int y = 0; y < size; y++) {
System.out.println(randomArray[y]);
}
}
Try something like this. You don't want to add the number unless it's not already in the list. Also for your random you need 7 instead of 6 if you want 0-6.
This code will fill your array with 0-6 not repeating any numbers.
If you only want the numbers 0..length-1 in random order you can do something like this:
int length = 7;
List<Integer> list = new ArrayList<>(length);
for(int i=0; i<length; i++){
list.add(Integer.valueOf(i));
}
//list is now in order, need to randomly shuffle it
Collections.shuffle(list);
//now list is shuffled, convert to array
int array[] = new int[length];
for(int i=0; i<length; i++){
array[i] = list.get(i);
}
Change minLimit, maxLimit and noOfItems to get random Numbers
public class RandomIntegers
{
public static final Random random = new Random();
public static final int maxLimit = 6;
public static final int minLimit = 0;
public static final int noOfItems = 7;
public static void main( String[] args )
{
Set<Integer> uniqueRandomIntegerSet = new HashSet< Integer >();
while(uniqueRandomIntegerSet.size() < noOfItems)
uniqueRandomIntegerSet.add( random.nextInt( maxLimit - minLimit + 1 ) + minLimit );
Integer[] randomUniqueIntegers = uniqueRandomIntegerSet.toArray( new Integer[0] );
}
}
As you should use a more optimal data structure for this approach, as mentioned in the other answer and comments, you can still accomplish this with an array of course. As you have defined the problem you would need to change int randomValue = randomNumber.nextInt(6); to int randomValue = randomNumber.nextInt(7); or else this will loop infinitely as there is no possible way to have no duplicates in a size 7 array with only 6 values.
You can do something like this to modify your code for it to work:
boolean flag = false;
for(int x = 0; x < size; x++)
{
int randomValue = randomNumber.nextInt(7);
for (int i = 0; i < x; i++)
{
if (randomValue == randomArray[i])
{
//randomArray[x] = randomValue;
flag = true;
x--;
}
}
if (!flag)
randomArray[x] = randomValue;
flag = false;
}//End for-loop
This code is simply flagging when it sees a duplicate value in the array already and will skip this value and decrement the x value so that it will create another random value for this spot in the array.
byte[] source = new byte[1024];
Random rand = new Random();
rand.nextBytes(source);
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.
In my 2D Tiled game, I have a problem, when I update all the Object from a 2D array in a for loop inside another (looping in the 2D array from top left to bottom right, row by row(like the code below)), If the program is looping at index (5,6) and it need data from the Object under itself, It'll use the new data that he have executed when the loop is at (5,5) but I want to use the all data before the start of the double for loop...
A basical example:
int[][] map = new int[10][10];
for(int x = 0; x < 10; x++)
{
for(int y = 0; y < 10; y++)
{
update(x, y, map);
}
}
// I remember you that it is an example
void update(int x, int y, int[][] m)
{
m[x][y] = 0
if(y > 9) { return; }
m[x][y + 1] = 1
}
It will put instantly the data "1" at (x, 10), without considering that it generate errors...(ArrayOutOfBoundsException...)
How I can make it use the data of the array when he don't started the double loop yet?
I know that it generata ArrayOutOfBoundExecption, and with a single if I can correct it like I done up here
int Water = 1;
int Air = 0;
int[][] map = new int[20][20];
void update()
{
for(int x = 0; x < 10; x++)
{
for(int y = 0; y < 10; y++)
{
tick(x, y, map);
}
}
}
void tick(int x, int y, int[][] m)
{
if(y > m.lenght - 1) { return; }
m[x][y] = Air;
m[x][y + 1] = Water;
}
You are saying that you are iterating your map row by row when you are actually doing it by columns. Try looping first for y and then for x.
Your update method is also wrong. y+1 when y = 9 will try to access map[x][10] which will throw an ArrayOutOfBoundsException. Remember than an array declared as new int[10] has 10 items starting from 0 and ending at position 9.
int Water = 1;
int Air = 0;
int[][] map = new int[20][20];
void update()
{
for(int x = 0; x < 10; x++)
{
for(int y = 9; y >= 0; y--)
{
tick(x, y, map);
}
}
}
void tick(int x, int y, int[][] m)
{
if (y < m[0].length - 1)
m[x][y+1] = m[x][y];
}
Of course, you'll need to make some cells water to begin with, but that should go in the constructor.