3Nex
3Nex

Reputation: 527

Simple console labirinth game: Need help to figure out a bug

I made an extermely simple labirinth game out of boredom, however there's a weird bug that i can't figure out why is happening.

When i try to move into the obstacle, the first row of my output shifts. Also, depending on where i try to move, it can shift just 1 or more than 1 characters to the right. This is pretty weird to me considering that my showFrame() function clears the screen every time before outputting.

The 90th line is in action when you try to move into an obstacle. In case the new position is invalid, it will first revert the position, then invoke showFrame(), and showFrame() clears the console before outputting. So what causes the first row to shift? AND why does it shift differently depending on which key is pressed?

The code follows. If i understand correctly, you need to compile and run on linux, not windows, because of the ncurses thing and the getchar function? But i'm not sure. (not really a C programmer much)

Add the -lncurses argument when compiling. If you don't have the ncurses library installed, it can be downloaded here: http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.7.tar.gz

#include <stdio.h>
#include <ncurses.h>
#include <stdlib.h>

int positionX = 1,
    positionY = 19,
    oldPositionX, 
    oldPositionY,
    sizeX, 
    sizeY;
char matrix[20][20] = 
   {'|', ' ', '|', ' ', ' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', ' ', ' ', ' ', ' ', '|', ' ', '|',
    '|', ' ', '|', ' ', ' ', ' ', '|', '-', '-', ' ', ' ', ' ', '-', '-', '|', ' ', ' ', ' ', ' ', '|',
    '|', ' ', '-', '-', '-', '-', '-', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|', ' ', '-', '-', ' ', '|',
    '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', ' ', '|', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', '|',
    '-', '-', '-', '|', ' ', '|', ' ', ' ', '|', ' ', '|', ' ', ' ', ' ', '-', '-', ' ', '|', ' ', '|',
    ' ', ' ', ' ', '|', ' ', '|', ' ', ' ', '|', ' ', '-', '-', '|', ' ', ' ', '|', ' ', '|', ' ', '|',
    ' ', '|', ' ', '|', ' ', '|', ' ', ' ', '|', ' ', ' ', ' ', '|', ' ', '|', '|', ' ', '|', ' ', '|',
    ' ', '|', ' ', ' ', ' ', '-', '-', '|', '|', ' ', ' ', ' ', '|', ' ', '|', ' ', ' ', '|', ' ', '|',
    ' ', '-', '-', '|', ' ', ' ', ' ', '|', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '-', '-', '-', '|',
    ' ', ' ', ' ', '|', ' ', '|', ' ', '|', ' ', '|', '-', '-', '-', ' ', '|', ' ', '|', ' ', ' ', '|',
    '-', '-', '-', '|', ' ', '|', ' ', '|', ' ', '|', ' ', ' ', ' ', ' ', '|', ' ', '-', '|', ' ', '|',
    '|', ' ', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', '|',
    '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '-', '-', '-', '|', ' ', ' ', '|', ' ', '|',
    '|', ' ', '|', '-', '-', '-', '-', '-', '-', '-', ' ', ' ', ' ', ' ', '|', ' ', '-', '-', ' ', '|',
    '|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', '-', '-', ' ', ' ', '|',
    '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', '-', '-', '-', ' ', ' ', ' ', ' ', ' ', ' ', '|',
    '|', '-', '-', '-', '-', '-', ' ', '|', '-', '-', ' ', ' ', '|', ' ', ' ', ' ', '-', '-', '-', '|',
    '|', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', '-', '|', ' ', ' ', ' ', ' ', ' ', '|',
    '|', ' ', '|', '-', '-', '-', '-', '-', ' ', ' ', '|', ' ', ' ', ' ', ' ', '-', '-', '-', '-', '|',
    '|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', '-', '-', '|', ' ', '|', ' ', ' ', ' ', ' '};

void main() {
   char key;
   int stty;

   // Get the size of the matrix   
   sizeX = sizeof(matrix) / sizeof(matrix[0]);
   sizeY = sizeof(matrix[0]);

   while(1) {
      // Output level
      showFrame();

      // Wait for user input to move player position
      stty = system("stty raw");
      key = getchar();
      system("stty cooked");

      // Store previou position and move player position accordingly
      oldPositionX = positionX;
      oldPositionY = positionY;
      switch(key) {
         case 'w':   positionY--;
                     break;
         case 'a':   positionX--;
                     break;
         case 's':   positionY++;
                     break;
         case 'd':   positionX++;
                     break;
         default:    printf("\bThat's an invalid key, stupid!\nYou're supposed to play with WASD keys.\n");
                     exit(0);
      }

      // Check to see if new position is okay
      if(positionY >= sizeY || positionY < 0 || positionX >= sizeX || positionX < 0) {
         revertPosition();
      }

      // Check to see if level cleared!
      if(positionX == 1 && positionY == 0) {
         showFrame();
         printf("You cleared the level, Sherlock.\nYou must be really proud of yourself\n");
         return;
      }
   }
}

int showFrame() {
   int i, j;

   // Output the matrix
   system("clear");
   for(i=0; i<sizeX; i++) {
      for(j=0; j<sizeY; j++) {
         // Check if player's position is at the current block
         if(i == positionY && j == positionX) {
            // If the players position is in an invalid block, revert his position
            if(matrix[i][j] != ' ') {
               revertPosition();
               showFrame();
               printf("You can't go there, stupid!\n");
               return 1;
            } else {
               printf("* ");
            }
         } else {
            printf("%c ", matrix[i][j]);
         }
      }
      printf("\n");
   }
   return 0;
}

void revertPosition() {
   positionX = oldPositionX;
   positionY = oldPositionY;
}

Upvotes: 0

Views: 106

Answers (1)

Paul92
Paul92

Reputation: 9062

It seems there is a problem with clear.

To identify the problem, you should start finding what those characters that shift your first row come from. Adding:

   system("clear");
   printf('\n');
   for(i=0; i<sizeX; i++) {
      for(j=0; j<sizeY; j++) {

brings a little bit of light. It seems that if i want to go up, the characters there are the same as those from the upper line, to my position.

Now, you need to find why those characters are not deleted by system("clear"); , as it is supposed. After some trial and error, I managed to find that if you print a '\n' before clearing, it works as it is supposed.

As I have never used ncurses before, I can not explain you why is this happening. My assuption is that clear command clears the terminal line by line. And a line is ended with newline character. So, everything you need to do is to append newline after those trailing characters (I would suggest you printing it at the beginning of the showFrame function, to avoid simillar situations):

int showFrame() {
   int i, j;

   // Output the matrix
   printf('\n');
   system("clear");
   for(i=0; i<sizeX; i++) {
      for(j=0; j<sizeY; j++) {
         // Check if player's position is at the current block
         if(i == positionY && j == positionX) {
            // If the players position is in an invalid block, revert his position
            if(matrix[i][j] != ' ') {
               revertPosition();
               showFrame();
               printf("You can't go there, stupid!\n");
               return 1;
            } else {
               printf("* ");
            }
         } else {
            printf("%c ", matrix[i][j]);
         }
      }
      printf("\n");
   }
   return 0;
}

I hope this was useful for you. Also, let me make some remarks about your code:

Using global variables is strongly discouraged. About the main's return value, I would recommend you to read this. Also, your ethier declare your functions before main:

int showFrame();
void revertPosition();

either move their entire definitions before main. As it is, your code did not compile on my machine (gcc 4.8.1).

Upvotes: 1

Related Questions