Simple algorithm for generating random numbers with bigger/smaller probability - javascript

I'm currently working on a game, with scrollable screen and I need to find a simple algorithm for placing obstacles in the game. I have a gameSpeed, that is increased in time (from 1 to 12, increased by 0.005 each 1/60s) and a range of available positions between 200 and 600 (ints). I'd like to achieve a bigger probability of receiving smaller number when the speed is bigger, but it's my 14th hour straight coding and I cannot come up with anything usable and not overcomplicated. I'd like to minimize Math and random functions so that the rendering loop won't take too long. Any help appreciated !

You could square or square-root the random number to shift the density in one direction. Math.random()*Math.random() will have a higher probability to produce smaller numbers (near 0) than higher ones (near 1).
Your formula could be like
var position = Math.pow(Math.random(), gameSpeed / 3) * 400 + 200;

The simplest answer I can think of is to create an array having more lower numbers compared to higher ones, for example, for producing random between [1,5] (both inclusive). So your array may look like [1,1,1,1,1,2,2,2,2,3,3,3,4,4,5]
And when you randomly pick an element from that array you will have a higher chance of picking up low number compared to high one.

Another way might be to have two (or more) percentages:
say, start with 10% of the time we access 90% of the range, and 90% of the time we access the other 10%. Then we gradually flip those numbers as the speed increases. For example,
var lBound = 200,
uBound = 600,
range = uBound - lBound,
gameSpeed = 1,
initialMarker = 0.1,
percentageRange = 1 - 2 * initialMarker,
marker = (gameSpeed - 1) / 11 * percentageRange + initialMarker,
position
Math.random() <= marker ? position = Math.floor(Math.random() * (1 - marker) * range) + lBound
: position = uBound - Math.floor(Math.random() * marker * range)
console.log(position)
Try changing gameSpeed and see what happens. Change initialMarker for a different set of percentages (currently set at 0.1, which means 10% / 90%).

Related

Based on distance away from a coordinate, generate score. (Lower Distance Away => Higher Score)

here is my question:
Based on distance away from a coordinate, generate a score. The smaller the distance away, the higher the score would be. How could this be done? I'm new to JS and not very good a math so how would I make a function to do this?
1000 would be the highest score achievable and 0 would be the lowest score achievable. Marking the first person who answers this question.
An real life example is provided in the image. A game called GeoGuessr calculates a score from 0-5000 based on the distance away from a point. View image for refrence.
Thanks so much all.
There are of course many possible ways to do it, but here is a suggestion: use a Gaussian formula like
score = 1000 * exp(-0.5 * (distance / sigma)^2)
where sigma is a positive parameter controlling the width of the Gaussian and exp is the exponential function (Math.exp() in JavaScript). This way, distance = 0 corresponds to the max score of 1000. The score decreases monotonically as distance increases, and asymptotically score = 0 as distance → ∞.
Seeing as the gaussian formula answers edit-queue is full. I just wanted to add that the correct syntax for Javascript for the formula is:
score = 1000 * Math.exp(-0.5 * (distance / sigma)**2)
Notice the
**2 instead of the ^2. ^2 in javascript is a bitwise XOR expression.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation
If you want a linear decrease and strict point for zero score then you can use this formula:
MaxPoints - distance * MaxPoints / DistanceForZeroScore
You can add Math.max(formula, 0) if you don't want negative scores.
Distance between points (A,B) and (X,Y) can be calculated in many ways, but the most natural is Euclidean distance:
sqrt((A-X)^2+(B-Y)^2)
So the complete formula can be for example
Math.max(1000 - Math.sqrt((A-X)^2+(B-Y)^2) * 1000 / 3000, 0)

Coming up with an Algorithm

