2
\$\begingroup\$

This is my first year at university, and I'm trying to learn everything about fundamentals. I've coded a snake game recently in C.

This is a programming-challenge that I've given to myself to practice arrays and pointers. I don't need a solution to my code because it works the way I want. I create a snake and its body grows the more I eat the food.

The thing is, I want to improve how I code, as I feel like at some point it becomes a mess. I've tried to write my algorithm and what I plan to code on paper first.

My algorithm works this way: I create a snake head, then it moves with my input, and if body comes along the head, they follow each other. There are two arrays so that I can hold the coordinates and the "values on the board": 2 means a snake, 0 means an empty space, 1 means border and so on.

Also I don't know any framework yet and studying only C feels like I'm lacking. Is that a problem?

I feel like I've repeated myself sometimes and couldn't write the best way possible, so how can I write this code better?

Or are there any bugs I can't see or anything I can do better?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <unistd.h>


int row_f=0,column_f=0;// food variables
int board[25][64];
int snake[150][2];
int movement=0;
int body_count=0;

void follow(int body_count);
void create_snake(int *rowPtr,int *colPtr,int x,int movement,int body_count);
void print_board();
void create_food(int *rowPtr,int *colPtr,int x);
void pointerset(int *rowPtr,int *colPtr);


int main()
{
    srand(time(NULL));
    char direction;

//----------------Creating board--------------
   for(int i=0;i<25;i++){
        for(int a=0;a<64;a++){
              if(i == 0 || i == 24){
            board[i][a]=1;
            }else if(a == 0 || a==63){
            board[i][a]=1;
            }else{
                board[i][a]=0;
            }
        }
    }
//----------------Creating board--------------

    create_food(&row_f,&column_f,3);
    create_snake(&snake[0][0],&snake[0][1],2,movement,body_count);

    print_board();
    control(direction,&snake[0][0],&snake[0][1]);

}


void control(char wasd_2486,int *rowPtr,int *colPtr){
    int food_eaten =0;

    while(!kbhit()){
        print_board();

        if(movement == 2){
            if(board[*rowPtr+1][*colPtr]==3){
                    food_eaten=1;
                    create_food(&row_f,&column_f,3);
                    body_count++;
                    create_snake(snake[body_count][0],snake[body_count][1],2,movement,body_count);
                }
                    follow(body_count);
        *rowPtr = *rowPtr+1;
        board[*rowPtr][*colPtr]=2;
        control(wasd_2486,rowPtr,colPtr);

        }else if(movement == 4){


            if(board[*rowPtr][*colPtr-1]==3){
                    food_eaten=1;
                    create_food(&row_f,&column_f,3);
                    body_count++;
                    create_snake(snake[body_count][0],snake[body_count][1],2,movement,body_count);
                }
                    follow(body_count);
             *colPtr = *colPtr-1;
             board[*rowPtr][*colPtr]=2;
             control(wasd_2486,rowPtr,colPtr);

        }else if(movement == 8){


            if(board[*rowPtr-1][*colPtr]==3){
                    food_eaten=1;
                    create_food(&row_f,&column_f,3);
                    body_count++;
                    create_snake(snake[body_count][0],snake[body_count][1],2,movement,body_count);
                }
                        follow(body_count);
                        
            *rowPtr = *rowPtr-1;
            board[*rowPtr][*colPtr]=2;

            control(wasd_2486,rowPtr,colPtr);

        }else if(movement == 6){


            if(board[*rowPtr][*colPtr+1]==3){
                    food_eaten=1;
                    create_food(&row_f,&column_f,3);
                    body_count++;
                    create_snake(snake[body_count][0],snake[body_count][1],2,movement,body_count);
                }
                       follow(body_count);


            *colPtr = *colPtr+1;
            board[*rowPtr][*colPtr]=2;

            control(wasd_2486,rowPtr,colPtr);

}
    control(wasd_2486,rowPtr,colPtr);

    while(kbhit()){
        print_board();
        wasd_2486=getch();

        if(wasd_2486 == '4' || wasd_2486 == 'a'){
            if(movement == 0 || movement != 6){
                    movement=4;
            }
        }else if(wasd_2486 == '6' || wasd_2486 == 'd'){
                if(movement == 0 || movement != 4){
                        movement =6;
                }
        }else if(wasd_2486 == '2' || wasd_2486 == 's'){
                    if(movement == 0 || movement != 8){
                            movement =2;
                    }
        }else if(wasd_2486 == '8' || wasd_2486 == 'w'){
                    if(movement == 0||movement !=2){
                        movement=8;
                    }
    }
    control(wasd_2486,rowPtr,colPtr);
    }
}
}


void follow(int body_count){

if(body_count == 0){
    board[snake[body_count][0]][snake[body_count][1]]=0;
    }else{

            for(int i=body_count;i>0;i--){

                    board[snake[body_count][0]][snake[body_count][1]]=0;
                    snake[i][0]=snake[i-1][0];
                    snake[i][1]=snake[i-1][1];
}

}
}





