HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Snake with ncurses in C

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withncursessnake

Problem

I've implemented a version of snake using GNU ncurses, and I'd appreciate some feedback! There are two main files, a main.c file that houses the main function and a few generic functions, and a snake.c file that houses mostly snake-related functions. I'll include the corresponding header files first, because they help document the implementation.

I used ncurses halfdelay along with a timer in order to manage movement. The levels of difficulty just set different timeouts between movement.

main.h

#ifndef MAIN_H
#define MAIN_H

#include 
#include 

typedef WINDOW Window;

typedef struct {
    Window* W;
    bool* isOccupied;
} GameWindow;

typedef struct {
    int x;
    int y;
} Coord, *CoordPtr;

// Doubly-LL implementation for easy growth
typedef struct CoordLL {
    Coord* loc;
    struct CoordLL* next;
    struct CoordLL* prev;
} CoordLL, *CoordLLPtr;

bool wmvaddch(Window* W, int y, int x, int ch);
int toOneD(int y, int x, int maxX);
bool isOccupied(GameWindow* GW, int y, int x, int xMax);
void freeGW(GameWindow* GW);
int renderMenu(Window* W, int menuWidth, char* title, char* subtitle, int numOptions, char** options); // returns selected index

#endif /* MAIN_H */


main.c

```
#include
#include
#include
#include
#include

#include "lib/snake.h"
#include "lib/main.h"

bool wmvaddch(Window* W, int y, int x, int ch){
int xMax, yMax;
getmaxyx(W,yMax,xMax);
if(yMax isOccupied[ind];
}

void freeGW(GameWindow* GW){
free(GW->isOccupied);
delwin(GW->W);
free(GW);
}

void updateScore(Window scoreWin, Snake S, int difficulty){
wclear(scoreWin);
box(scoreWin,0,0);
wmove(scoreWin,2,1);
wprintw(scoreWin,"Score: %d",S->len*difficulty);
wrefresh(scoreWin);
}

// This function is not very general, but could easily be changed as needed
int renderMenu(Window W, int menuWidth, char title, char* subtitle, int numOptions, char** options){
wattron(W,A_REVERSE);
mvwprintw(W,1,(menuWidth-

Solution

-
Your render function could be re-written as constants, shows that the snake is not changed by this function. e.g.

void renderSnake(Window* W, Snake const * const S){
    CoordLL* body = S->first;
    while(body){
        wmvaddch(W,body->loc->y,body->loc->x,ACS_DIAMOND);
        body = body->next;
    }
    wrefresh(W);
}


-
There is a memory leak around placeFood(). New food is allocated, and there is no call to free() the old food before it is overwritten.

-
"clunky" could be reduced to,

switch(choice){
        case KEY_UP:      // dropthrough
        case KEY_DOWN:    // dropthrough
        case KEY_LEFT:    // dropthrough
        case KEY_RIGHT:   // dropthrough
            S->lastDir = choice;
            break;
    }


OR, I suspect that it's only going to be one of these choices reaching this function. Simplify it to just,

S->lastDir = choice;

Code Snippets

void renderSnake(Window* W, Snake const * const S){
    CoordLL* body = S->first;
    while(body){
        wmvaddch(W,body->loc->y,body->loc->x,ACS_DIAMOND);
        body = body->next;
    }
    wrefresh(W);
}
switch(choice){
        case KEY_UP:      // dropthrough
        case KEY_DOWN:    // dropthrough
        case KEY_LEFT:    // dropthrough
        case KEY_RIGHT:   // dropthrough
            S->lastDir = choice;
            break;
    }
S->lastDir = choice;

Context

StackExchange Code Review Q#159222, answer score: 6

Revisions (0)

No revisions yet.