Jump to content
  • Advertisement
Sign in to follow this  
Adam4444

Help to find a bug in snake game

This topic is 4331 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have made a simple snake game in ncurses. And everything seems to work allright except one thing; the food doesn't showup sometimes and one can't continue to play the game since it isn't fun when there's no food. All the code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <ncurses.h>
#define WIDTH        80
#define HEIGHT       23
#define MAX_LENGTH   1000
#define START_LENGTH 3
#define B_SNAKE      'O'
#define B_FOOD       '*'
#define B_NOTHING    0
#define D_UP         0
#define D_DOWN       1
#define D_LEFT       2
#define D_RIGHT      3

typedef struct SnakeBlock_ {
    int x;
    int y;
} SnakeBlock;

void init_game(int *argc, char *argv[]);
void terminate_game(void);
void remove_tail(void);
void append_head(int x, int y);
void move_back_blocks(void);
void draw_map(void);
void place_food(void);
void grow(void);
bool is_empty(int x, int y);
int obj(int x, int y);
int nrand(int lower, int upper);

SnakeBlock snake[MAX_LENGTH];
WINDOW *game_map;
int x, y;
int fx, fy;
int length;
bool running;
struct timespec sleep_time;
int dir;

int main(int argc, char *argv[])
{
    int i;
    int c;
    
    sleep_time.tv_sec  = 0;
    sleep_time.tv_nsec = 90000000;
    
    init_game(&argc, argv);
    if (COLS < WIDTH || LINES < HEIGHT + 1) {
        terminate_game();
        printf("Your terminal size must be at least %dx%d.\n", WIDTH, HEIGHT);
        printf("Please resize yout terminal and start the game again.\n");
        exit(1);
    }
    
    nodelay(stdscr, true);
    
    running = 1;
    dir = D_UP;
    x = WIDTH / 2;
    y = HEIGHT - START_LENGTH;
    
    for (i = 0; i < START_LENGTH; i++) {
        snake.x = x;
        snake.y = y + i;
    }
    length = START_LENGTH;
    
    place_food();
    while(running) {
        c = getch();
        switch (c) {
            case 'w':
                if (dir != D_DOWN) {
                    dir = D_UP;
                }
                break;
            case 's':
                if (dir != D_UP) {
                    dir = D_DOWN;
                }
                break;
            case 'a':
                if (dir != D_RIGHT) {
                    dir = D_LEFT;
                }
                break;
            case 'd':
                if (dir != D_LEFT) {
                    dir = D_RIGHT;
                }
                break;
            case 'q':
                running = false;
                break;
        }
        switch (dir) {
            case D_UP:
                y--;
                break;
            case D_DOWN:
                y++;
                break;
            case D_LEFT:
                x--;
                break;
            case D_RIGHT:
                x++;
                break;
        }
        if (obj(x, y) == B_FOOD) {
            length++;
            place_food();
        }
        else if (obj(x, y) == B_SNAKE || (x > WIDTH || x < 0 || y > HEIGHT || y < 0)) {
            terminate_game();
            printf("You are so dead, asshole.\n");
            printf("Your snake reached a length of %d.\n", length);
            exit(0);
        }
        remove_tail();
        move_back_blocks();
        append_head(x, y);
        draw_map();
        mvprintw(0, 0, "Length: %d", length);
        mvprintw(1, 0, "x = %d, y = %d", x, y);
        mvprintw(2, 0, "fx= %d, fy = %d", fx, fy);
        refresh();
        wborder(game_map, '|', '|', '-', '-', '*', '*', '*', '*');
        wrefresh(game_map);
        nanosleep(&sleep_time, NULL);
    }
    terminate_game();
    
    return 0;
}

void init_game(int *argc, char *argv[])
{
    initscr();
    noecho();
    curs_set(0);
    srand((unsigned int) time((time_t *) NULL));
    
    if (*argc > 1) {
        if (strcmp(argv[1], "-author") == 0 || strcmp(argv[1], "-a") == 0) {
            terminate_game();
            printf("Created by Adam Lundvall\n");
            exit(0);
        }
    }

    game_map = newwin(HEIGHT, WIDTH, LINES - (HEIGHT + (HEIGHT / 2)), COLS - (WIDTH + (WIDTH / 2)));
    wborder(game_map, '|', '|', '-', '-', '*', '*', '*', '*');
    wrefresh(game_map);
}

