Search code examples
carraysgameboy

Fatal error while printing a 2 dimensional array


Im having this problem with a little chunk of code:

for(x = 0; x < 8; x++){
for(y = 0; y < 8; y++){
printf(" %d", occupy[x][y]);
}
printf(" \n");
}

I'm making a randomly generated maze game for the Gameboy, and I'm using a 2d array to know where each screen is in the maze. For testing I'm trying to print that array so I can see if its generating properly before I move on. When I try to compile with that little chunk of code I get an error on the top line of it, then says fatal Compiler internal error in file blah blah blah. Is there like a big no-no in that code that I didn't know of?

Full code:

#include <gb\gb.h>
#include <stdio.h>
#include <rand.h>


#define UP 0x01U
#define RIGHT 0x02U
#define DOWN 0x04U
#define LEFT 0x08U

int occupy[8][8]= {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}
};


void generate(){
int temp;
int x;
int y;
UBYTE restrict;
UBYTE direction;
for(x = 0; x < 8; x++){
for(y = 0; y < 8; y++){
occupy[x][y] = 0;
}
}
/* ========Occupy=Cleared========== */
restrict = 0x00U;
x = rand() & 7;
y = rand() & 7;

if(x == 6 || x == 7){ restrict += RIGHT;}
if(x == 0 || x == 1){ restrict += LEFT;}
if(y == 0 || y == 1){ restrict += UP;}
if(y == 6 || y == 7){ restrict += DOWN;}

/* in the rest of generation wrap this block in if(restrict != 0x0FU){ */

do{
temp = rand() & 3;
if(temp == 0){ direction = UP;}
if(temp == 1){ direction = RIGHT;}
if(temp == 2){ direction = DOWN;}
if(temp == 3){ direction = LEFT;}
}while(restrict & direction);


occupy[x][y] = 5;
if(direction == UP){ occupy[x][y-1] = 1;}
if(direction == RIGHT){ occupy[x+1][y] = 2;}
if(direction == DOWN){ occupy[x][y+1] = 3;}
if(direction == LEFT){ occupy[x-1][y] = 4;}

for(x = 0; x < 8; x++){
for(y = 0; y < 8; y++){
printf(" %d", occupy[x][y]);
}
printf(" \n");
}

}


void main(){
generate();

}

Solution

  • This compiles under my version of GBDK fine, although I'm not sure why the changes I make are what fixes it.

    Changes made:

    • occupy is now an array of unsigned int rather than just int (without this change sdcc crashes)
    • printf call inside of loop was changed from " %d" to " %u" (as the value is unsigned)
    • A printf showing the address of occupy has been added. If I remove it or change it to do something else, sdcc crashes. This is silly, but it seems to be required. I'm looking in to alternatives that don't need a pointless printf.

      • Note that the following can be used instead, which results in nothing being printed (as in it tries to write to address $0000, but that's read only and fails). It's still stupid but doesn't display anything. It might still cause some slowdown though.

        sprintf(0, "", &occupy);
        
    • I also improved indentation.

    #include <gb\gb.h>
    #include <stdio.h>
    #include <rand.h>
    
    
    #define UP 0x01U
    #define RIGHT 0x02U
    #define DOWN 0x04U
    #define LEFT 0x08U
    
    unsigned int occupy[8][8] = {
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0}
    };
    
    void generate(){
        int temp;
        int x;
        int y;
        UBYTE restrict;
        UBYTE direction;
    
        for(x = 0; x < 8; x++){
            for(y = 0; y < 8; y++){
                occupy[x][y] = 0;
            }
        }
        /* ========Occupy=Cleared========== */
        restrict = 0x00U;
        x = rand() & 7;
        y = rand() & 7;
    
        if(x == 6 || x == 7){ restrict += RIGHT;}
        if(x == 0 || x == 1){ restrict += LEFT;}
        if(y == 0 || y == 1){ restrict += UP;}
        if(y == 6 || y == 7){ restrict += DOWN;}
    
        /* in the rest of generation wrap this block in if(restrict != 0x0FU){ */
    
        do{
            temp = rand() & 3;
            if(temp == 0){ direction = UP;}
            if(temp == 1){ direction = RIGHT;}
            if(temp == 2){ direction = DOWN;}
            if(temp == 3){ direction = LEFT;}
        }while(restrict & direction);
    
    
        occupy[x][y] = 5;
        if(direction == UP){ occupy[x][y-1] = 1;}
        if(direction == RIGHT){ occupy[x+1][y] = 2;}
        if(direction == DOWN){ occupy[x][y+1] = 3;}
        if(direction == LEFT){ occupy[x-1][y] = 4;}
    
        printf(" %x\n", &occupy); //Strangely without this printf it doesn't compile???
        for(x = 0; x < 8; x++){
            for(y = 0; y < 8; y++){
                printf(" %u", occupy[x][y]);
            }
            printf(" \n");
        }
    
    }
    
    
    void main(){
        generate();
    }
    

    Here's a few other comments about the code:

    • You don't ever initialize the RNG, so the results will always be the same. There's a few ways to set the seed. Normally, you do it with time on the title screen, or you can have a seed chooser.

      //Seeds RNG by time taken to press start
      void seedRNG() {
          UINT16 seed = 0;
      
          printf("Press start\n");
          while (!(joypad() & J_START)) {
              seed++;
          }
          initrand(seed);
      }
      
      //Seeds RNG with a user-chosen number.
      //Requires inclusion of <gb\console.h>.
      void seedRNG() {
          UINT16 seed = 0x8000U; //In the middle to prevent over/underflow issues
      
          printf("Seed:");
      
          while (!(joypad() & J_START)) {
              if (joypad() & J_UP) { seed++; }
              if (joypad() & J_DOWN) { seed--; }
              gotoxy(0,1);
              printf("%x\n", seed);
              delay(10);
          }
          initrand(seed);
      }
      
    • You don't actually need to print stuff out to view it in this case, since you can use the "Memory Viewer" found in most emulators. The locations can be found in a RAM map generated with the -Wl-j or -Wl-m options.

    • I recommend using INT16 or WORD rather than int and UINT16 or UWORD rather than unsigned int, ect, as they include the sizes in their names. UBYTE and such are also nice to use.