+batari Posted March 11, 2007 Share Posted March 11, 2007 The standard random number generator isn't great, but it does have an even distribution. One problem with the methods above for limiting the range is that neither will give an even distribution. Doug's method will give a mound-like probability distribution, while Michael's will be stepped, with smaller values preferred. This might not matter for a game, but I thought it was worth mentioning. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 11, 2007 Share Posted March 11, 2007 Thanks for the posts, will look them over and see if they help my problem. Can this be used to set up players so they don't cross paths? The second version I posted of the get_rand function works for finding a random number between X and Y, where 0 <= X <= Y <= 255, and Y - X < 255. For example, n = get_rand (0, 254) is okay, and n = get_rand (1, 255) is okay, but n = get_rand (0, 255) will not work. But the disadvantage of using any kind of loop (in this case, a subtraction loop) is that the number of cycles could vary quite a bit depending on how many times the loop is repeated. And of course, an "if" statement will usually also cause the execution time to vary a bit. It might be possible to optimize the get_rand function for smaller ranges, to keep the number of iterations to a minimum. As for keeping multiple players from crossing paths, yes, you could do that, because user-defined bB functions can use variables-- even array elements-- for their arguments. But you'll probably want to restrict each player to a certain range of rows, otherwise a given player's initial position and target position could severely limit the initial positions and target positions of the other players. How many players are you planning to move around this way? Michael Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 11, 2007 Author Share Posted March 11, 2007 Well right now I am using all of the sprites in the multikernal, Player0 thru Player5. Pretty much they just go back and forth with some variations of height. As for how true it needs to randomize, as longs as it can simulate it (make it appear to be random even if it is selecting on of say 10 or 20 pre-selected positions) Of course, true randomization would be best, but whatever would work. This brings up another question, any way to get Player1 - Player5 to display in front of Player0? I have Player0 as a tall image and using that because it doesn't cause flickering with the other Player graphics. But all the others will go behind it when passing through and would like some to go in front if possible. Corey Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 11, 2007 Share Posted March 11, 2007 The standard random number generator isn't great, but it does have an even distribution. One problem with the methods above for limiting the range is that neither will give an even distribution. Doug's method will give a mound-like probability distribution, while Michael's will be stepped, with smaller values preferred. This might not matter for a game, but I thought it was worth mentioning. Yes, if the number of values in the desired range doesn't evenly divide into 255, then the remainder will wrap around to the smaller values, so those values will have a slightly higher probability of being returned. But the difference shouldn't be large enough to matter much. For example, suppose the desired range is 10 to 30. The rand function will return a pseudo-random value from 1 to 255, each value having a 1-in-255 chance of being returned. Calling get_rand(10,30) will first adjust the desired range so it's 1 to 21, and the values returned by rand will be divided up as follows: 1/22/43/64/85/106/127/148/169/190/211/232/253 --> 1 (13-in-255, or 5.098%) 2/23/44/65/86/107/128/149/170/191/212/233/254 --> 2 (13-in-255, or 5.098%) 3/24/45/66/87/108/129/150/171/192/213/234/255 --> 3 (13-in-255, or 5.098%) 4/25/46/67/88/109/130/151/172/193/214/235 --> 4 (12-in-255, or 4.706%) 5/26/47/68/89/110/131/152/173/194/215/236 --> 5 (12-in-255, or 4.706%) etc. 21/42/63/84/105/126/147/168/189/210/231/252 --> 21 (12-in-255, or 4.706%) Then the value would be adjusted to fall within the original range of 10 to 30, so 10 to 12 would have a 5.098% chance of being returned, and 13 to 30 would have a 4.706% chance of being returned. The worst-case scenario would be something like get_rand(1,250), in which case 1 to 5 would have a 0.784% (2-in-255) chance of being returned, and 6 to 250 would have a 0.392% (1-in-255) chance of being returned-- in other words, 1 to 5 would be twice as likely to be returned as 6 to 250 would. The only thing I can think of to get around that would be to toss out any of the "remainder" values: function get_rand rem *** temp1 and temp2 are used by * and /, so we need to save them temp3 = temp1 temp4 = temp2 temp4 = temp4 - temp3 + 1 temp5 = 255 / temp4 temp5 = temp4 * temp5 get_rand_loop1 temp6 = rand if temp6 > temp5 then get_rand_loop1 get_rand_loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto get_rand_loop2 temp6 = temp6 + temp3 - 1 return temp6 end This should keep the number of unnecessary rand calls to a minimum (so the whole rand sequence doesn't start repeating itself any sooner than necessary), while also preserving an ideal distribution where each value has an equal chance of being picked. But it still uses a lot of cycles, and the number of cycles used could vary quite a bit. Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 11, 2007 Share Posted March 11, 2007 This brings up another question, any way to get Player1 - Player5 to display in front of Player0? I have Player0 as a tall image and using that because it doesn't cause flickering with the other Player graphics. But all the others will go behind it when passing through and would like some to go in front if possible. Players 1 through 5 use GRP1, and player 0 uses GRP0. The VCS will always draw GRP0 on top of GRP1 wherever they overlap. So the "only" way to have players 1 through 5 be drawn on top of player 0 is to modify the multisprite kernel so that players 1 through 5 use GRP0, and player 0 uses GRP1-- which is certainly doable. But an alternative would be to temporarily swap the graphics, color, and x/y position of player 0 with one of the other players whenever their positions would be overlapping and you want player 1 through 5 to be drawn on top (if you see what I mean?). Michael Quote Link to comment Share on other sites More sharing options...
potatohead Posted March 11, 2007 Share Posted March 11, 2007 Yep, you do get mounds with the quickie and method. Never thought about it though. Seemed to work well enough for me. It might explain needing to move the random requests around in code though... Never thought about that aspect of things. If the gameplay reaches a state where this kind of stuff actually matters that much, there is a strong case for some reconsideration. --or make it an element of the game, sharp players can pick up on! Whatever works! I am liking this thread, btw. Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 13, 2007 Author Share Posted March 13, 2007 function get_rand rem *** temp1 and temp2 are used by * and /, so we need to save them temp3 = temp1 temp4 = temp2 temp4 = temp4 - temp3 + 1 temp5 = 255 / temp4 temp5 = temp4 * temp5 get_rand_loop1 temp6 = rand if temp6 > temp5 then get_rand_loop1 get_rand_loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto get_rand_loop2 temp6 = temp6 + temp3 - 1 return temp6 end When I add the code and compile, I get the following: --- Unresolved Symbol Listscreenheight 0000 ???? (R ) mul8 0000 ???? (R ) div8 0000 ???? (R ) Fatal assembly error: Source is not resolvable. I put the function below initial set commands and I have the lines to retrieve the get_rand: player1x=get_rand(10,30) player1y=get_rand(10,30) Quote Link to comment Share on other sites More sharing options...
Dan Iacovelli Posted March 13, 2007 Share Posted March 13, 2007 check for sytax errors it's pretty sensitive when it comes to sytax(spaces etc) Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 13, 2007 Author Share Posted March 13, 2007 That is the only code, first part is a direct copy and past from the above post, and the two other lines are correct. I removed and compiled correctly. Quote Link to comment Share on other sites More sharing options...
+batari Posted March 13, 2007 Share Posted March 13, 2007 --- Unresolved Symbol Listscreenheight 0000 ???? (R ) mul8 0000 ???? (R ) div8 0000 ???? (R ) Fatal assembly error: Source is not resolvable. This means you need the div_mul.asm module. Put "include div_mul.asm" near the beginning of your code to fix this. Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 13, 2007 Author Share Posted March 13, 2007 This means you need the div_mul.asm module. Put "include div_mul.asm" near the beginning of your code to fix this. Ok, this fixes the compiling issue, but the screen is just blank now. Tried it both in Z26 and Stella. Tried some different numbers in the get_rand, still nothing. Removed the get_rand function and comes up. Quote Link to comment Share on other sites More sharing options...
+batari Posted March 14, 2007 Share Posted March 14, 2007 (edited) This means you need the div_mul.asm module. Put "include div_mul.asm" near the beginning of your code to fix this. Ok, this fixes the compiling issue, but the screen is just blank now. Tried it both in Z26 and Stella. Tried some different numbers in the get_rand, still nothing. Removed the get_rand function and comes up. I haven't examined the routine in great detail, but right now I see that if temp5 or temp4 is zero when entering your loops, they will repeat forever. EDIT: Or, certain values of temp6 and temp4 will also cause the other loop to repeat endlessly. Edited March 14, 2007 by batari Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 14, 2007 Author Share Posted March 14, 2007 I haven't examined the routine in great detail, but right now I see that if temp5 or temp4 is zero when entering your loops, they will repeat forever. In this line: get_rand(10,30) Wouldn't temp1 be 10 (so would temp3), temp2 would be 30 (also with temp4). Temp4 = temp4 - temp3 + 1 = 21. Temp5 = 255 / 21 = 12 (rounded down from 12.14...) Then Temp5(252) = Temp4 (21) * Temp5 (12). Or is Temp1 and Temp2 coming from something else? Corey Quote Link to comment Share on other sites More sharing options...
+batari Posted March 14, 2007 Share Posted March 14, 2007 (edited) One thing I just noticed is that you have an "end" at the end of your function. These aren't needed for functions. Aside from that, I haven't a clue why it doesn't work, as I've tried compiling and running it and the routine works for (10,30). Edited March 14, 2007 by batari Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2007 Share Posted March 14, 2007 I haven't examined the routine in great detail, but right now I see that if temp5 or temp4 is zero when entering your loops, they will repeat forever. In this line: get_rand(10,30) Wouldn't temp1 be 10 (so would temp3), temp2 would be 30 (also with temp4). Temp4 = temp4 - temp3 + 1 = 21. Temp5 = 255 / 21 = 12 (rounded down from 12.14...) Then Temp5(252) = Temp4 (21) * Temp5 (12). Or is Temp1 and Temp2 coming from something else? Corey bB uses the temp variables when you call a user-defined function, so if you say n=get_rand(10,30), then temp1 will be 10 and temp2 will be 30. However, bB also uses temp1 and temp2 when it does multiplication and division, but this function includes some multiplication and division. Consequently, we need to store the values of temp1 and temp2 in some other variables before we get to the lines that contain the multiplication and/or division. We could use some user variables (a through z), but I was trying to avoid that, so I set temp3 to temp1, and temp4 to temp2: Call the function: temp1 = 10 temp2 = 30 Store temp1 and temp2 before * and / obliterate them: temp3 = temp1 = 10 temp4 = temp2 = 30 The built-in rand function returns a value from 1 to 255, but we want something between X and Y (not the user variables x and y, but two user-defined values-- call them LOW and HIGH if you wish). The easiest way to do this (besides just looping back until rand returns something in that range) is to revise the range so it's from 1 to something, as follows: Change the range: temp4 = temp4 - temp3 + 1 = 30 - 10 + 1 = 20 + 1 = 21 So now the range is from 1 to 21 (we won't worry about the lower value, we'll just focus on the upper value). To keep the possible values evenly distributed (instead of possibly being stepped in favor of lower values), we calculate the maximum multiple of temp4 that is less than or equal to 255, by dividing 255 by temp4, then multiplying the result by temp4: Find the highest multiple of temp4 that's less than or equal to 255: temp5 = 255 / temp4 = 255 / 21 = 12.142857 = 12 (the fractional part gets dropped by bB) temp5 = temp4 * temp5 = 21 * 12 = 252 So now we're looking for a value between 1 and 252, because this will give an equal distribution. In other words, we still want a number between 1 and 21, but if we use 1 to 252, and then reduce the result by using repeated subtraction, then each value between 1 and 21 can occur 12 times. So first we call rand until the result is from 1 to 252: loop1 temp6 = rand : if temp6 > temp5 then loop1 Now that we've found a number between 1 and 252, without having to call rand any more times than absolutely necessary, we want to reduce the random value until it's within the range 1 to 21: loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto loop2 For example, if temp6 was 22, then 22 - 21 = 1. Or, if temp6 was 252, then 252 - 21 = 231 231 - 21 = 210 210 - 21 = 189 189 - 21 = 168 168 - 21 = 147 147 - 21 = 126 126 - 21 = 105 105 - 21 = 84 84 - 21 = 63 63 - 21 = 42 42 - 21 = 21 So after subtracting temp4 from temp6 as many times as needed, we now have some random value between 1 and 21, with each value having an equal possibility of having been picked. But before we return the value, we need to adjust it again so it's within the actual desired range (in this case, 10 to 30): temp6 = temp6 + temp3 - 1 For example, if we ended up with temp6 = 1 (the lowest value in the temporary range), then temp6 = temp6 + temp3 - 1 = 1 + 10 - 1 = 11 - 1 = 10 Or, if temp6 ended up as 21 (the highest value in the temporary range), then temp6 = temp6 + temp3 - 1 = 21 + 10 - 1 = 31 - 1 = 30 So no matter what value we got for temp6, we've just adjusted it so it's between 10 and 30. As I mentioned in my post, you *CANNOT* use get_rand(0,255), or you'll break it: temp1 = 0 temp2 = 255 temp3 = temp1 = 0 temp4 = temp2 = 255 temp4 = temp4 - temp3 + 1 = 255 - 0 + 1 = 255 + 1 = 256 = 0 temp5 = 255 / temp4 = 255 / 0 = undefined! However, you *can* use get_rand(0,254), because then the adjusted range becomes 1 to 255-- or you can use get_rand(1,255). Any two values will work, as long as their difference is less than or equal to 254, such that adding 1 to their difference won't exceed 255. Well, you also wouldn't want to use something like n=get_rand(4,4), because that would be silly (why not just set n to 4 in the first place?. It should work, but the modified range would be 1 to 1, so no matter what value rand gives you, you'd end up reducing it down to 1, then readjusting it to 4. And as I mentioned in my post, the numbers should be (low,high), so you wouldn't want to use something like n=get_rand(10,3)-- instead, switch it around to be n=get_rand(3,10). I might not have said it in so many words, but here's where I mentioned the restrictions: 0 <= X <= Y <= 255, and Y - X <= 254 In other words, X should not be greater than Y, and their difference should not exceed 254-- this is assuming that X is listed first, or n=get_rand(X,Y). I'm not saying it's the best way to do things, but it does provide a generic function that will return a (pseudo)random value between (almost) any two 1-byte values. And yes, I forgot to mention that you need to add include div_mul.asm to your program if you want to use this function. Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2007 Share Posted March 14, 2007 The second version I posted of the get_rand function works for finding a random number between X and Y, where 0 <= X <= Y <= 255, and Y - X < 255. For example, n = get_rand (0, 254) is okay, and n = get_rand (1, 255) is okay, but n = get_rand (0, 255) will not work. Oh well, I actually said Y - X < 255, not Y - X <= 254. Same difference. I used end at the end because that's what the example in the documentation showed. So you're saying that the return statement will terminate it? What if there are multiple return statements? a = lowest(b,c,d) rem *** find the lowest of three values function lowest if temp1 < temp2 then if temp1 < temp3 then return temp1 if temp2 < temp1 then if temp2 < temp3 then return temp2 if temp3 < temp1 then if temp3 < temp2 then return temp3 end Michael Quote Link to comment Share on other sites More sharing options...
+batari Posted March 14, 2007 Share Posted March 14, 2007 I think I might have figured out a possible issue. If we call getrand(a,b) and a=b or a=b-1, we'll get an infinite loop. So here's the fix: function get_rand rem *** temp1 and temp2 are used by * and /, so we need to save them temp3 = temp1 temp4 = temp2 temp4 = temp4 - temp3 + 1 if temp4<=1 then return temp1 temp5 = 255 / temp4 temp5 = temp4 * temp5 get_rand_loop1 temp6 = rand if temp6 > temp5 then get_rand_loop1 get_rand_loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto get_rand_loop2 temp6 = temp6 + temp3 - 1 return temp6 Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2007 Share Posted March 14, 2007 I think I might have figured out a possible issue. If we call getrand(a,b) and a=b or a=b-1, we'll get an infinite loop. get_rand(4,5) t1=4 t2=5 t3=t1=4 t4=t2=5 t4=t4-t3+1=5-4+1=1+1=2 (so new range is 1 to 2) t5=255/2=127.5=127 t5=t4*t5=2*127=254 t6=rand etc. Sorry, I'm not seeing it. But even so, this function isn't really cycle-effecient for very small ranges, so for something like get_rand(0,1) it would be better to do get_rand(0,254) and then use a bitmask or something. And as I said, if you call get_rand(a,b) where a=b, that would be just silly-- "Give me a random number between 5 and 5," etc. Check first to make sure a and b aren't equal-- if they are then set c to a instead of calling c=get_rand(a,b). So here's the fix: function get_rand rem *** temp1 and temp2 are used by * and /, so we need to save them temp3 = temp1 temp4 = temp2 temp4 = temp4 - temp3 + 1 if temp4<=1 then return temp1 temp5 = 255 / temp4 temp5 = temp4 * temp5 get_rand_loop1 temp6 = rand if temp6 > temp5 then get_rand_loop1 get_rand_loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto get_rand_loop2 temp6 = temp6 + temp3 - 1 return temp6 I'll look it over tonight after work. Thanks for posting it! Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2007 Share Posted March 14, 2007 Okay, I just glanced at it, the only situations this handles is a=b or b-a=255. Which is great, now those situations don't break it-- but b-a=1 was okay all along, since that would give you temp4=2. Michael Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 14, 2007 Author Share Posted March 14, 2007 I've changed the code and it still does the same thing. I have removed the get_rand from the player1y line that I had it in for testing and it still does the same thing. I remove the code and the program loads fine. I thought it might be because I ran out of memory (only 4K), but it says it it has 1516 bytes free. If I change the screenheight, it will show white scan lines. Thanks for the help Corey Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 15, 2007 Share Posted March 15, 2007 I've changed the code and it still does the same thing. I have removed the get_rand from the player1y line that I had it in for testing and it still does the same thing. I remove the code and the program loads fine. I thought it might be because I ran out of memory (only 4K), but it says it it has 1516 bytes free. If I change the screenheight, it will show white scan lines. Thanks for the help Corey If you post a copy of your code, we can see if we can find the problem. Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 15, 2007 Share Posted March 15, 2007 If temp4-temp3+1=0, it would imply that temp4-temp3=255, in which case I think a better fix would be to use (1,255) instead of just returning temp1. Here's a revision that tries to compensate for all of the odd contingencies, since calling get_rand with variables implies that you don't know what the two values in the range are, so they could be equal, or could be (greater,lesser), or could be (0,255): function get_rand if temp1 = temp2 then return temp1 rem *** temp1 and temp2 are used by * and /, so we need to save them if temp1 < temp2 then temp3 = temp1 : temp4 = temp2 else temp3 = temp2 : temp4 = temp1 temp4 = temp4 - temp3 + 1 if temp4 = 0 then temp3 = 1 : temp4 = 255 temp5 = 255 / temp4 temp5 = temp4 * temp5 get_rand_loop1 temp6 = rand if temp6 > temp5 then get_rand_loop1 get_rand_loop2 if temp6 > temp4 then temp6 = temp6 - temp4 : goto get_rand_loop2 temp6 = temp6 + temp3 - 1 return temp6 end I tried it with various "previously bad" parameters-- (0,255), (4,4), (10,5), etc.-- and it seems to work okay now. Michael Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 15, 2007 Author Share Posted March 15, 2007 If you post a copy of your code, we can see if we can find the problem. Michael Here is my code. I changed the get_rand function to your latest post. Corey aquarium.bas Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 15, 2007 Share Posted March 15, 2007 (edited) If you post a copy of your code, we can see if we can find the problem. Michael Here is my code. I changed the get_rand function to your latest post. Corey One problem I see right away is that you put the get_rand function at the beginning of the program code, which is bad. A user-defined function is basically a special kind of subroutine, and like any other subroutine it should probably go at the end of your code-- or you at least need some code to "jump over" it to get to where your real code begins. Try the version attached below, it works fine for me (I just moved get_rand to the bottom of the program). Very nice screen by the way! Michael aquarium.bas aquarium.bas.bin Edited March 15, 2007 by SeaGtGruff Quote Link to comment Share on other sites More sharing options...
8bitclassics Posted March 15, 2007 Author Share Posted March 15, 2007 Thanks, changed and it loads. Testing the randomness of it right now. I thought I read that the function needed to be at the top above the code (or I thought I did) so that is why I put it there. Corey Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.