having problems with Random numbers

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

having problems with Random numbers

Post by andydansby »

Hello:

I have been playing around with random numbers. I started out with the built in rnd()

Code: Select all

 decision = (((long)(range) * rand()) / (long)(RAND_MAX))
Which seems to work just fine until I reached the end point of my game at that point, everything gave a crash.

So, I thought, let's try an xorshift pseudo random number generator.

I found a macro for the xorshift

Code: Select all

static unsigned char jz,jsr=5;
#define SHR3 (jz=jsr, jsr^=(jsr<<7), jsr^=(jsr>>5), jsr^=(jsr<<3),jz+jsr)
And it again seems to work OK until the end game at which point everything gave a crash in almost the exact same way.

So I deleted them both and ran the game, works great, but no Random numbers.

I have a feeling something else is going on, but I can't quite put my finger on it, driving me crazy.

I can provide the entire source code if anyone else needs it.

My compiling string is.

Code: Select all

zcc +zx -zorg=32772 -O3 -vn main.c -o build\main.bin -lndos
Any help would be appreciated

Andy
User avatar
dom
Well known member
Posts: 1187
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

The code generated looks correct in terms of stack operations - I don't think it's got anything to do with rand() itself given that you've substituted for another algorithm.

Is this the only use of long operations (multiple, divide) within your program? And what do you mean by end-game?
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

Hi Dom:

This is the only bit shifting I've done in the game so far. However I get the same type of crash if I use randomize or use the Xor shift randomize which now that you mention it may have something to do with the operators. I'm quite lost why I'm getting crashes on trying to generate random numbers.


The end game is when you kill 2 enemies and the game starts over, very much the end of the game.

I've put the entire source on GitHub https://github.com/andydansby/fase-bubble if you like to help me look further into it.

In the variables.h, I've defined

Code: Select all

static unsigned short jz,jsr=5;
at line 100. The macro is at line 22 in main.c.

The macro is called at line 125 of main.c combined with a modulo to normalize it to the range I want.. Works OK until you kill 2 enemies, which triggers game over.

If the randomizer is removed from the function, and decision = 0 to 4, then all seems to work just fine. quite confusing to me.

I certainly would appreciate any help on this issue, as I quite like randomness :).

Andy
User avatar
dom
Well known member
Posts: 1187
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Thanks for that, I had a bit of fun getting latest to compile that - I didn't handle calling through a plain void * pointer it seems.

Anyway, a few bug fixes later and it now compiles main.c

But it raises the question as to what version of z88dk you're using and whether your problem goes away with the latest code from GitHub - I'm wondering if you're tripping over one of the bugs I've fixed in the past year.
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

I guarantee, it was the latest when I downloaded it LOL. Of course, I downloaded it a while back. The directory dates to 12-8-2016 and the readme.1st inside says
z88dk - v1.99A 23 Dec 2015

I might be a little closer to the solution, I think it might be a problem with me not declaring a stack pointer. When I include

Code: Select all

#pragma output STACKPTR = 64000
, I'm getting a semi stable solution. I'm getting some oddball things going on if I run the test game on an emulated 128 or +2, but more stable on a +2a and +3 while in 48k mode. If I am in pure 128k, the game crashes immediately. Odd with the different models.

Which brings up another one of my silly questions, if the STACKPTR is required, is there a common sense way of setting it correctly, or should I use a HEX viewer and find a good chunk of empty space. I guess I should research more on the stack.

As for the randomizer macro I found, I'm rather pleased with it as it seems a simple implementation and gives me a nice steady stream of pseudo random numbers.

Andy
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

BTW, I do want to say the sources for the random number macros were adapted from

http://www.ciphersbyritter.com/NEWS4/RANDC.HTM

I adjust the shifting using http://www.arklyffe.com/main/2010/08/29 ... generator/ as a bit of guidance, just want to give where credit is due on the marcos.

Andy
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

andydansby wrote:I might be a little closer to the solution, I think it might be a problem with me not declaring a stack pointer. When I include

Code: Select all

