Swift: Generate random number between multiple ranges - swift

I want to generate a random number that can be between
-3...-8 and 3...8
I know I could find a roundabout way of doing this by first doing a random integer between 0 and 1 and then picking the range on that:
let zeroOrOne = CGFloat.random(in: 0...1)
if zeroOrOne == 0 {
randomNum = CGFloat.random(in: -3...-8)
} else {
randomNum = CGFloat.random(in: 3...8)
}
but I am wondering if there is a better way of doing this.

I am sure you want to use Bool.random.
One way to write it would be
let randomNum = CGFloat.random(in: 3...8) * (Bool.random() ? 1 : -1)
or
var randomNum = CGFloat.random(in: 3...8)
if Bool.random() {
randomNum.negate()
}
There is no single correct solution.

There is a general solution for generating a random integer within several nonoverlapping ranges.
Find the number of integers in each range; this is that range's weight (e.g., if each range is a closed interval [x, y], this weight is (y - x) + 1).
Choose a range randomly according to the ranges' weights (see this question for how this can be done in Swift).
Generate a random integer in the chosen range: CGFloat.random(in: range).

Related

Extrapolate Animation Curve (Endless game balancing curve)

I need a curve editor to make balancing of endless game then I tried to use AnimationCurve.
I need to set a curve to a certain range ex. [0;1] and if I want a value over 1, the result of the Evaluation have to extrapolate the curve. I want to be able to compute Y from X and X from Y.
The problem is AnimationCurve have only 3 WrapMode (Clamp, PingPong, Loop).
How to extrapolate an AnimationCurve ?
Is there a better tool to make curve with extrapolation (post and pre curve) ?
For real extrapolation I think you'd have to implement your own system based on Bézier mathematics. Me at least am not aware of unity providing it out of the box.
A work around for it could be to just define values beyond the 0 to 1 range to cover the extents, animation curves do allow this, I don't think there are to many issues with that.
Another solution, to stay in 0 to 1 range still but achieve the same effect, would be to model the curve from 0 to 1 so that it would cover extreme values within that range and remap the time for curve evaluation given by the object to a 0 to 1 range.
E.g.:
// define range extents
float rangeMin = -5f, rangeMax = 5f;
var range = 10f;
// range could be calculated at runtime if necessary:
// [to] (higher value) - [from] (lower value) = [range]
// 5f - -5f = 10f
var timeRaw = 0; // variable provided value
var time01 = (timeRaw - rangeMin) / range;
// reult by timeRaw = 0: (0 - -5) / 10 = 0.5
// reult by timeRaw = 5: (5 - -5) / 10 = 1.0
// reult by timeRaw = -5: (-5 - -5) / 10 = 0.0
Combining both solutions allow you to cover even more extreme values.

2D Motion vectors - calculate location of object at a given time

