RandExcept (rifddle)
BlitzMax Forums/BlitzMax Beginners Area/RandExcept (rifddle)
| ||
| 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 :) |
| ||
| If you want Rand(3,9) except 5 then use Rand(3,8) and add 1 if result is at least 5. |
| ||
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
|
| ||
| 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. |
| ||
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! |
| ||
| Oh, read over that. Is there any reason for this (kind of strange) limitation you set yourself? |
| ||
| 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. |
| ||
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 |
| ||
| |
| ||
| *points at H&K* Cheater, cheater, cheater... Cheater, cheater, cheater... H&K??? Heckler and Koch??? |
| ||
| 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" |
| ||
| 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... :) |
| ||
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. |
| ||
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. |
| ||
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 ;) |
| ||
| 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 |
| ||
Function RandExcept(v1, v2, ex) Local result = Rand(v1, v2-1); If result = ex Then result = v2; Return result; End Function ;) |
| ||
| lol |
| ||
| ' Your code must be only here in this line after Return :( |
| ||
| Koriolis, yours is definitely much prettier than mine, but I think Czar Flavius beats us both. :) |
| ||
| Ah, but which version is faster? ( No, don't test it, I was being facetious :P ) |
| ||
| I guarantee mine is the slowest, and Czar Flavius's is the fastest. |
| ||
| 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 |
| ||
| 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. |
| ||
| Oh sorry, I missed this. You're right. |