I am trying to create a snake game where i have 400x400 pane and the snake moves by 20 at X and Y axis. By doing this i have created a grid that has step of 20 at X and Y axis.
I want to randomly spawn a fruit at the pane but i want the width and height to be in grid so it should spawn at steps of 20 (0, 20, 40, 60 , 80, ... , 400).
I can use Math.random()*400 to get range but i cant give it unit step.
I found this question which is exactly what i asked but the solution is for lua based math.random():
math.random function with step option?
Here is how i translate the snakes position:
if (input.equals(KeyCode.W.toString()) || input.equals(KeyCode.UP.toString()))
if (snakes.get(0).getY() == 0)
movement.stop();
else
snakes.get(0).setY(snakes.get(0).getY() - 20);
*Snakes is an Arraylist of rectangles that expand as it eats food and i want only the head to eat the food
*Food is a circle that spawns at random location
And here is how i check if they come in contact:
if (food.getCenterX() == snakes.get(0).getX() && food.getCenterY() == snakes.get(0).getY())
score++;
setScore();
I move my snake over the food but the x and y position don't ever match unless i spawn food myself at the grid (say [20,40] or [60, 200]).
Is there another alternative or random with unit step or some other question that i couldn't find here at stackoverflow that can help me?
if you need integer values you can use Random.nextInt(int bound). This will produce coordinates inside your 20x20 matrix.
Random r = new Random();
int x = r.nextInt(20)*20; // values from 0 to 19 inclusively
int y = r.nextInt(20)*20;
If you want a random number out of 0, 20, 40, 60 , 80, ... , 400, then first realize that there are 21 values in that list.
Which means you want a random integer value 0, 1, 2, ..., 20, and then multiply that by 20, to get the step of 20 you want.
Don't use Math.random() for this. Sure it's convenient, but mostly is you want double values. Instead, use one of the following:
new Random() - Use in single-threaded code. Recommended.
You should generally only allocate one, then share it throughout your code.
new SplittableRandom() - Use for parallel computations.
ThreadLocalRandom.current() - Use in multi-threaded code, e.g. web servers.
All 3 have a nextInt(int bound) which returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive).
Example
Random rnd = new Random();
// in some loop generating fruits:
int fruitX = rnd.nextInt(21) * 20;
int fruitY = rnd.nextInt(21) * 20;
Related
I'm making a program in which a JPanel is created with a random RGB value and the user has to use buttons to match the color in another JPanel.
I want the random R, G, and B values to be multiples of 15, though, so the user can match the color more easily.
Right now my code looks like this:
int randRed = rand.nextInt(255);
and the same for green and blue. I could use a modulus to repeat the code until it happens to be a multiple of 15 but that would be terribly inefficient.
What is the best method to achieve a random multiple of 15 less than 255?
RIght after posting I figured it out...
int randRed = (rand.nextInt(17)+1)*15;
15 goes into 255 17 times, so just multiple a random int between 0 and 17, add 1, and multiply by 15.
In general,
static int randomBoundedMultiple(int bound, int multiplier){
return new Random().nextInt(bound) * multiplier % bound
}
then, in particular,
randomBoundedMultiple(255, 15);
So, I saw this on Hacker News the other day: http://web.mit.edu/tee/www/bertrand/problem.html
It basically says what's the probability that a random chord on a circle with radius of 1 has a length greater than the square root of 3.
Looking at it, it seems obvious that the answer is 1/3, but comments on HN have people who are smarter than me debating this. https://news.ycombinator.com/item?id=10000926
I didn't want to debate, but I did want to make sure I wasn't crazy. So I coded what I thought would prove it to be P = 1/3, but I end up getting P ~ .36. So, something's got to be wrong with my code.
Can I get a sanity check?
package com.jonas.betrand;
import java.awt.geom.Point2D;
import java.util.Random;
public class Paradox {
final static double ROOT_THREE = Math.sqrt(3);
public static void main(String[] args) {
int greater = 0;
int less = 0;
for (int i = 0; i < 1000000; i++) {
Point2D.Double a = getRandomPoint();
Point2D.Double b = getRandomPoint();
//pythagorean
if (Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)) > ROOT_THREE) {
greater++;
} else {
less++;
}
}
System.out.println("Probability Observerd: " + (double)greater/(greater+less));
}
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
boolean xsign = new Random().nextBoolean();
if (!xsign) {
x *= -1;
}
//formula for a circle centered on origin with radius 1: x^2 + y^2 = 1
double y = Math.sqrt(1 - (Math.pow(x, 2)));
boolean ysign = new Random().nextBoolean();
if (!ysign) {
y *= -1;
}
Point2D.Double point = new Point2D.Double(x, y);
return point;
}
}
EDIT: Thanks to a bunch of people setting me straight, I found that my method of finding a random point wasn't indeed so random. Here is a fix for that function which returns about 1/3.
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
Random r = new Random();
if (!r.nextBoolean()) {
x *= -1;
}
//circle centered on origin: x^2 + y^2 = r^2. r is 1.
double y = Math.sqrt(1 - (Math.pow(x, 2)));
if (!r.nextBoolean()) {
y *= -1;
}
if (r.nextBoolean()) {
return new Point2D.Double(x, y);
} else {
return new Point2D.Double(y, x);
}
}
I believe you need to assume one fixed point say at (0, 1) and then choose a random amount of rotation in [0, 2*pi] around the circle for the location of the second point of the chord.
Just for the hell of it I wrote your incorrect version in Swift (learn Swift!):
struct P {
let x, y: Double
init() {
x = (Double(arc4random()) / 0xFFFFFFFF) * 2 - 1
y = sqrt(1 - x * x) * (arc4random() % 2 == 0 ? 1 : -1)
}
func dist(other: P) -> Double {
return sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y))
}
}
let root3 = sqrt(3.0)
let total = 100_000_000
var samples = 0
for var i = 0; i < total; i++ {
if P().dist(P()) > root3 {
samples++
}
}
println(Double(samples) / Double(total))
And the answer is indeed 0.36. As the comments have been explaining, a random X value is more likely to choose the "flattened area" around pi/2 and highly unlikely to choose the "vertically squeezed" area around 0 and pi.
It is easily fixed however in the constructor for P:
(Double(arc4random()) / 0xFFFFFFFF is fancy-speak for random floating point number in [0, 1))
let angle = Double(arc4random()) / 0xFFFFFFFF * M_PI * 2
x = cos(angle)
y = sin(angle)
// outputs 0.33334509
Bertrand's paradox is exactly that: a paradox. The answer can be argued to be 1/3 or 1/2 depending on how the problem is interpreted. It seems you took the random chord approach where one side of the line is fixed and then you draw a random chord to any part of the circle. Using this method, the chances of drawing a chord that is longer than sqrt(3) is indeed 1/3.
But if you use a different approach, I'll call it the random radius approach, you'll see that it can be 1/2! The random radius is this, you draw a radius in the circle, and then you take a random chord that this radius bisects. At this point, a random chord will be longer than sqrt(3) 1/2 of the time.
Lastly, the random midpoint method. Choose a random point in the circle, and then draw a chord with this random point as the midpoint of the chord. If this point falls within a concentric circle of radius 1/2, then the chord is shorter than sqrt(3). If it falls outside the concentric circle, it is longer than sqrt(3). A circle of radius 1/2 has 1/4 the area of a circle with radius 1, so the chance of a chord smaller than sqrt(3) is 1/4.
As for your code, I haven't had time to look at it yet, but hope this clarifies the paradox (which is just an incomplete question not actually a paradox) :D
I would argue that the Bertrand paradox is less a paradox and more a cautionary lesson in probability. It's really asking the question: What do you mean by random?
Bertrand argued that there are three natural but different methods for randomly choosing a chord, giving three distinct answers. But of course, there are other random methods, but these methods are arguably not the most natural ones (that is, not the first that come to mind). For example, we could randomly position the two chord endpoints in a non-uniform manner. Or we position the chord midpoint according to some non-uniform density, like a truncated bi-variate normal.
To simulate the three methods with a programming language, you need to be able to generate uniform random variables on the unit interval, which is what all standard (pseudo)-random number generators should do. For one of the methods/solutions (the random midpoint one), you then have to take the square root of one of the uniform random variables. You then multiple the random variables by a suitable factor (or rescale). Then for each simulation method (or solution), some geometry gives the expressions for the two endpoints.
For more details, I have written a post about this problem. I recommend the links and books I have cited at the end of that post, under the section Further reading. For example, see Section 1.3 in this new set of published lecture notes. The Bertrand paradox is also in The Pleasures of Probability by Isaac. It’s covered in a non-mathematical way in the book Paradoxes from A to Z by Clark.
I have also uploaded some simulation code in MATLAB, R and Python, which can be found here.
For example, in Python (with NumPy):
import numpy as np; #NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt #for plotting
from matplotlib import collections as mc #for plotting line chords
###START Parameters START###
#Simulation disk dimensions
xx0=0; yy0=0; #center of disk
r=1; #disk radius
numbLines=10**2;#number of lines
###END Parameters END###
###START Simulate three solutions on a disk START###
#Solution A
thetaA1=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
thetaA2=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
#calculate chord endpoints
xxA1=xx0+r*np.cos(thetaA1);
yyA1=yy0+r*np.sin(thetaA1);
xxA2=xx0+r*np.cos(thetaA2);
yyA2=yy0+r*np.sin(thetaA2);
#calculate midpoints of chords
xxA0=(xxA1+xxA2)/2; yyA0=(yyA1+yyA2)/2;
#Solution B
thetaB=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pB=r*np.random.uniform(0,1,numbLines); #choose radial component uniformly
qB=np.sqrt(r**2-pB**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaB=np.sin(thetaB);
cos_thetaB=np.cos(thetaB);
#calculate chord endpoints
xxB1=xx0+pB*cos_thetaB+qB*sin_thetaB;
yyB1=yy0+pB*sin_thetaB-qB*cos_thetaB;
xxB2=xx0+pB*cos_thetaB-qB*sin_thetaB;
yyB2=yy0+pB*sin_thetaB+qB*cos_thetaB;
#calculate midpoints of chords
xxB0=(xxB1+xxB2)/2; yyB0=(yyB1+yyB2)/2;
#Solution C
#choose a point uniformly in the disk
thetaC=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pC=r*np.sqrt(np.random.uniform(0,1,numbLines)); #choose radial component
qC=np.sqrt(r**2-pC**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaC=np.sin(thetaC);
cos_thetaC=np.cos(thetaC);
#calculate chord endpoints
xxC1=xx0+pC*cos_thetaC+qC*sin_thetaC;
yyC1=yy0+pC*sin_thetaC-qC*cos_thetaC;
xxC2=xx0+pC*cos_thetaC-qC*sin_thetaC;
yyC2=yy0+pC*sin_thetaC+qC*cos_thetaC;
#calculate midpoints of chords
xxC0=(xxC1+xxC2)/2; yyC0=(yyC1+yyC2)/2;
###END Simulate three solutions on a disk END###
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So i've began coding a small game and need the 'enemys' to spawn from two points.
Heres my code for the enemy spawn;
public void createEnemy(int enemy_count){
for(int i = 0; i < enemy_count; i++){
addEntity(new Enemy((200), -10, tex, this, game));
}
}
As you can see the '(new Enemy((200)' is the point where one enemy would spawn. The other would be at 450.
so how do i alternate between these two point where the enemy spawns each time they are killed?
********************EDIT
// For respawn enemy
if(y > (Game.HEIGHT * Game.SCALE)){
x = 450;
y = -10;
}
Okay im pretty sure ive got to randomize that as well for it to work? ideas? (x needs to be random 450 or 200).
Thanks,
Max
If you want to alternate between 200 and 450 on every other iteration:
addEntity(new Enemy((i % 2 == 1 ? 200 : 450), -10, tex, this, game));
This uses the modulo operator % to determine whether the loop counter i is odd or even and uses the ternary operator to select either 200 or 450.
If you want to pseudorandomly choose one or the other, you can use Math.Random() instead, as #Chrisky expounded in a comment:
addEntity(new Enemy((Math.Random() > 0.5 ? 200 : 450), -10, tex, this, game));
Edit: You can apply the same patterns to the second block of code you've added to your question.
if (y > (Game.HEIGHT * Game.SCALE)) {
x = (Math.Random() > 0.5 ? 200 : 450);
y = -10;
}
If you want the monster to spawn at a random undetermined location each time, you should generate a random value, in your case you only have two random points so you want 0 or 1.
Once you create a random number (either 0 or 1) check the value of the random number, and then turns it into either 250 or 400. This can be done using an associate array, or (much simpler) an if else statement.
See:
Generating a Random Number between 1 and 10 Java
Also, you should know there's no such thing as truly random. Some people insist on calling it psuedorandom but I find that somewhat pedantic.
Select a location at random:
Random random = new Random(); // Somewhere at the top of your code
addEntity(new Enemy((random.nextBoolean() ? 200 : 450), -10, tex, this, game));
Alternating locations, without dependency on the loop counter variable. This is useful if you spawn enemies outside of the loop as well. (For example, other loops for other types of enemies.)
bool flag = false; // Somewhere at the top of your method for spawning enemies.
addEntity(new Enemy((flag = !flag ? 200 : 450), -10, tex, this, game));
I have an 600x600 screen that I wanted to divide it each 10 squares basically so I can do an snake game, so I need to generate the food into those divisions.
The code I thought of:
x.nextInt(10)*x.nextInt(6)*x.nextInt(10)
This doesn't work, and even if it worked there are multiple values that can achieve 20, lets say 1*2*10, 2*1*10...
So I also thought of this:
(int)(x.nextInt(600)/10)*10
But it doesn't make the interval of 10...
I also thought of this one:
Integer.parseInt(Double.toString(x.nextInt(600)/10))*10
but its pretty much stupid and it doesn't work (gives an error)
if you didn't understood what I want, here is results:
Random pairs (x and y):
10, 60
420, 170
550, 480
80, 600
Here is what I don't want:
14, 52
88, 19
551, 529
415, 550
How can I manage the logic to make the random with this interval?
You could try:
(int)(Math.random() * 60) * 10
Essentially this finds a random int between 0 and 59 then multiplies it by ten so that the numbers have a gap of 10...
Alternativly, you could take advantage of integer division and use
(int)(Math.random() * 600) / 10 * 10
which works on the same principle.
You can solve this by generating an integer between 0 and 60 (or I guess you really want 0 to 59 as a tile is 10 pixels wide and should be on the screen), and then multiplying that integer by 10.
You should use Math.random()
int random = (int )(Math.random() * 60 +1) * 10;
Description:
random() method returns a random number between 0.0 and 0.999. So, you multiply it by 60, so upper limit becomes 0.0 to 59.999, when you add 1, it becomes 1.0 to 60.999, now when you you truncate to int, you get 1 to 60. and then multiply it by 10 to get a multiple of 10 between 10 to 600.
note: If you want from 0 to 60 remove 1 and use
int random = (int )(Math.random() * 61) * 10;
Have a GridSquare class, with coordinates from 0 to 10 (randomly chosen), and then use a toScreenArea function that multiplies the coordinates by the number of pixels per square to find the appropriate spot on the screen to put the squares on.
I'm trying to create a function that will translate float values to a color. I created a simple linear scale:
float value;
float maxValue;
float scaleStep = maxValue / 5;
if (value < scaleStep) {
color = blue
}
if (value > scaleStep && value <= scaleStep * 2) {
color = green
}
if (value > scaleStep * 2 && value <= scaleStep * 3) {
color = yellow
}
if (value > scaleStep * 3 && value <= scaleStep * 4) {
color = orange
}
if (value > scaleStep * 4 && value <= scaleStep * 5) {
color = red
}
but since most (but not all) of the values from the sets that I'm trying to represent are in close proximity from one particular value, graphical representation using linear scale isn't very useful (almost everything is translated to one color).
How can I create a non-linear scale so that differences between the values are more visible?
Interpolation is what you want. Interpolation generates samples between known samples in a dataset.
Here, your known samples are your colors; blue, green, yellow, orange, and red. The colors between those known colors are what you're looking for.
Here's a link to a nice visualizer of interpolation functions.
And here's a few interpolation functions for your convenience. Play with them, find the one that works best for you!
public float linearInterpolation(float start, float end, float normalizedValue) {
return start + (end - start) * normalizedValue;
}
public float sinInterpolation(float start, float end, float normalizedValue){
return (start+(end-start)* (1 - Math.cos(normalizedValue * Math.PI)) / 2;
}
//usage
linearInterpolation(red, green, .5f);//halfway between red and green.
//same with other demonstrations.
Edit:
Here, start and end refer to a starting and ending sample. The normalizedValue is some value between [0, 1] inclusive (that means it can equal exactly 0 or 1, or any value in between 0 and 1. That's what the term normalized means typically.)
So, for you, start and end will be two colors, and normalizedValue will represent how near you are to the starting or ending color.
Take linearInterpolation for example.
red = 1;
green = 2;
float midway = 1 + (2 - 1) * .5;
//midway = 1.5, which is halfway between red and green.
float allRed = 1 + (2 - 1) * 0;
//allRed = 1, which is the value of red (or start)
float allGreen = 1 + (2 - 1) * 1;
//allGreen = 2, which is the value of green (or end)
So, for linear interpolation, the closer the normalizedValue is to 1, the nearer the returned value it is to end. The closer normalizedValue is to 0, the closer the returned value is to start.
This isn't necessarily true for other interpolation functions. You can think linear interpolation as a simple line segment connecting values. Want a value halfway between those segments? Use a normalized value of .5, viola!
Other functions might have steeper slopes, or even oscillate between start and end!
Try and stop thinking in terms of color, and start thinking more abstractly. Colors are a certain distance apart. Interpolation helps you define what values lie in the distance between them.
Since the float values are in a set, you know how many there are and can calculate a color interval. You can then iterate over them, assigning colors and incrementing by the color interval.
Edit: The downside of this approach is that the same float value will not map to the same color when the number of values changes.
I suggest a logarithmic scale. If you use base 10 logs, the range will be from -39 to +39.
Depending on your distribution, a double or triple log can be better. I made a very quick test, and for the sample { 1.00, 1.20, 1.10, 1.05, 1.15, 9.70, 1.20, 2.00, 1.01, 1.03, 1.16, 1.02, 9.00, 1.20, 1.10, 1.50, 1.05, 1.15, 2.00, 3.00 }, function
int f(float x) {
return (int)(Math.log(Math.log(x)*100+1)*2.5) ;
}
Produces the following distribution:
f(x) color count
0 blue 4
1 green 4
2 yellow 6
3 orange 3
4 red 3
Not bad for 5 minutes of work. However, if you post a reasonable sample of numbers (say 100), a distribution graph, or, much better, a distribution histogram, we could help you better. The trick is to find the distribution function of the data. From that function it is very easy to come with a second function that makes the distribution uniform ("flat").
A second alternative in your case (which is relatively simple as you want to use just a few colors), is to use scaleSteps of different "width".
if( value < greenMin ) color= blue ;
else if( value < yellowMin ) color= green ;
else if( value < orangeMin ) color= yellow ;
else if( value < redMin ) color = orange ;
else color= red ;
I took the liberty of condensing the code a bit. Let me know if it's not clear. You need to determine the values of greenMin, yellowMin, orangeMin, and redMin, of course. For that, grab a big, representative data sample, sort it, and divide it in 5 groups of equal size. The first value of the second group is greenMin, first value of the third is yellowMin, and so on. You can use an office spreadsheet program to do this, as it's a one-time activity.