I use this method to get a random location outside the screen to spawn all the zombies on.
public void initZombie(){
for(int i = 0; i < 100; i++){
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomYSpawn = (int) Math.random() * -100 + 800;
int[][] spawn = {{randomXSpawn,randomYSpawn}};
for(int j = 0; j < spawn.length; j++){
zombie.add(new Zombie(spawn[j][0],spawn[j][1]));
}
}
}
The problem that I am having with this is that the two ints that gets the random location only run once so therefor every single zombie spawns at the exact same place inside of each other. How would I be able to get the ints to run multiple times so that the zombies spawn at different locations? I have tried to put them inside of the run() method instead and then they run two times so that the first zombie spawns in one location and then the 99 other zombies spawn at another location inside of each other.
You are casting Math.random() to an integer which floors the value. Since Math.random() generates a double that is 0 <= x < 1, it will always be rounded to 0. That is why you are getting the exact same spawn position.
You need to add parenthesis to your cast:
int randomXSpawn = (int) (Math.random() * -300 + -50);
int randomYSpawn = (int) (Math.random() * -100 + 800);
If I were you, I'd use the Random object, and I'd call the nextInt function
Random rnd = new Random();
for(...)
{
int randInt = rnd.nextInt(300) //300 is the maximum
}
You don't index your spawn array. Actually I don't think you even need one. Try this
public void initZombie(int maxZombies){
Random r=new Random();
for(int i = 0; i < maxZombies; i++){
zombie.add(new Zombie(r.nextInt(MAX_X), r.nextInt(MAX_Y));
}
}
If you later need to recall the spawn position of a zombie, you can save it as a private int in the zombie instance.
Also the original code will give you negative coordinates because you multiply with a negative constant. And even if it did work you'd end up with more zombies than you'd want because the new Zombie() code runs in an inner loop.
There are a couple things causing problems with the code. As Supericy said, you're accidentally casting all of your random numbers too soon, truncating their values, and as SJuan76 mentioned in a comment, your for loop isn't quite set up right. (It works, but it can be much cleaner.)
First, the casting issue: When you cast a double to an int, the decimal portion is rounded down.
int num = (int) 0.999; //num == 0
Math.random() always returns a double between 0 and 1, so when cast to an int, it's always truncated to zero as well.
So that means your line
int randomXSpawn = (int) Math.random() * -300 + -50;
is evaluated like this:
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomXSpawn = (int) 0.xxxx * -300 + -50;
int randomXSpawn = 0 * -300 + -50;
int randomXSpawn = -50;
To fix this, simply add parenthesis to force the multiplication and addition to happen before the casting, like Supericy said:
int randomXSpawn = (int) (Math.random() * -300 + -50);
int randomYSpawn = (int) (Math.random() * -100 + 800);
Second, the for loops: This is what you have now. It works correctly, but it could be written more clearly.
for(int i = 0; i < 100; i++) {
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomYSpawn = (int) Math.random() * -100 + 800;
int[][] spawn = {{randomXSpawn,randomYSpawn}};
for(int j = 0; j < spawn.length; j++){
zombie.add(new Zombie(spawn[j][0],spawn[j][1]));
}
}
What happens during a single iteration of the outer for loop?
//int i = 0;
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomYSpawn = (int) Math.random() * -100 + 800;
int[][] spawn = {{randomXSpawn,randomYSpawn}};
for(int j = 0; j < spawn.length; j++){
zombie.add(new Zombie(spawn[j][0],spawn[j][1]));
}
First, you generate two random numbers:
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomYSpawn = (int) Math.random() * -100 + 800;
Then, you store those numbers so you can get to them later:
int[][] spawn = {{randomXSpawn,randomYSpawn}};
Finally, you enter into the final for loop:
for(int j = 0; j < spawn.length; j++){
zombie.add(new Zombie(spawn[j][0],spawn[j][1]));
}
What happens in there? We know that spawn is a two-dimensional array. Since you just declared it above, we also know that it has dimensions [1][2]. This means that the for loop will iterate once: when j = 0, because when j = 1 on the next iteration, j < spawn.length will no longer be true.
Because of how you declared spawn, we know that spawn[0][0] == randomXSpawn and spawn[0][1] == randomYSpawn, so the line in the middle of the inner for loop effectively does this:
zombie.add(new Zombie(randomXSpawn,randomYSpawn));
This suggests a way to make your code more clear: You can remove the spawn array and the inner for loop in order to call the Zombie constructer with randomXSpawn and randomYSpawn directly.
This is what the change would look like:
for(int i = 0; i < 100; i++) {
int randomXSpawn = (int) Math.random() * -300 + -50;
int randomYSpawn = (int) Math.random() * -100 + 800;
zombie.add(new Zombie(randomXSpawn,randomYSpawn));
}
Putting both changes together, we get this:
for(int i = 0; i < 100; i++) {
int randomXSpawn = (int) (Math.random() * -300 + -50);
int randomYSpawn = (int) (Math.random() * -100 + 800);
zombie.add(new Zombie(randomXSpawn,randomYSpawn));
}
If you don't like my suggested restructuring of the for loops, you don't have to change that. I think the way you have them now works correctly. It's just my opinion that it's difficult to read, and if you disagree, that is allowed =). The first change about using parenthesis to control casting is what is causing the problem you mentioned in your question, though, and needs to be taken care of.
Related
Given a radius, find the coordinates (x, y) such that the distance between (x, y) to the origin is greater than the radius. However, I want to find the distance that is the smallest distance that is greater than the radius. Problem is seen here: open.kattis.com/problems/discdistrict. My code works well for radii that are less than or equal to 5000. However, for large radii, my code starts to break and takes exponentially longer to finish!! Are there any ideas?
Examples: 1 yields (1, 1). 5 yields (2, 5). 10 yields (5, 9). (radius | radius >= 10,000) takes an exponentially long period of time.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class disc_district {
public static void main(String[] args) {
Scanner new_scanner = new Scanner(System.in);
int radius = new_scanner.nextInt();
new_scanner.close();
//ArrayList<Double> new_distance = new ArrayList<>();
double min_max_dist = Double.MAX_VALUE - 1;
int[] new_min_pair = new int[2];
for (int i = (radius / 2); i <= radius; i++) {
int start = (int)Math.floor(Math.sqrt(Math.pow(radius, 2) - Math.pow(i, 2))) + 1;
for (int j = Math.max(i, start); j <= radius; j++) {
//for (int j = i; j <= radius; j++) {
double new_dist = Math.sqrt(Math.pow(i, 2) + Math.pow(j, 2));
if (new_dist > radius) {
if (min_max_dist > new_dist) {
min_max_dist = new_dist;
new_min_pair[0] = i;
new_min_pair[1] = j;
}
}
}
}
System.out.println(new_min_pair[0] + " " + new_min_pair[1]);
}
}
Thanks again!
It does not takes an exponential time to finish, just a quadratic time, that is O(radius² / 4). This is because you use 2 nested loops. You can speed up the inner-most loop by just solving a basic conic inequation.
Indeed, you are searching for j values where sqrt(i² + j²) > r with r = radius. This means i² + j² > r² since all values are expected to be positives ones. This means j² > r² - i² and so j > sqrt(r² - i²). As a result, you can start the second inner loop to the value Math.sqrt(Math.pow(r, 2) - Math.pow(i, 2)) if it is bigger than i (note that the expression in the square root is always positive since i <= r).
The resulting code is:
for (int i = (radius / 2); i <= radius; i++) {
int start = (int)Math.floor(Math.sqrt(Math.pow(radius, 2) - Math.pow(i, 2))) + 1;
for (int j = Math.max(i, start); j <= radius; j++) {
System.out.println(i + " " + j);
}
}
Note that if you want to get one value, you can just use a break instruction so to avoid many unneeded computations.
Assuming the initial code is correct and you really need all the values to be printed, the complexity of the new code is optimal (each iteration is done in a constant time and is strictly useful since it results in a printed line), but it is still quadratic. A deeper analysis of the code shows its (optimal) complexity is O(radius² / 11.68). Thus the new code is only about ~3 times faster in theory. It can still be slow since there are a lot of values to be printed. It may be interesting to better control when the output is flushed.
Update:
Based on the additional information (about the distance being minimized and only one solution required to be printed), here is the resulting code:
double min_max_dist = Double.MAX_VALUE - 1;
int[] new_min_pair = new int[2];
for (int i = (radius / 2); i <= radius; i++) {
int start = (int)Math.floor(Math.sqrt(Math.pow(radius, 2) - Math.pow(i, 2))) + 1;
int j = Math.max(i, start);
double new_dist = Math.sqrt(Math.pow(i, 2) + Math.pow(j, 2));
if (new_dist > radius) {
if (min_max_dist > new_dist) {
min_max_dist = new_dist;
new_min_pair[0] = i;
new_min_pair[1] = j;
}
}
}
System.out.println(new_min_pair[0] + " " + new_min_pair[1]);
This code find the solution that minimize the distance. It runs in O(n/2) time, that is, a linear time.
I'm currently going through the book Computer Science: An Interdisciplinary Approach, which contains a code snippet for shuffling an array (in this example, the array contains a deck of cards). The code is as follows:
int n = deck.length;
for (int i = 0; i < n; i++)
{
int r = i + (int) (Math.random() * (n-i));
String temp = deck[i];
deck[i] = deck[r];
deck[r] = temp;
}
My question is, why is the simpler (int) (Math.random() * n) not preferred? Is it less random than i + (int) (Math.random() * (n-i))?
Any help appreciated!
They give you different values.
(int) (Math.random() * n) gives you a value in the range 0 <= r < n (between 0 [inclusive] and n [exclusive]).
i + (int) (Math.random() * (n-i)) gives you a value in the range i<= r < n (between i [inclusive] and n [exclusive]).
So for example, if i is 10, your "simplified" version could give you 5. The version in the code cannot.
The idea is to take a random value that hasn't been chosen yet. If you'd allow your scheme then some elements may never get shuffled and the chance that some elements stay in place is therefore too high.
Math.Random() can return a double value between 0.0 and 1.0.
https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#random()
So if you just do (int) (Math.random() * n) then the value of r can be higher then n-1 while will lead to ArrayIndexoutofbound exception.
http://docs.oracle.com/javase/7/docs/api/java/lang/ArrayIndexOutOfBoundsException.html
How do I print a number that is not 'x'. But within the given range.
int x = (int) (Math.random() *3);// I have generated a random number
System.out.println(x);// This will print the random number
There is some confusion understanding this problem so i will explain it with the help of an example.
Suppose 'x' is equal to 2
Now i want to print a number that is not equal to 'x' for example 1, which is within the range stated above.
I would do:
int possibilities = 7;
int x = ThreadLocalRandom.current().nextInt(possibilities);
int y = ThreadLocalRandom.current().nextInt(possibilities - 1);
if (y >= x)
y++; // adding 1 to y here means that y can't equal x
This way y is equally likely to be any of the integers in the range 0 to possibilities - 1 except x.
ThreadLocalRandom.current().nextInt(possibilities); is just an alternative way of generating a random number in a range. ThreadLocalRandom.current() just gives an instance of the Random class, and nextInt is a method for producing random numbers in a range (I prefer this to the Math.random approach).
However, you may find it easier to understand this solution, which is more similar to your original question.
int possibilities = 7;
int x = (int) (Math.random() * possibilities);
int y = (int) (Math.random() * (possibilities - 1));
if (y >= x)
y++;
Try the Random class
Random r = new Random();
int max = 10;
int min = 1;
int x = r.nextInt((max - min) + 1) + min;// I have generated a random number
System.out.println(x);// This will print the random number
I assume you want to print a random number within gives range in java you replace your line
int x = (int) (Math.random() *3);
with this code
Random rand;
int x = rand.nextInt((max - min) + 1) + min;
Given your code:
int x = (int) (Math.random() *3);
int y = (int) (Math.random() *3);
if(y != x){
System.out.println(x);
}
Right now, it makes number above 50 positive and numbers below 50 negative. How should I change the code to make it so that any number can be either positive or negative?
public class P1G
{
static void main()
{
int[] a = new int[10];
for(int index = 0; index < 10; index ++)
{
double r = Math.random();
int p = (int) (((100 - 0) + 1) * r + 0); // (-) or (+)
if ( p < 50 )
{
int n = (int) (((100 - 0) + 1) * r + 0);
n = n * -1;
System.out.println(n);
}
else
{
int n = (int) (((100 - 0) + 1) * r + 0);
n = n;
System.out.println(n);
}
}
}
}
Unless I'm missing something you want
int n = (int) (Math.random() * 101) - 50;
System.out.println(n);
Explanation
Get a random int in the range 0 to 100 and subtract 50, that gives the range -50 to positive 50. Per the Math.random() Javadoc -
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Instead of randoming over [0,101], you can random over [-50, 50] by doing the following:
int p = (int) (100 * r - 50);
Can you just use this?
new Random().nextInt(50)-100
Oh, sorry,, make a big careless mistake.
new Random().nextInt(100) - 50
I've been trying to generate a pattern of circles using a for loop. However, when it runs everything looks fine except for the 9th ring of circles which is ever so slightly. Having looked at a print out of numbers for that circle everything looks fine, so I can't work out what is going wrong. However, when I add one to the angle value of that ring. i.e. j (the commented out code) it pretty much corrects.
Any idea why this might happen. having looked at all the numbers I can only think it is some math error that I haven't factored in or am I missing something obvious.
Thanks!
ellipse(325,325,15,15);
float div = 1;
for (int i = i; i < 25; i++)
{
div = i*6
float segment = 360/div;
float radius = (i*20);
for (int j = 0; j < 360; j+=segment)
{
//if (i==8)
//{
//println("before " + j);
//j+=1;
//println("after " + j);
//}
float x = 325 + (radius*cos(radians(j)));
float y = 325 + (radius*sin(radians(j)));
ellipse(x, y, 15, 15);
}
}
Ok, three things, in order of importance. Two of these have already been mentioned.
1) Clean out the ints. Variable i can be an int, but none of the others (especially j since it is an angle, not a counter or index), and you want to make sure that all math operations treat numbers as doubles. Go so far as to designate your constants as doubles (e.g. use 1d instead of 1).
2) Avoid cumulative errors. In your inner for loop, you repeatedly add to j. Bad. Instead, compute your angle directly based on which circle you're computing.
3) Use double, not float. You'll get better precision.
I'd do it like this...
ellipse(325,325,15,15);
for (int i = i; i < 25; i++)
{
double div = i*6d;
double radius = (i*20d);
for (int j = 0; j < div; j++)
{
double theta = j * 360d / div;
double x = 325d + (radius*cos(radians(theta)));
double y = 325d + (radius*sin(radians(theta)));
ellipse(x, y, 15, 15);
}
}
You get the segment as a float, but then you use an int to calculate the degrees.
for (int j=0; j < 360; j+=segment)
and
float x = 325 + (radius*cos(radians(j)));
This is what is causing the rounding errors.
And if you make i to get a value bigger than 60 the program will never end.
Use double instead of float to minimise representation error.
Change the for loop to reduce error.
for (int k = 0; k < div; k++) {
int j = k * 360 / div;
This will give you different values for j which are likely to be more correct.