RandExcept (rifddle)

BlitzMax Forums/BlitzMax Beginners Area/RandExcept (rifddle)

Matt Merkulov(Posted 2007) [#1]
Can you make a function that returns a random integer (int) number in certain range but except one? In example, RandExcept(3, 9, 5) can return 3, 4, 6, 7, 8, 9 with equal chances, but never 5.

Main limitation is that you only allowed to enter code in one sting after "Return", so it'll be one formula.

Just interesting.

Function RandExcept(v1, v2, ev)
 Return ' Your code must be only here in this line after Return
End Function


P. S. This riddle obviously HAVE a solution :)


Floyd(Posted 2007) [#2]
If you want Rand(3,9) except 5 then use Rand(3,8) and add 1 if result is at least 5.


Jake L.(Posted 2007) [#3]
Function RandExcept% (v1%,v2%,ex%)
 if v1=v2 and ex=v1 then RuntimeError ("Use some useful parameters!")
 local res%
 repeat
    res=Rand(v1,v2)
 until res<>ex
 return res
End Function



Matt Merkulov(Posted 2007) [#4]
Jake L.:

Keep this in mind:

Main limitation is that you only allowed to enter code in one sting after "Return", so it'll be one formula.




Dreamora(Posted 2007) [#5]
Not possible as a single line but with 2 lines:
Function RandExcept(v1, v2, ev)
 local i:int = rand(v1,v2)
 return i + (i>=ev)
end function


Reason that a single line can not work is there as well: you need to know the result of rand before you can work with it!


Jake L.(Posted 2007) [#6]
Oh, read over that. Is there any reason for this (kind of strange) limitation you set yourself?


Floyd(Posted 2007) [#7]
Is there any reason for this (kind of strange) limitation

It's a puzzle, not a question about useful code.

At first glance it seems impossible. I can think of some tricks that suggest there may be a solution, although I have not found one.

For example, you could shift the values up to the top of the range of 32-bit integers. The idea is to have some of them "overflow" to negative numbers. This breaks the sequence into two pieces, rather like the excluded value. But I don't see a way to extend this idea to a solution to the original puzzle.


Floyd(Posted 2007) [#8]
Got it !

' The idea is to generate equally spaced double precision
' numbers with a gap very slightly larger than 1. Values are
' converted to integer with Floor.

' The gap must be carefully chosen so that excl is missed.

' Suppose the numbers were 3.97, 4.99, 6.01, 7.03, where the gap is 1.02.
' The Floor values are 3, 4, 6, 7 and the value 5 has been skipped.

' Assumes reasonable values: low <= excl <= high   and   low < high.

Function RandEx( low , high , excl )
	Return  Floor( excl + Rand( 1 + low - excl , high - excl ) * ( 1 + 1! / 2 ^ 34 ) - 1! / 2^35 )
End Function




H&K(Posted 2007) [#9]



TaskMaster(Posted 2007) [#10]
*points at H&K*

Cheater, cheater, cheater...

Cheater, cheater, cheater...

H&K??? Heckler and Koch???


H&K(Posted 2007) [#11]
Hugs and Kisses.

Not cheating,
1) Works,
2) Comforms with condition "Main limitation is that you only allowed to enter code in one sting after "Return"


TaskMaster(Posted 2007) [#12]
Yeah, but I am guessing that the private function isn't part of one "sting" after return. But, I am not sure what a "sting" is, so I could be way off base... :)


jhans0n(Posted 2007) [#13]
Function RandExcept(v1, v2, ev)
 Return Int(Trim(Replace(" "+String(Rand(v1, v2-1))+" ", " "+String(ev)+" ",String(v2))))
End Function


Pretty? No. Works? Seems to.

To explain, it generates a random number from v1 to v2 minus one. Then it turns that into a string, and replaces any instance of ev with v2. I put in spaces around the random number and the replace string just in case the ev was 5 and the randomly generated number was 50. Then it strips off the spaces and turns it back into an int.


Koriolis(Posted 2007) [#14]
Function RandExcept(v1, v2, ev)
	Return [Rand(v1, ev-1), Rand(ev+1,v2)][Rand(v1,v2-1)>=ev]
End Function

Pretty? I think so.
Works? Yep.

;)

The main trick here is to use auto arrays and array indexing to select one value among two possibles ones, based on a third parameter (exactly like the ternary operator in C).
Then all you have to do is:
- generate two random values in the first (v1 to ev-1) and second (ev+1 to v2) range
- select between these two values, based on a random value that can be 0 or 1 and with a probability (of being one or the other) that matches the relative sizes of the two ranges.


Czar Flavius(Posted 2007) [#15]
Function RandExcept(v1, v2, ex)
	Local result = Rand(v1, v2-1)
	If result = ex Then result = v2
	Return result
End Function


Not as good as those others I know, but I wanted a go ;)


TaskMaster(Posted 2007) [#16]
Yep, but he said it had to all be one line on the return line...

In other words:

Function RandExcept(v1, v2, ev)
Return ' YOUR CODE MUST BE RIGHT HERE ONLY ON THIS LINE
End Function


Czar Flavius(Posted 2007) [#17]
Function RandExcept(v1, v2, ex)
	Local result = Rand(v1, v2-1); If result = ex Then result = v2; Return result;
End Function

;)


H&K(Posted 2007) [#18]
lol


Perturbatio(Posted 2007) [#19]
' Your code must be only here in this line after Return


:(


jhans0n(Posted 2007) [#20]
Koriolis, yours is definitely much prettier than mine, but I think Czar Flavius beats us both. :)


Gabriel(Posted 2007) [#21]
Ah, but which version is faster? ( No, don't test it, I was being facetious :P )


jhans0n(Posted 2007) [#22]
I guarantee mine is the slowest, and Czar Flavius's is the fastest.


Matt Merkulov(Posted 2007) [#23]
Floyd, Koriolis: (cheers) :)

jhanson: unfortunately, the chances of returned numbers appearance are not equal.

And here's my variant, based on strings also:

For n = 0 To 19
	res1$ = res1$ + RandExcept(0, 5, 5) + ", "
	res2$ = res2$ + RandExcept(0, 5, 3) + ", "
	res3$ = res3$ + RandExcept(-3, 2, -1) + ", "
Next
Print "Test 1, from 0 to 5 except 5: " + res1$
Print "Test 2, from 0 to 5 except 3: " + res2$
Print "Test 3, from -3 to 2 except -1: " + res3$

Function RandExcept(v1, v2, ev)
	Return Mid$(Rand(v1, ev - 1) + "            " + Rand(ev + 1, v2), 12 * (Rand(v1,v2 - 1) >= ev)).ToInt()
End Function



jhans0n(Posted 2007) [#24]
Matt Merkulov: They absolutely are equal in my solution. If you have a range of 1 to 5, and you want to skip 3, you should have a 25% chance of getting 1, 2, 4, or 5. My solution generates a random number from 1 to 4 (25% chance of each) and replaces all of the 3's with 5's. If it got any more equal than that, my head would explode.


Matt Merkulov(Posted 2007) [#25]
Oh sorry, I missed this. You're right.