#pragma output STACKPTR = 64000
, I'm getting a semi stable solution. I'm getting some oddball things going on if I run the test game on an emulated 128 or +2, but more stable on a +2a and +3 while in 48k mode. If I am in pure 128k, the game crashes immediately. Odd with the different models.
Are you doing any banking in the top 16k and have register "I" pointing up there for an im2 routine? If "I" points into contended ram and the code is being executed in contended ram, the spectrum can crash due to hardware bug. The 128k has odd banks contended 1,3,5,7 whereas the +3 has banks 4-7 contended so they will behave differently. To make sure things always work, the entry to your interrupt routine should be in 0x8000 to 0xbffff so that "I" points into bank 2 which is never contended.
Which brings up another one of my silly questions, if the STACKPTR is required, is there a common sense way of setting it correctly, or should I use a HEX viewer and find a good chunk of empty space. I guess I should research more on the stack.
If you don't set it (classic) or REGISTER_SP=-1 (newlib) then the stack location is set by the basic loader. The basic loader will do a "CLEAR n" to load the compiled program to address "n+1" and the CLEAR causes basic to move the stack underneath that address.
I adjust the shifting using http://www.arklyffe.com/main/2010/08/29 ? generator/ as a bit of guidance, just want to give where credit is due on the marcos.
The built in rand() is also a marsaglia xor generator (see
https://github.com/z88dk/z88dk/blob/mas ... xor_32.asm ). The classic library was switched to this generator today.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

There is a goto in the code and there is something about gotos that was fixed in sccz80.
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

Well, I just upgraded to the latest Z88dk and boy did that compile get out of hand real quick. Dom, you said that you were able to get it to compile with a few bug fixes, any pointers (love that pun) on what I should address or do you have a copy of the bug fixes you did on the code I posted, so my stuff can be compatable with the latest and greatest?

So right now, on the new verson of Z88dk, I'm getting quite a few errors

Code: Select all

sccz80:"main.c" L:250 Warning:Calling via non-function pointer
sccz80:"main.c" L:256 Warning:Calling via non-function pointer
sccz80:"main.c" L:263 Warning:Calling via non-function pointer
sccz80:"main.c" L:269 Warning:Calling via non-function pointer
sccz80:"main.c" L:275 Warning:Calling via non-function pointer
sccz80:"main.c" L:280 Warning:Calling via non-function pointer
sccz80:"main.c" L:280 Warning:Assigning from a void expression
sccz80:"main.c" L:285 Warning:Calling via non-function pointer
sccz80:"main.c" L:285 Warning:Assigning from a void expression
sccz80:"main.c" L:908 Warning:Control reaches end of non-void function
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Error:Missing token, expecting ( got ?
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Error:Illegal Argument Name:
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Warning:Expected ','
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Error:Illegal Argument Name:
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Warning:Expected ','
sccz80:"main.c" L:927 Error:Unexpected end of file
sccz80:"main.c" L:927 Error:Illegal Argument Name:
Yuck, I started moving the definitions to another file, but haven't finished with that yet.




@Alvin, I'm working on taking care of the GOTO, this was the code I got from the sample of FASE code from Antonio. So far my attempts on getting rid of the while(1) loop by doing something like.

Code: Select all

unsigned char lives;

while (1)
{
    //menu loop

   //control selected
   {
        break;
   }
}

lives = 3;

while(lives > 0)
{
    //game loop;

   //character dies
   {
     lives --;
   }

}
Sadily, there were some problems, and I upgraded to the latest Z88dk before I explored it more.


Andy
User avatar
dom
Well known member
Posts: 1187
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I changed a couple of things in your code

- ended variables.h with a new line
- removed the eof text at the end of the code - that?s why you?ve got all the earnings on line 927

I only looked at main.c though. The same things probably apply to other files.

Most of those warnings are because you?re using a void * as a function pointer (that was what I had to fix up in sccz80). Function pointers could always be declared, but now they can have parameters as well.
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

Well, I am certainly getting a compile now. I'm going to have to do further troubleshooting on the code, I am getting an immediate crash on menu selection that I did not get when using the older version of Z88dk. My feeling is that is has to do with the function pointer.

I'll try to reformulate the input function. This is one that came with the FASE engine and didn't touch it since it just worked.

I updated my github with the latest version and will play around with the beasty after my head clears up.

Andy
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

@Alvin, I'm working on taking care of the GOTO, this was the code I got from the sample of FASE code from Antonio. So far my attempts on getting rid of the while(1) loop by doing
something like.
Using a goto is ok, it's just that there has been a bug associated with it under sccz80 that has been fixed since 1.99B that you were using.

People always say "gotos are bad" but it shouldn't be taken as dogma. What is really meant is that gotos, if used inappropriately, destroy the structure of a program which makes it hard to understand and often leads to less than optimal code written by the programmer. However, there are legitimate reasons for using goto, especially when it simplifies the structure of a program like getting out of a deeply nested point in the code.

About the stack location, FASE reserves its own independent region of memory and you have to make sure the stack and the z88dk generated code stays out of that area.

And as mentioned by dom, some of those warnings are inconsequential. sccz80 is now checking for many more potential errors in the code so it generates a lot more warnings than it used to. However, you should check warnings to make sure they aren't actual errors that used to be skipped over, and you may want to clean up code to eliminate those warnings.

sccz80:"main.c" L:280 Warning:Assigning from a void expression
This one probably indicates an error as the compiler is saying the expression produces no result but you're still using its non-existent value for an assignment. Maybe this has something to do with the function pointer expression you're using. The older z88dk would have ignored this.

sccz80:"main.c" L:908 Warning:Control reaches end of non-void function
This one means the function expects to return a value but you're leaving the function without returning one.

sccz80:"main.c" L:927 Error:Unexpected end of file
You probably don't have a blank line at the end of the file (you're not allowed to end a source file without a blank line).
andydansby
Member
Posts: 31
Joined: Fri May 27, 2016 8:58 pm

Post by andydansby »

I ended up using a macro and it works great with a pretty small footprint

Code: Select all

static unsigned short jz,jsr=5;//used in randomizer
in my global variables

with the macro being

Code: Select all

#define SHR3 (jz=jsr, jsr^=(jsr<<7), jsr^=(jsr>>5), jsr^=(jsr<<3),jz+jsr)
calling the random number via.

Code: Select all

decision = (SHR3 % 4);//our random number from the macro , range is 1 to 4
Andy
cborn
New member
Posts: 9
Joined: Tue Oct 06, 2020 7:45 pm

Re: having problems with Random numbers

Post by cborn »

Hello, my thougths about randomize is using the R-register since that changes the most fast
it always raises so i split it in two lines, even and odd, where one will raise and the other will lower.
the 'oddness' is reversed by the way its coded. it helps a bit, and still can be improved.

Code: Select all

void  rndseed()  // not very random yet, needs better one
        {
      #asm
         di
         ld hl,23672    // 10t  raises only once in 69288 tstate with 1 per frame
         ld a,r         //  9t  raises every ~4~24 tstate with 1 or maybe 2 per instruction , inner LDR , LDI instructions counted.
         bit 0,a        //  8t
         jp z,rev       // 10t  z=0=even

         cpl            //|  4t the value of 'r' now decreases instead of raising
         jp nn          //| 10t  odd is now even  0xff=0x00
rev:
         inc a          //~  4t  raise and  even is now odd  0x00=0x01
         jp nn          //~ 10t  jp=only for timing sake here, DELAY

nn:
         xor (hl)       //  7t
         ld b,a         //  4t
         inc hl         //  7t raise once per 256 FRAMES of 69288 = after ~5.5 seconds
         ld a,r         //  9t
         xor (hl)       //  7t

         ld h,b         //  4t
         ld l,a         //  4t
         
//         ld a,h         //  4t
//         and 31         //  7t dont (start) seed above 8192 area
//         ld h,a         //  4t

         ld (23670),hl  //  15t write new seed
         ei             //   4t
         ret            //  10t  
      #endasm    // always equal timing = 4+10+9+8+10 +4+10  +7+4+7+9+7+4+4   +15+4+10 =126 tstate
        }



void setrand()
        {
        rndseed() ;
        char* sd = 23670 ;
        srand(*sd) ; 
        }



int dice(int aods)
        {
//        randomize() ;
        setrand() ;
        char d = rand()%aods +1 ;
        return d ;
        }

EDIT
i had copied some part double, now its good again
Post Reply