I am having problems understanding 2D motion vectors when moving certain objects at a given time. My knowledge of linear algebra is limited and I really don't know the exact search terms to look for, so I wanted to know whether anybody could help me or at least hint me in the right direction.
My problem looks like this:
I have two points, a startPoint, and an endPoint in space. They have each a specific location, denoted as (x_1, x_2) and (y_1, y_2) respectively. Both of these points have a time attached to it, named t_startPoint or t_endPoint, respectively. I now want to find out, for a given currentTime (= basically any point in time that is in between t_startPoint and t_endPoint), where exactly would a new point N be positioned on the connection line between those two points. I know the description is not trivial and that’s why I also added an image describing what I would like to do:
So far, this is what I have as my algorithm:
func update(_ time: Int64) {
let t_startPoint: Int64 = 1
let position_startPoint: = (1.0, 1.0)
let t_endPoint: Int64 = 5
let position_endPoint: Vector = (4.0, 5.0)
let currentTime = 3
let duration = t_endPoint - t_startPoint
let x = position_startPoint.x + ((position_endPoint.x - position_startPoint.x) / Float(duration)) * (Float(currentTime - t_startPoint))
let y = position_startPoint.y + ((position_endPoint.y - position_startPoint.y) / Float(duration)) * (Float(currentTime - t_startPoint))
//
However, no matter what I do, my objects keep overshooting, erratically moving back and forth, and I don't know where to start. Any help would be greatly appreciated!
For constant velocity moving there is relation:
(t-t1) / (t2-t1) = (x-x1) / (x2-x1)
x = x1 + (x2-t1) * (t-t1) / (t2-t1)
so your expresiion looks right. Check:
1 + (4-1) * (3-1) / (5-1) = 1 + 3 * 2 / 4 = 2.5 - exact middle, OK

Generate a random number between negative and positive in swift [duplicate]

This question already has an answer here:
How to generate a random number in a range (10...20) using Swift [duplicate]
(1 answer)
Closed 4 years ago.
So I'm trying to generate a random number between negative and positive range because I need to give an object a position on the x axis. I've tried with arc4random and arc4random_uniform but it doesn't work. I need a way to generate a random position on the x axis, negative and positive.
I don't think you can generate negative random number using arc4random directly
let lValue = -10 // (your negative number)
let uValue = 10 //(your positive number)
let result = Int(arc4random_uniform(UInt32(uValue - lValue + 1))) + lValue
print(result)
hope this will work
let min : UInt32 = 10
let max : UInt32 = 50
let randomNumber = arc4random_uniform(max - min) + min
if arc4random_uniform(2) == 0 {
randomNumber = randomNumber * -1
}

Creating random number in SpriteKit

I'm trying to create a game in which a projectile is launched at a random angle.
To do this I need to be able to generate two random Int's. I looked up some tutorials and came up with this:
var random = CGFloat(Int(arc4random()) % 1500)
var random2 = CGFloat(Int(arc4random()) % -300)
self.addChild(bullet)
bullet.physicsBody!.velocity = CGVectorMake((random2), (random))
It worked for a while but now it just crashes.
Any help would be appreciated.
What I find I use the most is arc4random_uniform(upperBound) which returns a random Int ranging from zero to upperBound -1.
let random = arc4random_uniform(1500)
let random2 = arc4random_uniform(300) * -1
//pick a number between 1 and 10
let pick = arc4random_uniform(10)+1
The lowdown on the arc4 functions: arc4random man page
GameplayKit has a nice class wrapping the arc4 functions: GameplayKit Randomness
and a handy reference: Random Hipster
I dont understand very well your issue but I think it could be useful:
func getRandomPointFromCircle(radius:Float, center:CGPoint) -> CGPoint {
let randomAngle = Float(arc4random())/Float(UInt32.max-1) * Float(M_PI) * 2.0
// polar => cartesian
let x = radius * cosf(theta)
let y = radius * sinf(theta)
return CGPointMake(CGFloat(x)+center.x,CGFloat(y)+center.y)
}

Swift - arc4random() could not find an overload for '%' that accepts the supplied arguments

I have a UISlider to give a range of a radius of search (for 5 - x miles, max x=100 miles), and I want to be able to get a random radius distance within this range.
#IBAction func sliderMoved(sender: UISlider){
//gives a range (minimum range 5 miles, maximum range 5 - 100 miles)
var range = (sender.value*95)+5
//gives a random distance in miles from within that range
var distance = Int((arc4random()%(range))+1)
}
When I try to assign "distance" I get the error "could not find an overload for '%' that accepts the supplied arguments".
Use arc4random_uniform()
let distance = arc4random_uniform(UInt32(range)) - 1
arc4random_uniform() will perform the modulo operation without bias.
The problem is that the sender.value is a UISlider.value that is a Float. arc4random is a UInt32 which is your main issue here.
What you've done is try to convert the whole thing to an Int when you just need the internal components to be matching first. So get the range and the arc4random to the same type (I've done a Float here) and then do the casting you want =
Int(Float(arc4random()) % range + 1)
You of course could also use arc4random_uniform as the other commenters have stated as in :
arc4random_uniform(UInt32(range)) + 1
which is actually much better if you don't really care about the value of your range (especially any decimal part).
http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=20282