I have a circle in my canvas. The mouse position is calculated in relation to the canvas. I want the circle to move when the mouse is at <=100px distance from it. The minimum distance to start moving is 100px, at 0.5px/tick. It goes up to 2px/tick at 20px distance.
Basically, the closer the mouse is to the circle, the faster the circle should move.
What I have so far moves the circle when distance is less or equal to 100 -- (I'm using easeljs library)
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circle.x += 0.3;
stage.update();
}
}
What I want
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circleSpeed = // equation that takes distance and outputs velocity px/tick.
circle.x += circleSpeed;
stage.update();
}
}
So I thought this was a mathmatical problem and posted it on math exchange, but so far no answers. I tried googling several topics like: "how to come up with an equation for a relation" since I have the domain (100, 20) and the range (0.5, 2). What function can relate them?
Thing is I'm bad at math, and these numbers might not even have a relation - I'm not sure what I'm looking for here.
Should I write a random algorithm "circleSpeed = 2x + 5x;" and hope it does what I want? Or is it possible to do as I did - "I want these to be the minimum and maximum values, now I need to come up with an equation for it"?
A pointer in the right direction would be great because so far I'm shooting in the dark.
If I understand it correctly, you want circleSpeed to be a function of distance, such that
circleSpeed is 0.5 when distance is 100.
circleSpeed is 2 when distance is 20.
There are infinity functions which fulfill that, so I will assume linearity.
The equation of the line with slope m and which contains the point (x₀,y₀) is
y = m (x-x₀) + y₀
But in this case you have two points, (x₁,y₁) and (x₂,y₂), so you can calculate the slope with
y₂ - y₁
m = ───────
x₂ - x₁
So the equation of the line is
y₂ - y₁
y = ─────── (x - x₁) + y₁
x₂ - x₁
With your data,
0.5 - 2
y = ──────── (x - 20) + 2 = -0.01875 x + 2.375
100 - 20
Therefore,
circleSpeed = -0.01875 * distance + 2.375
I assume you want a linear relation between the distance and speed?
If so, you could do something like circleSpeed = (2.5 - 0.5(distance/20)).
That would, however set the speed linearly from 0 to 2.5 on the range (100 to 0), but by using another if like this if (distance < 20) circleSpeed = 2 you would limit the speed to 2.0 at 20 range.
It's not 100% accurate to what you asked for, but pretty close and it should look ok I guess. It could possibly also be tweaked to get closer.
However if you want to make the circle move away from the mouse, you also need to do something to calculate the correct direction of movement as well, and your problem gets a tiny bit more complex as you need to calculate speed_x and speed_y
Here is a simple snippet to animate the speed linearly, what that means is that is the acceleration of the circle will be constant.
if distance > 100:
print 0
elseif distance < 20:
print 2
else:
print 2 - (distance -20 ) * 0.01875
Yet other relationships are possible, (other easings you might call them) but they will be more complicated, hehe.
EDIT: Whoops, I’d made a mistake.

How do I calculate logrithmic labels for a VU meter scale?

