Jump to content
IGNORED

Decided to play :)


8bitclassics

Recommended Posts

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

 

  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 List

screenheight 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)

Link to comment
Share on other sites

--- Unresolved Symbol List

screenheight 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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 by batari
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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 by batari
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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. :D 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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

 

post-7456-1173923160_thumb.jpg

aquarium.bas

aquarium.bas.bin

Edited by SeaGtGruff
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...