abaudrand Posted July 5, 2012 Share Posted July 5, 2012 I'm trying to use the on gosub function but I only got Syntax error on the first line of gosub. Is it coming from my old XP version of batari basic? rem ' Rolling Dice1 a=rand(&5) on a gosub Data1 Data2 Data3 Data4 Data5 Data6 var15=c:var16=d rem ' Rolling Dice2 if equal to Dice1, cast Dice again RollingDice2 b=rand(&5) on b gosub Data1 Data2 Data3 Data4 Data5 Data6 var17=c:var18=d if var17=var15 && var18=var16 then goto RollingDice2 Data1 c=%11101000 d=%01101000 return Data2 c=%01010000 d=%00001001 return Data3 c=%00101100 d=%00001100 return Data4 c=%00111000 d=%00110100 return Data5 c=%01110000 d=%01110100 return Data6 c=%00100000 d=%00000100 return Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted July 5, 2012 Share Posted July 5, 2012 (edited) Did you try printing b to the score before executing the on .. gosub? It could help in debugging. UPDATE: Fooling around I think rand(&5) should be (rand&5) Edited July 5, 2012 by theloon Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 yes the random is not well written but i v e tried to use a number instead and the compilation still fail on the first gosub line... Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 rebooting on XP to try Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 I ve corrected the random argument but its still failing on my side... Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 im in chatroom Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted July 5, 2012 Share Posted July 5, 2012 I got this to compile in bB 1.0 in Vista 32-bit rem ' Rolling Dice1 a=(rand&5) on a gosub Data1 Data2 Data3 Data4 Data5 Data6 var15=c:var16=d rem ' Rolling Dice2 if equal to Dice1, cast Dice again RollingDice2 b=(rand&5) on b gosub Data1 Data2 Data3 Data4 Data5 Data6 var17=c:var18=d if var17=var15 && var18=var16 then goto RollingDice2 Data1 c=%11101000 d=%01101000 return Data2 c=%01010000 d=%00001001 return Data3 c=%00101100 d=%00001100 return Data4 c=%00111000 d=%00110100 return Data5 c=%01110000 d=%01110100 return Data6 c=%00100000 d=%00000100 return Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 Damn, it doesn't work on my version... guess the on ... gosub statement was fixed with the latest release... should I upgrade to latest version on XP or not, that is the question.... Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 could you give me the ASM it compile, maybe I could include it and start to play a little with inline ASM? Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 5, 2012 Share Posted July 5, 2012 Try using bBWin7_64bit.zip that is posted here: http://www.atariage.com/forums/topic/123849-visual-bb-1-0-a-new-ide-for-batari-basic/ See if the program works for you using that version of bB. Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 5, 2012 Author Share Posted July 5, 2012 got XP and the latest build 554... so I donno what could mess up... got networkframe3, changed the 2600bas file to the latest one... Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted July 6, 2012 Share Posted July 6, 2012 (edited) I don't think rand&5 is going to give you what you think; it can never be 2 or 3. You might want to use a loop, like this: a = rand reduce_a if a > 5 then a = a - 6 : goto reduce_a That isn't as fast as using &, but it will give you a random number from 0 to 5 with a pretty good distribution-- the likelihood of rolling 0, 4, or 5 will be 42 out of 255, and the likelihood of rolling 1, 2, or 3 will be 43 out of 255. If on...gosub doesn't work with the version of bB you're using, you can use on...goto to accomplish the same thing, like this: rem ' Rolling Dice1 a=rand reduce_a if a>5 then a=a-6:goto reduce_a gosub check_a var15=c:var16=d rem ' Rolling Dice2 if equal to Dice1, cast Dice again RollingDice2 b=rand reduce_b if b>5 then b=b-6:goto reduce_b gosub check_b if b=a then goto RollingDice2 var17=c:var18=d check_a on a goto Data1 Data2 Data3 Data4 Data5 Data6 check_b on b goto Data1 Data2 Data3 Data4 Data5 Data6 Data1 c=%11101000 d=%01101000 return Data2 c=%01010000 d=%00001001 return Data3 c=%00101100 d=%00001100 return Data4 c=%00111000 d=%00110100 return Data5 c=%01110000 d=%01110100 return Data6 c=%00100000 d=%00000100 return Edited July 6, 2012 by SeaGtGruff Quote Link to comment Share on other sites More sharing options...
abaudrand Posted July 6, 2012 Author Share Posted July 6, 2012 thanks SeaGtGruff... I didnt knew the trouble with random yet I ve noticed some result barely go out but didnt knew why . I'm far from computer till next week so I could not try it for the moment but yes, I was going to a goto solution yet not as good as yours. Quote Link to comment Share on other sites More sharing options...
potatohead Posted July 6, 2012 Share Posted July 6, 2012 The AND (&) function is a bit mask. What it does is only output a 1, if both the numbers involved also contain a 1, otherwise it outputs 0. AND is good for powers of two: 1, 11, 111, 1111, etc... When used this way, it will mask off all the extra digits, clipping a larger number to a smaller set of values. If you want just a single digit, 0 or 1, then you use & 1 If you want the numbers 0 to 3, then you use & 11 For the numbers 0 to 7, you use & 111 The numbers 0 - 15 are done with & 1111 Take each power of 2, and subtract one from it. 2, 4, 8, 16 become 1, 2, 7, 15, etc... Any other numbers will not produce all the values, because not all the digits contain a 1. Using & 4, for example would produce the numbers 0 and 4, that's it, because the binary is 100, leaving only two choices. If you want the numbers 1 through 4, you can use & 3, then add one. In this program, the numbers 0 through 5 are needed for the on gosub. Use the next highest power of two, which is 8, subtract one, arriving at & 7. Now you have the numbers 0 through 7. Use an "if, then" statement to quickly check for the number being larger than 5, and if so, loop back and pick another number. rand_loop a = (rand & 7) if (a > 5) goto rand_loop Or... You can stack a couple of random number ranges together. Say you want a range from 0 to 13. You could take (rand&7)+(rand&3)+(rand&3) and get there too. Smallest number is 0, largest is (7+3+3) 13. Different methods bias the numbers in various ways. Adding several smaller random numbers together to get a larger one will produce a different kind of random than picking from the next largest power of two number and looping until one is obtained in the range will. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted July 7, 2012 Share Posted July 7, 2012 I've been thinking about the random number problem-- specifically, a random number from 1 to 6 (i.e., rolling a 6-sided die). The challenge is to come up with a method that always takes the same amount of time-- preferably as short as possible-- and gives an equal distribution for each possible value. I don't especially care for the bit-masking method, because bB's rand statement returns a value from 1 to 255, so (if I'm not mistaken) masking the bits can't give an equal distribution-- plus, you're limited to values from 0 to 2^n-1, which doesn't work for 1 to 6 anyway. I think the best method for generating a number from 1 to 6 is to reduce the result so it falls within 1 to 6-- but a repeated subtraction loop will take a variable amount of time, plus you have three values left over (253 reduces to 1, 254 reduces to 2, and 255 reduces to 3). I've come up with a solution that uses a lookup table instead of a loop so the reduction always takes the same amount of time. And since there are three extra values, and 6 is a multiple of 3, it uses two tables instead of one. Thus, the first table reduces rand to a number from 1 to 6, with an extra chance of getting 1, 2, or 3; and the second table also reduces rand to a number from 1 to 6, but with an extra chance of getting 4, 5, or 6. This is more or less a lookup table with 510 values (255+255=510), which is a multiple of 6 (510/6=85), so each value occurs exactly 85 times. But since we can't have a lookup table greater than 256 bytes, the 510 values are split into two separate lookup tables, and you have to alternate between them. This has the disadvantage of requiring 512 bytes for the two lookup tables, plus extra variables for keeping track of which table to use; but it has the advantage of always taking the same amount of time and giving an equal distribution for the six possible values. Here's a sample program to demonstrate the idea. It simulates rolling two 6-sided dice, and shows the results in the score. Since either die could have the same value as its previous value, the score alternates between yellow and blue each time the dice are rolled, just to indicate that the dice were rolled. And since rand gives 255 values-- an odd number-- and is used twice when rolling the dice, each die should cycle through all 255 possible values before the combinations start to repeat in the same sequence. But since the program alternates between two lookup tables, this should actually come out to 510 iterations before the combinations of reduced values start to repeat the same sequence over again. This method could be used with other ranges, but the number of lookup tables might be different, since any remainders would need to be multipled to get equal distributions. And it goes without saying that this method is specifically for a number of values that isn't a power of 2. rem * generate a random number from 1 to 6 with equal chances dim die1 = a dim die2 = b dim roll1 = c dim roll2 = d dim counter = e rem * roll1 and roll2 are used to track whether to use table0 or rem * table1 when looking up the mod 6 value for die1 and die2 scorecolor=$14 loop if counter = 0 then gosub rolldice drawscreen counter=counter+1:counter=counter&63 goto loop rolldice rem * roll the first die temp1=rand roll1=roll1^1 if roll1=0 then die1=table0[temp1] else die1=table1[temp1] rem * roll the second die temp1=rand roll2=roll2^1 if roll2=0 then die2=table0[temp1] else die2=table1[temp1] score=0 for temp1=1 to die1:score=score+1000:next for temp1=1 to die2:score=score+1:next scorecolor=scorecolor+128 return data table0 0,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1 2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3 4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5 6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1 2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3 4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5 6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1 2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3 end data table1 0,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 end Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 7, 2012 Share Posted July 7, 2012 So a = (rand/64) + (rand/64) isn't good enough? www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#rand Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted July 7, 2012 Share Posted July 7, 2012 So a = (rand/64) + (rand/64) isn't good enough? Well, rand/64 will give 0, 1, 2, or 3, so (rand/64)+(rand/64) will give 0 through 6-- not 1 through 6. Not only are you calling rand twice to get one number, but if you actually want 1 through 6 then you'll need to loop back and try again, so that means you might be calling rand four times, or six times, or eight times, etc.-- plus, the loop will take a variable amount of time. I was trying to figure out a way to keep the amount of time constant and ensure an absolutely equal distribution of results, and that was the best I could come up with. I'm not saying it's the best way, or that anyone should do it that way-- it's just the best way I could think of so far. Note, you could also randomize the two lookup tables, rather than just listing 1 through 6 over and over as I did-- just make sure you have 85 instances of each digit. Or if you actually wanted 0 through 5, then change the values to 0 through 5. Also, keep in mind that the first value in the two lookup tables is just a garbage value, since rand will never equal 0-- unless you *set* it to 0 and "break" the rand function. You need it to make the tables 256 bytes, but you could also overlap the two tables so the 0th value of the second table is the 255th value of the first table. On the other hand, it's probably best to keep each table 256 bytes to avoid page-crossing situations. I didn't align the tables to page boundaries-- I assumed bB would do it automatically. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 7, 2012 Share Posted July 7, 2012 So a = (rand/64) + (rand/64) isn't good enough? Well, rand/64 will give 0, 1, 2, or 3, so (rand/64)+(rand/64) will give 0 through 6-- not 1 through 6. Not only are you calling rand twice to get one number, but if you actually want 1 through 6 then you'll need to loop back and try again, so that means you might be calling rand four times, or six times, or eight times, etc.-- plus, the loop will take a variable amount of time. Oops. I forgot something. In his first example, he needed 0 through 5 for an on-gosub (6 numbers). What I posted gives 0 through 6 (7 numbers). I'd never loop back to get another number, so what about this: a = (rand/64) + (rand/128) + (rand/128) That should give a random number between 0 and 5 (6 numbers). Does rand and division use too many cycles? Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted July 7, 2012 Share Posted July 7, 2012 Oops. I forgot something. In his first example, he needed 0 through 5 for an on-gosub (6 numbers). What I posted gives 0 through 6 (7 numbers). I'd never loop back to get another number, so what about this: a = (rand/64) + (rand/128) + (rand/128) That should give a random number between 0 and 5 (6 numbers). Does rand and division use too many cycles? That would work, but division uses a loop so it takes a variable amount of time, plus I'm not sure how the distribution will be, although I'm pretty sure it won't be even. I checked, and bB doesn't align data statements to page boundaries, plus it adds a JMP before each data set, so the number of bytes used is actually the length of the table plus 3. As long as you don't care about page crossings, my previous example can be made more compact by overlapping table0 with the return of the subroutine, and then overlapping table1 with most of table0, as follows, thus reducing the total table size to just 258 bytes: rem * generate a random number from 1 to 6 with equal chances dim die1 = a dim die2 = b dim roll1 = c dim roll2 = d dim counter = e rem * roll1 and roll2 are used to track whether to use table0 or rem * table1 when looking up the mod 6 value for die1 and die2 scorecolor=$14 loop if counter = 0 then gosub rolldice drawscreen counter=counter+1:counter=counter&63 goto loop rolldice rem * roll the first die temp1=rand roll1=roll1^1 if roll1=0 then die1=table0[temp1] else die1=table1[temp1] rem * roll the second die temp1=rand roll2=roll2^1 if roll2=0 then die2=table0[temp1] else die2=table1[temp1] score=0 for temp1=1 to die1:score=score+1000:next for temp1=1 to die2:score=score+1:next scorecolor=scorecolor+128 asm table0 rts byte 1,2 table1 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 byte 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 byte 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 byte 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 byte 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 byte 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 byte 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 byte 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 byte 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 byte 1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4 byte 5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2 byte 3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6 end I tried using rand16 as well, but got a result of 96 for one roll, which is the return opcode, so I guess using rand16 can give a 0 return value at times? Quote Link to comment Share on other sites More sharing options...
potatohead Posted July 7, 2012 Share Posted July 7, 2012 You know, that division could be sped up by using inline ASM. Since it's powers of two.... a = rand ASM lda a lsr lsr lsr REM continue program... Shifts are cheap. lsr = divide by 2, asl multiply by 2, and there are the bitmasks. Bitmasks do bias things, but one does have choices in that bias. Instead of doing the bitmask for the lower digits, do it in the middle, or the higher digits, etc...? a = rand ASM lda a and #%00111100 lsr lsr REM continue program A couple of shifts and you can very easily move the number to the range you want. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted July 7, 2012 Share Posted July 7, 2012 (edited) I've been thinking about the random number problem-- specifically, a random number from 1 to 6 (i.e., rolling a 6-sided die). The challenge is to come up with a method that always takes the same amount of time-- preferably as short as possible-- and gives an equal distribution for each possible value. I don't especially care for the bit-masking method, because bB's rand statement returns a value from 1 to 255, so (if I'm not mistaken) masking the bits can't give an equal distribution-- plus, you're limited to values from 0 to 2^n-1, which doesn't work for 1 to 6 anyway. Hi there, 1 to 6 is a small number, so how about adding up bits? I'm not sure what the distribution would look like, but the time would always be the same (40 cycles of assembly, plus whatever rand takes). Something like this, where you use rand to get a number between 1-255 (I think rand never returns 0, but that doesn't matter for this code anyway): rem * I do not no BB syntax, but do rand function for a value 1-255 a = (rand) ASM ;now,"a" is actually located at zero page register address??? (lets assume it is $80 for this example) lda #1 asl $80 adc #0 ; 1 to 2 possible asl $80 adc #0 ; 1 to 3 possible asl $80 adc #0 ; 1 to 4 possible asl $80 adc #0 ; 1 to 5 possible asl $80 adc #0 ; 1 to 6 possible sta $80 ; place the value back in "a" END Edit: If you wanted to have a random number between 0 and 5 you would just change "lda #1" to "lda #0" in the code above. Edited July 7, 2012 by Omegamatrix Quote Link to comment Share on other sites More sharing options...
potatohead Posted July 7, 2012 Share Posted July 7, 2012 You can just reference A as a label, btw. No need to deal with the address. Very nice bB feature, IMHO Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted July 7, 2012 Share Posted July 7, 2012 1 to 6 is a small number, so how about adding up bits? I had considered that solution, but I wasn't sure about the distribution. For a sequence of "random" numbers where each value occurs exactly once and all values between 0 and 255 occur, each bit can be on 50% of the time or off 50% of the time. But when you add the bits up, you won't get an even distribution. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 7, 2012 Share Posted July 7, 2012 . . . you won't get an even distribution. Speaking of that: http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#rand I noticed when I used AND with rand instead of dividing, the distribution was very uneven. When I switched to dividing or a mix of AND and dividing, the distribution became more even. For example, instead of using something like a = (rand&3) + (rand&1) + (rand&1), I had to use something like a = (rand/64) + (rand&1) + (rand/128). Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted July 8, 2012 Share Posted July 8, 2012 (edited) 1 to 6 is a small number, so how about adding up bits? I had considered that solution, but I wasn't sure about the distribution. For a sequence of "random" numbers where each value occurs exactly once and all values between 0 and 255 occur, each bit can be on 50% of the time or off 50% of the time. But when you add the bits up, you won't get an even distribution. I see. You are right the spread is not good. I took a look in excel and it wasn't even close. There is another approach you might try. rand MOD 6 is a fairly good distribution. I wrote some code to find this using divison by 6 to get the whole number, then multiplication by 6 followed by subtraction to get the remainder. I then increased it by 1 to get a number of 1 to 6. It is slower than using a look up table of course, but it saves bytes and is faster than the worse time case of looped division. So it is a medium length time/bytes approach to try and get the most bang for the buck. Try it out. a = rand ASM tempOne = $80 ; $80 is just for this demonstration, you must determine a correct address for a tempvariable lda #$08 ; one bit is pre-set to save a SEC instruction later sta tempOne lda a ; holds value from rand, currently 1 to 255 possible ;do unsigned division by six, result is the whole number (no remainder) cmp #192 bcc .do96 sbc #192 ; carry is set! .do96 rol tempOne cmp #96 bcc .do48 sbc #96 .do48 rol tempOne cmp #48 bcc .do24 sbc #48 .do24 rol tempOne cmp #24 bcc .do12 sbc #24 .do12 rol tempOne cmp #12 bcc .do6 sbc #12 .do6 ; carry gets set due to the pre-load of #$08 rol tempOne sbc #6 rol tempOne ; at this point "tempOne" holds the whole number of the division of six, ; lets do multiplication by six now lda tempOne asl adc tempOne sta tempOne adc tempOne sta tempOne ;tempOne is now multiplied by six, find the remainder dec tempOne ; instead of 0-5, lets get a number 1-6 lda a ; rand value 1 to 255 sec sbc tempOne sta a ; now holds a number 1 to 6 END Edited July 8, 2012 by Omegamatrix 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.