I writing a meter widget using canvas and need to calculate the label values for the scale. No problem except when I'm trying to re-create the scale for a VU meter. I understand it's logrithmic, but the values aren't powers of 10 on that type of meter.
see: https://en.wikipedia.org/wiki/VU_meter
The function I have is given the min and max values for the scale. For normal scales, it also is given the step between values. For example, given -20 and 30 with a step of 10, it would produce labels:
-20 -10 0 10 20 30
For a VU meter given -20 and 6, I need to produce labels:
-20 -10 -5 -3 0 3 6
And, the spacing isn't the same on the scale between those values.
I am not asking for actual code examples, but instead for ideas on how to best approach implementing this.
Should I write the function so one of the parameters is a list of labels, then plot them on a logarithmic scale? That doesn't appear to work properly because the numbers do not end up in the right places as seen in the image above of a proper VU meter.
Is there some special formula just for dB levels that isn't a simple log function?
Again, I'm not asking for code examples, just for some help understanding the best approach to use.
Thanks!
I suppose you have a value-to pixel function. What you need to write is the inverse function of that.
When you have the inverse function, you just divide the screen area to N equal parts (in the picture you have 6 regions). One region will be X pixels in width. Now you can use your inverse function to get the value for that pixel-position.
This will not be an integer, it will be something like 3.434 or 11.34 - you need a prettyfier function which will generate the closest "pretty" number (let's say just chop off the parts after the decimal).
Now you take the pretty value and calculate the pixel position for it with your original function.
Some code:
function value2px(value, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return ratio * (sigLog(value) - sigLog(valueMin)) + pxMin;
}
function px2value(px, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return sigExp((px - pxMin) / ratio + sigLog(valueMin));
}
and the demo:
http://jsfiddle.net/ambcwoLg/1/

calculating rotate and translate position based on scroll value of window

I want to move the object in my case its a plane along the shown curve on page scroll step by step taking into consideration the amount of scroll value.firstly the object moves in straight line and then after a point it changes its direction and move in that direction.How to calculate those co-ordinates?
There are two ways you could get this one. I'll try to explain both in detail.
Scenario 1: Simple path like in the question.
Scenario 2: Arbitrary complex path.
Scenario 1:
In this case you can use a simple formula. Let's go with y = -x^2. This will yield a parabola, which has a similar shape as the path in the question. Here are the steps for what to do next (we assume your scrolling element is the body tag and I assume you have jquery):
Get the "y" value of the body using the following code:
var y = $("body").scrollTop();
Plug this value into the formula. I will give 3 examples where y is 0, 100 and 225 respectively.
//y=0
0 = -x^2
-x = sqrt(0)
x = +/- 0
So if we scroll and we are at the top of the page, then x will be zero.
//y=100
100 = -x^2
-x = sqrt(100)
x = +/- 10
The equation yieldsx as either positive of negative x but we only want positive so be sure to Math.abs() the result.
//y=225
225= -x^2
-x = sqrt(225)
x = +/- 15
From this you can see that the further we scroll down the more the object moves to the right.
Now set the "left" css of your object to the calculated value. This should be enough for this method.
Scenario 2
For more complex paths (or even random paths) you should rather put the x-values into an array ahead of time. Lets say you generate the array randomly and you end up with the following x-values:
var xvals = [0, 0.5, 1, 0.5, 0];
We use normalized x-values so that we can later calculate the position independent from screen size. This particular series of values will cause the object to zig-zag across the screen from left to right, then back to left.
The next step is to determine where our scroll position is at relative to the total scroll possibility. Lets say our page is 1000px in height. So if the scoll position is at zero then x = 0. If scroll = 500 then x = screenWidth. If scroll = 250 then x = 0.5 * screenWidth etc.
In the example I won't multiply with screen width for the sake of simplicity. But given the x value this should be simple.
The first thing you might want to get ready now is a lerping function. There is plenty of example code and so on so I trust that part to you. Basically it is a function that looks like this:
function lerp(from, to, prog);
Where from and to are any values imaginable and prog is a value between 0 and 1. If from is 100 and to is 200, a prog value of 0.5 will yield a return of 150.
So from here we proceed:
Get the scroll value as a normalized value
// scrollval = 200
var totalScroll = 1000;
var normScroll = scrollval/totalScroll; // answer is 0.2
Before we get to lerp we first need to get the x-values to lerp from and to. To do this we have to do a sort of lerping to get the correct index for the xvals array:
// normScroll = 0.2
var len = xvals.length; // 5
var indexMax = Math.ceil((len-1) * normScroll); // index = 1
var indexMin = Math.floor((len-1) * normScroll); // index = 0
Now we know the 2 x values to lerp between. They are xvals[0] which is 0, and xvals[1] which is 0.5;
But this is still not enough information. We also need the exact lerping "prog" value:
// We continue from the x indeces
scrollRange.x = totalScroll / len * indexMin; // 0
scrollRange.y = totalScroll / len * indexMax; // 250
var lerpingvalue = (scrollVal - scrollRange.x) / (scrollRange.y - scrollRange.x);// 0.8
Now we finally have everything we need. Now we know we need a value between xvals[0] and xvals[1] and that this value lies at 80% between these two values.
So finally we lerp:
var finalX = lerp(xvals[0], xvals[1], lerpingvalue);// 0.4
Now we know that the x coordinate is at 0.4 of the total screen size.
Trigger these calculations on each scroll event and you should be on your way.
I hope this was clear enough. If you try and try and can't get results and can show how hard you tried then I'll be happy to write a complete index.html sample for you to work from. Good luck!
EDIT: I made a mistake with the lerpingval calculation. Fixed now.

Trying to model a hole being drilled using JS/Canvas

I'm trying to represent a hole being drilled using a web based application and I'm having difficulties. I'm in control of the inputs and various variables but unsure of how best to approach the issue.
The simulation currently has these values, they're for test purposes only.
Radius of drill bit= 15
inches Length of drill = 1000ft
RPM of drill = 100
The stratigraphic layers have their own properties, and in this instance have:
Name = bla
Depth = 100ft (models start and finish of each layer - here, 0 to 100ft down)
Permeability = 10 (currently unsure how best to model)
I don't know at the moment how to model the pressure being applied to the drill but a constant can be used if need be.
I thought I'd be able to calculate the volume of the drillbit and then apply a percentage of sorts that would represent the strength of the material so as to slow the progress of the drill.
In it's simplest form I'm trying to figure out how best to represent a hole being drilled and then calculate the area of the hole as it's being drilled.
Here's my test code:
The time variable is passed in my the way of a JavaScript Date() object. I'm hoping on using the Date object to represent the actual amount that may be drilled real time.
The test case of the canvas that is modelling it is 800px deep with a well depth of 20000ft = 25ft per pixel. I'm still trying to make sense of the output and correct it, it's a slow process. Below is the rudimentary test code.
// aggregate function:
// depth(t) = (a * RPM - b * density) * t
function depthOverTime(time, density, a, b){
var aa = (a * RPM - b * density) * time;
//(1 * 50 - 1 * 20) * 60
//(50 - 20) * 60
//30 * 60
//1800
console.log("DOT: " + roundTo2(aa)+"ft^3" + "T: " +time);
return aa;
}
function volumeExcavated(t){
var rad = 15 * 0.083333;
dot = depthOverTime(t,20,1,1);
var a = Math.PI * Math.pow(rad, 2) * dot;
console.log("VEOT: " + roundTo2(a)+"ft^3");
return a;
}
This is a sample of the console log: http://pastebin.com/UW1M73jY
As a real world simulation, this isn't nearly enough information to come up with a code description. So, assuming this is a purely fictional exercise, as a simple simulation the hole you're drilling is always going to have the drill's penetrated volume, with the drill's speed of penetration determined by the substrate's density (ignoring a million real world material properties). The RPM value determines how much substrate gets scraped per time unit, so density slows your penetration down, RPM speeds your penetration up, and if we assume the drill is indestructible, that's pretty much all we need to know.
The volume excavated is equal to the drill's volume, ignoring its groove. Keep things simple and assume a cylindrical drill, and the volume is simply πr²h, where h is the penetrated depth, and r is (obviously) the drill radius.
Start with an aggregate function:
depth(t) = (a * RPM - b * density) * t
we don't know a or b, but we do know what they represent: a is the pressure behind our drill, and b is an unknown constant that balances our function. The first step is to normalise this function with respects to the various units (RPM is per minute, t is most likely in seconds, for instance), after which we can start figuring out what a and b should concretely be (also note that we can normalise this function by fixing either a or b to 1, and setting the remaining free variable to whatever is necessary to balance the equation with respect to the reality we're simulating)
Once we have our depth-over-time function, we're pretty much done, as the volume excavated is simply
volume(t) = π * r² * depth(t)
or, if you're a student of physics and prefer the common quadratic expression:
volume(t) = τ/2 * r² * depth(t)

Categories