void terminate_game(void)
{
    curs_set(1);
    clear();
    endwin();
}

void append_head(int x, int y)
{
    snake[0].x = x;
    snake[0].y = y;
}

void remove_tail(void)
{
    mvwaddch(game_map, snake[length - 1].y, snake[length - 1].x, ' ');
    snake[length - 1].x = -1;
    snake[length - 1].y = -1;
}

void move_back_blocks(void)
{
    int i;
    SnakeBlock temp;

    for (i = length; i > 0; i--) {
        temp = snake[i - 1];
        snake = temp;
    }
}

void draw_map(void)
{
    int i;

    for (i = 0; i < length; i++) {
        if (snake.y != -1 && snake.x != -1) {
            mvwaddch(game_map, snake.y, snake.x, B_SNAKE);
        }
    }
    mvwaddch(game_map, fy, fx, B_FOOD);
}

void place_food(void)
{
    do {
        fx = nrand(0, WIDTH);
        fy = nrand(0, HEIGHT);
    }
    while (obj(fx, fy) == B_SNAKE);
}

int obj(int x, int y)
{    
    if (x == fx && y == fy) {
        return B_FOOD;
    }
    if (!is_empty(x, y)) {
        return B_SNAKE;
    }
    
    return B_NOTHING;
}

bool is_empty(int x, int y)
{
    int i;
    
    for (i = 0; i < length; i++) {
        if (snake.x == x && snake.y == y) {
            return false;
        }
    }
    return true;
}

int nrand(int lower, int upper)
{
    int dif = upper - lower;
    
    return (int)((double)rand() / ((double)RAND_MAX + 1) * dif);
}
The functions of interest is place_fodd(), main() and obj(). Hope somebody can help me out, casue I can't see where it goes wrong. [Edited by - Adam4444 on January 30, 2007 4:21:01 PM]

Share this post


Link to post
Share on other sites
Advertisement
Just guessing here, since I don't understand how nrand() works, but I see it takes upper and lower parameters, but you are passing in 0 and 80. The bounds of a standard console screen would run from 0 to 79, since it displays 80 characters.

Is it possible that the food is sometimes placed in column 80, i.e. off the screen so clipped by ncurses?

Try passing (0,WIDTH-1) to nrand instead would be my suggestion.

BTW, for large amounts of code, use [ source ][ /source ] (without the spaces) tags so your posts don't get so long.

Share this post


Link to post
Share on other sites
Quote:
Original post by EasilyConfusedTry passing (0,WIDTH-1) to nrand instead would be my suggestion.

Didn't work. Is it possible that the problem occur when place_food() tries to put a food where the snake is? It shouldn't be wrong there but when I run the game it looks lika if fails just then.

Share this post


Link to post
Share on other sites
Adam, you need to keep an on screen log, showing the coordinates of the food at all times, so that when it doesnt show up, you can see what its co-ordinates. This will help to determine where your problem lies. (Make sure that you also know what your snakes co-ordinates are at that point just in case it is on the head or something!).

Share this post


Link to post
Share on other sites
Quote:
Original post by chosendl
Adam, you need to keep an on screen log, showing the coordinates of the food at all times, so that when it doesnt show up, you can see what its co-ordinates. This will help to determine where your problem lies. (Make sure that you also know what your snakes co-ordinates are at that point just in case it is on the head or something!).

I'm already doing that. The lines
mvprintw(0, 0, "Length: %d", length);
mvprintw(1, 0, "x = %d, y = %d", x, y);
mvprintw(2, 0, "fx= %d, fy = %d", fx, fy);
does that.
But I can't see any pattern.

Share this post


Link to post
Share on other sites
chosendl made an excellent suggestion.

Since you are not calling srand() as far as I can see (and if you are, comment it out for a bit), you should be getting exactly the same random sequence every time the game runs.

So what are the co-ordinates of the first food piece that fails to materialize? If it falls within the screen, can you decypher where it falls in relation to the snake segments?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!