void create_snake(int *rowPtr,int *colPtr,int x,int movement,int body_count){
        if(movement == 0){
            pointerset(rowPtr,colPtr);

        }else if(movement == 2){
            snake[body_count][0]= snake[body_count-1][0]-1;
            snake[body_count][1]= snake[body_count-1][1];
            board[snake[body_count][0]][snake[body_count][1]]=2;
        }else if(movement == 4){
            snake[body_count][0]= snake[body_count-1][0];
            snake[body_count][1]= snake[body_count-1][1]+1;
            board[snake[body_count][0]][snake[body_count][1]]=2;
        }else if(movement == 6){
            snake[body_count][0]= snake[body_count-1][0];
            snake[body_count][1]= snake[body_count-1][1]-1;
            board[snake[body_count][0]][snake[body_count][1]]=2;
        }else if(movement == 8){
            snake[body_count][0]= snake[body_count-1][0]-1;
            snake[body_count][1]= snake[body_count-1][1];
            board[snake[body_count][0]][snake[body_count][1]]=2;
        }


}



void create_food(int *rowPtr,int *colPtr,int x){
pointerset(rowPtr,colPtr);

if(board[*rowPtr][*colPtr]==1){
  create_food(rowPtr,colPtr,x);

}else if(board[*rowPtr][*colPtr]==0){
    board[*rowPtr][*colPtr]=x;

}else{
    create_food(rowPtr,colPtr,x);
}
}

void pointerset(int *rowPtr,int *colPtr){
    *rowPtr=rand()%25;
    *colPtr=rand()%64;
}

void print_board(){

    system("CLS");

    for(int i=0;i<25;i++){
        for(int a=0;a<64;a++){
        if(board[i][a]==1){
            printf("+");
        }else if(board[i][a]==0){
            printf(" ");
        }else if(board[i][a]==2){
            printf("o");
        }else if(board[i][a]==3){
            printf("*");
        }
}
 printf("\n");
}
printf("\n");printf("\n");printf("\n");printf("\n");

}
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Indent the code, please. It's very hard to read it now. E.g. it looks like srand(time(NULL)) is called after main(), not inside it, and board[i][a]=1 is out of previous if statement. \$\endgroup\$ Jan 6 at 11:38
  • \$\begingroup\$ @PavloSlavynskyy done \$\endgroup\$ Jan 6 at 11:47
3
\$\begingroup\$

Overall

Aside from the atrocious format, very nice code for a learner.


Use an auto-formatter!

Avoid manual formatting, yet always run an auto-formatter before code review.

Ding, Ding, Ding!!!

No warnings, even with many enabled. Yeah!

Bug: direction never assigned before use.

char direction;
...
control(direction,&snake[0][0],&snake[0][1]);

Avoid naked magic numbers

//int board[25][64];
//for (int i = 0; i < 25; i++) {
//  for (int a = 0; a < 64; a++) {

#define BOARD_ROWS 25
#define BOARD_COLS 25
int board[BOARD_ROWS][BOARD_COLS];
for (int i = 0; i < BOARD_ROWS; i++) {
  for (int a = 0; a < BOARD_COLS; a++) {

// if(i == 0 || i == 24){
if(i == 0 || i == BOARD_COLS - 1){

And many many other constants too.

Short on comments

I recommend at least a comment/function definition and some overall program comment. Your algorithm belongs in the top of code as a comment.

Alternative to calling rand() twice

// *rowPtr = rand() % 25;
// *colPtr = rand() % 64;
int r = rand() % (BOARD_ROWS * BOARD_COLS);
*rowPtr = r / BOARD_COLS;
*colPtr = r % BOARD_COLS;

Alternative printing

As board[i][a] should be only [0...3]

    //if(board[i][a]==1){
    //    printf("+");
    //}else if(board[i][a]==0){
    //    printf(" ");
    //}else if(board[i][a]==2){
    //    printf("o");
    //}else if(board[i][a]==3){
    //    printf("*");

    // Table look up - in this case a string look up.
    putchar(" +o*"[board[i][a] & 3]);

Initialize function

Consider putting Creating board code in its own function rather than main(). Better if initialization does not rely on global variable initial values and assigns them here.

Collapse repetitive code

// printf("\n");printf("\n");printf("\n");printf("\n");
printf("\n\n\n\n"); // or the like

Advanced: Global variables

As you advance, consider a struct to hold all the global data together and then pass around a pointer to that struct.

Minor: Incomplete prototype

Declaration void print_board(); still allows calls like print_board(42);. Use (void).

// void print_board();
void print_board(void);

C2x may change this and have void print_board(); same as void print_board(void);

Minor: Avoid type change warnings.

// srand(time(NULL));
srand((unsigned) time(NULL));

What is wasd_2486?

Comment or use a better name.

\$\endgroup\$
1
  • \$\begingroup\$ wasd_2486 is actually for taking input to decide which movement we want the snake to go, and the only way to do that is using wasd letters or 2486 numbers, that is why i decided that variable name, but i guess doing something like "input_from_keyboard" would be more readable, thank you for your help! \$\endgroup\$ Jan 7 at 7:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.