How to make a Snake Game ?

How to make a Snake Game ?

Make a Snake Game in Command Prompt using C

Let's say you have completed all the basics for C programming language and want to test your learnings and create some projects. At this point a Snake Game can be a good project to add to your portfolio.

Now to make this game we need to create

  • boundary : we can use " | "(vertical bar) , "_"(underscore) to make the walls.
  • snake : The head is represented as "O"(capital letter o) and the body is represented as "+"(plus sign).
  • fruit : which is represented as "*"(asterisk).

Game Screen

Our game will have below mentioned functionalities

  • The user can control the snake using [ W,A,S,D keys ].
  • After our snake eats a fruit the snakelength and the score will increase.
  • And a new fruit will generate within the boundary and the snake speed will also increase.
  • The boundary walls can be teleport able.
  • After the snake touches itself the game will be over.

Steps to create the game:

Here to perform all the tasks we'll need some variables, build-in functions and some custom functions.

Headers Used:

//Making the Snake Game
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <unistd.h>
#include <time.h>

Variables Used:

int i, j;
// Snake Position
int x, y;
// Snake Node Coordinates
int snakenodeX[1000], snakenodeY[1000];
// Snake Length
int snakelength;
int k, L, P;
// Fruit Position
int fruitx, fruity;
int score, gameover, flag;
int height = 20, width = 56;

These are the Global variables used in our game. We will also need some Local variables at the time when we will write our custom function definition. But before that let's look at some build-in functions

Build-in Functions Used:

  • rand()
  • srand()
  • kbhit()
  • usleep()
rand() The C library function int rand(void) returns a pseudo-random number in the range of 0 to RAND_MAX. RAND_MAX is a constant whose default value may vary between implementations but it is granted to be at least 32767. rand() is defined in the standard library and declared in the <stdlib.h> headers

To generate a new fruit onto a new location we will need a new number everytime when the snake eats the fruit, so that we can feed the new number in the snake co-ordinate variables.

//This programme will print random numbers
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{  
    printf("Random numbers are:");
    for (int i = 0; i < 3; i++)
    {
        int rand_num = rand();
        printf(" %d ", rand_num);
    }
}

Code output: output

If we run the above programme more than once, then we can see the rand() function is generating the same series of numbers again and again. This is where we need the srand() function.

srand() int srand(unsigned seed) function gives a starting point for producing the pseudo-random integer series. The argument is passed as a seed for generating a pseudo-random number, where seed is an integer that is used by srand() function to generate pseudo-random numbers. Whenever a different seed value is used in srand() the pseudo number generator can be expected to generate different series of results. srand() is also defined in the standard library and declared in the <stdlib.h> headers
//This programme will print random numbers
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{  srand(time(0));
    printf("Random numbers are:");
    for (int i = 0; i < 3; i++)
    {
        int rand_num = rand();
        printf(" %d ", rand_num);
    }
}

Code output: output

In this above programme we've used time() function as srand(time(0)); as a seed to generate a different series of numbers everytime it runs.

kbhit() The kbhit() function is basically the Keyboard Hit. Whenever a key is pressed the kbhit() returns a non-zero value otherwise it returns zero. kbhit() can be declared using standard library and defined using <conio.h> headers.
//This programme will show that how we can implement kbhit()
#include <stdio.h>
#include <conio.h>
void main()
{
    do
    {
        printf("Press any key to stop loop.\n");
    } while (!kbhit());
}

Code output: output

In this programme we've used getch() to implement the kbhit() function. getch() function pauses the output console until a key is pressed. It does not use any buffer to store the input character. The entered character is immediately returned without waiting for the enter key.

usleep() usleep() is a C runtime library function built upon system timers. It suspends the current process for the number of microseconds passed to it. And for delaying the current operation for some numbers of seconds and nanoseconds we can use sleep() and nanosleep().
The usleep() is defined using standard library and declared using <unistd.h> for LINUX/UNIX environment and <Windows.h> for the Windows OS.
//This programme will show that how we can implement usleep()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void main()
{
    for (int i = 0; i < 5; i++)
    {
        usleep(600000);
        printf("Snake Saga\n");
    }
}

Code output: output

In this above programme the output will get printed with a delay time of 600000 microseconds or 0.6 seconds/iteration.

So, up untill now we have all the required build-in functions. Now it's time to build our custom funtions.

Custom Functions Used:

  • loading()
  • setup()
  • draw()
  • input()
  • logic()
loading() This function will print the home screen and the loading screen, which contains boundary , ASCII art and the loading graphic. Though it's not a necessary component in our game, so if you want you can omit this function.

//Making the Snake Game
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <unistd.h>
#include <time.h>

int i, j;
// Snake Position
int x, y;
// Snake Node Coordinates
int snakenodeX[1000], snakenodeY[1000];
// Snake Length
int snakelength;
int k, L, P;
// Fruit Position
int fruitx, fruity;
int score, gameover, flag;
int height = 20, width = 56;

//Loading function for printing ASCII art and loading Screen
void loading()
{
    char play;
Start:
    //printing the boundary
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            if (i == 0 || i == height - 1)
            {
                printf("_");
            }
            else if (j == 0 || j == width - 1)
            {
                printf("|");
            }
            else
            {
                printf(" ");
            }
        }
        printf("\n");
    }
    //Printing ASCII art
    gotoxy(4, 8);
    printf(" _____            _          _____                \n");
    gotoxy(4, 9);
    printf("|   __| ___  ___ | |_  ___  |   __| ___  ___  ___ \n");
    gotoxy(4, 10);
    printf("|__   ||   || .’|| ‘_|| -_| |__   || .’|| . || .’|\n");
    gotoxy(4, 11);
    printf("|_____||_|_||__,||_,_||___| |_____||__,||_  ||__,|\n");
    gotoxy(4, 12);
    printf("                                        |___|     \n");

    gotoxy(56, 20);
    printf("\nPress X to Continue!");
    scanf(" %c", &play);

    //Nested Loop for printing the Boundary and Loading...
    if (play == 'x' || play == 'X')
    {
        system("cls");
        for (i = 0; i < height; i++)
        {
            for (j = 0; j < width; j++)
            {
                if (i == 0 || i == height - 1)
                {
                    printf("_");
                }
                else if (j == 0 || j == width - 1)
                {
                    printf("|");
                }
                else
                {
                    printf(" ");
                }
            }
            printf("\n");
        }
        for (int loop = 0; loop < 2; ++loop)
        {
            for (int x = 0; x < 4; ++x)
            {
                gotoxy(24, 10);
                printf("Loading%.*s   \b\b\b", x, "...");
                fflush(stdout); //force printing as no newline in output
                usleep(700000);
            }
        }
    }
    else
    {
        printf("\nInvalid Input!\n");
        goto Start;
    }
}
// Function declaration
int main()
{
    loading();
}

Code Output:

output

Code Explanation:

Firstly we'll take a nested for loop to make the boundary using the variables i and j, where i will be releted to height and j to width. After that we will have to put an if else statement with

1. expression1 printf("_"); , condition when i = 0 and i = height-1
2. expression2 printf("|"); , condition when j = 0 and j = width-1
3. expression3 printf(" "); , condition when i != 0 or j != 0 or i !=height-1 or j != width-1

Shown in the diagram below

Code Explanation

In the diagram above m = height-1 and n = width-1 .

In the next step we will print the ASCII art using gotoxy(int x, int y) function where x = column number and y = row number. The gotoxy() can be declared using <conio.h> headers.

After this we will put an escape condition Press X to Continue! so that our user can move towards the loading screen.

Next we have to print the loading screen which contains the boundary and the loading graphic but before that we'll have to clear the home screen using system("cls") or clrscr() .

Now we have two ways to print the loading graphic. First is using nested for loop and the second one is without using a nested for loop .

Without using nested for loop:

//gotoxy(col, row);
    gotoxy(24, 10);
    printf("Loading");
    usleep(500000);
    gotoxy(24, 10);
    printf("Loading.");
    usleep(500000);
    gotoxy(24, 10);
    printf("Loading..");
    usleep(500000);
    gotoxy(24, 10);
    printf("Loading...");
    usleep(500000);
    getch();

Here we've used the gotoxy(col,row) function to print the loading graphic.

Using nested for loop:

for (int loop = 0; loop < 2; loop++)
        {
            for (int x = 0; x < 4; x++)
            {
                gotoxy(24, 10);
                printf("Loading%.*s   \b\b\b", x, "...");
                fflush(stdout); //force printing as no newline in output
                usleep(700000);
            }
        }

Code Explanation:

Here the first for loop of the nested for loop will control how many times we want our loading... graphic to run and the second for loop will print the loading... graphic using

printf("Loading%.*s   \b\b\b", x, "...");

Here, we've used %.*s . The arguments for %.*s are the string width and the target string.

printf("%.*s", string_width, string);

For our better understanding let's change the code as

printf("Loading%.*s+++\b\b\b", x, "...");

Step by step output when the loop=0

Code Explanation

Here x represents the length of the string to be printed on the screen.

Step by step output when the loop=1

Code Explanation

Here we've used fflush(stdout) to clear (or flush) the output buffer and move the buffered data to console.

After this we'll put an else condition to check whether the user has given the required input or not.

else
    {
        printf("\nInvalid Input!\n");
        goto Start;
    }
setup() In setup() function we will set the snake's initial position by using x and y variables with the help of height and width along with this we will also build the logic for creating the random numbers for fruitx and fruity co-ordinates.
// Setup the snake game
void setup()
{
    //Intialise the Snake
    x = width / 2, y = height / 2;
    snakelength = 0;
    score = 0;
    srand(time(0));
// Initialising fruitx position using rand() function
label1:
    fruitx = rand() % ((width - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    if (fruitx == 0 || fruitx == x)
    {
        goto label1;
    }
// Initialising fruity position using rand() function
label2:
    fruity = rand() % ((height - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    if (fruity == 0 || fruity == y)
    {
        goto label2;
    }
}
// Function declaration
int main()
{
    setup();
}

Code Explanation:

As we've already initialised the boundary variables as height = 20 and width = 56 , here you can take any height or width as you wish. Now we will initialise the snake's initial position as x = width/2 and y = height/2.

Code Explanation

Here the snakelength and score will be 0. After this we have to make the logic to create the random numbers for fruitx and fruity co-ordinates as shown below

srand(time(0));
label1:
//rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    fruitx = rand() % ((width - 3) + 1);
label2:
//rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    fruity = rand() % ((height - 3) + 1);

Here, rand() % (upperlimit-(lowerlimit+1)+lowerlimit) expression will create a new number in between the range of lowerlimit to upperlimit. Where upperlimit = (width-1) and lowerlimit = 1 as the 0th position and the max-width position is occupied by the boundary charecter.
Note that we don't want to generate the fruit at the snake's position. So to counter that we will have to put a if condition.

if (fruitx == 0 || fruitx == x)
    {
        goto label1;
    }

if (fruity == 0 || fruity == y)
    {
        goto label2;
    }
draw() This function will print the boundary , snake ,snakenode and the fruit for our game.
//Draw() funtion definiton
void draw()
{
    system("cls");

    //Nested loop for printing the Boundary
    for (j = 0; j < height; j++)
    {
        for (i = 0; i < width; i++)
        {
            if (j == 0 || j == height - 1)
            {
                printf("_");
            }
            else if (i == 0 || i == width - 1)
            {
                printf("|");
            }
            // Printing snake
            else
            {
                if (i == x && j == y)
                {
                    printf("O");
                }
                else if (i == fruitx && j == fruity)
                {
                    printf("*");
                }
                else
                {
                    printf(" ");
                }
            }
        }
        printf("\n");
    }
}
// Function declaration
int main()
{
    while (!gameover)
    {
        draw();
    }
}

Code Output:

oputput

Note: If we run the above programme we'll not be able to see the snake and the fruit . To have the required output we have to add the setup() function with draw() function.

Code Explanation:

Here at first we have to clear the screen to remove the preveous output. In this way we can see the updated output everytime our programme runs. After that again we have to make the boundary.

In the next step we'll print the snake and the fruit using nested if else statement with,

1. expression1 printf("O"); , condition when i == x && j == y
2. expression2 printf("*"); , condition when i == fruitx && j == fruity

Note that after eating a fruit our snake length will not be increased. For that we need to add some code to our draw() function, which we will do later.(*)

Now it's time to make the next custom function .

input() After making all the visual changes on our game now it's time to take the input from the user. So that we can control the snake using [W,A,S,D keys].
//Input() function definition
void input()
{ //Using Kbhit() to identify the input and getch() to get the input
    if (kbhit())
    {
        switch (getch())
        {
        case 'A':
            flag = 1;
            break;
        case 'a':
            flag = 1;
            break;
        case 'S':
            flag = 2;
            break;
        case 's':
            flag = 2;
            break;
        case 'D':
            flag = 3;
            break;
        case 'd':
            flag = 3;
            break;
        case 'W':
            flag = 4;
            break;
        case 'w':
            flag = 4;
            break;
        case 'X':
            flag = 5;
            break;
        case 'x':
            flag = 5;
            break;
        }
    }
}
// Function declaration
int main()
{
    while (!gameover)
    {
        input();
    }
}

Code Explanation:

Here, we've used the kbhit() function under if condition to check wheather a input is given or not along with that we've used the getch() function with switch case operation to identify what input is given. After getting the input we'll assign a particular value to our flag variable which we'll use in our logic() function.

logic() In this function we will define the movement of the snake adding to that we'll also create the teleportable walls and the gameover graphic.
//Logic() function definition
void logic()
{
    int delay;
    //when score is 0 delay will be 90000 microseconds
    if (score == 0)
    {
        delay = 90000;
    }
    //when score is >0 delay will be decreased
    else if (score != 0)
    {
        delay = 90000 - score * 10;
    }
    usleep(delay);

    switch (flag)
    {
    case 1:
        x--;
        break;
    case 2:
        y++;
        break;
    case 3:
        x++;
        break;
    case 4:
        y--;
        break;
    case 5:
        break;
    }
    // After Eating a fruit
    if (x == fruitx && y == fruity)
    {
        score += 10;
        printf("Score %d", score);
        snakelength++;

        //generate a new fruit
    label3:
        fruitx = rand() % ((width - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
        if (fruitx == 0)
        {
            goto label3;
        }
    label4:
        fruity = rand() % ((height - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)

        if (fruity == 0)
        {
            goto label4;
        }
    }

    if (gameover == 1)
    { //Game Over ASCII art
        gotoxy(8, 8);
        printf(" _____                  _____\n");
        gotoxy(8, 9);
        printf("|   __|___ _____ ___   |     |_ _ ___ ___\n");
        gotoxy(8, 10);
        printf("|  |  | .'|     | -_|  |  |  | | | -_|  _|\n");
        gotoxy(8, 11);
        printf("|_____|__,|_|_|_|___|  |_____|\\_/|___|_|");
    }
    if (gameover == 1)
    {
        gotoxy(56, 20);
        printf("\nScore %d", score);
    }
   //wall teleportation Syntax
    if (x < 1)
    {
        x = width - 1;
    }
    else if (x > width - 1)
    {
        x = 1;
    }
    if (y < 1)
    {
        y = height - 1;
    }
    else if (y > height - 1)
    {
        y = 1;
    }
}

// Function declaration
int main()
{
    while (!gameover)
    {
        logic();
    }
}

Code Explanation:

At the beginning we'll put a if else condition to increase the speed of our snake as the score increases.

After this we'll use a switch() case operation to move the snake

    switch (flag)
    {
    case 1:
        x--;
        break;
    case 2:
        y++;
        break;
    case 3:
        x++;
        break;
    case 4:
        y--;
        break;
    case 5:
        break;

Code Explanation

As we take input as [W, A, S, D, X]; we have to increase or decrease the value of X and Y.

In the next step the score will get increased when x == fruitx and y == fruity and after that a new fruit will be generated at a random new location.

After this whenever the gameover = 1 we'll show the gameover graphic in the screen followed by the score.

if (gameover == 1)
    { //Game Over ASCII art
        gotoxy(8, 8);
        printf(" _____                  _____\n");
        gotoxy(8, 9);
        printf("|   __|___ _____ ___   |     |_ _ ___ ___\n");
        gotoxy(8, 10);
        printf("|  |  | .'|     | -_|  |  |  | | | -_|  _|\n");
        gotoxy(8, 11);
        printf("|_____|__,|_|_|_|___|  |_____|\\_/|___|_|");
    }
if (gameover == 1)
    {
        gotoxy(56, 20);
        printf("\nScore %d", score);
    }

Note: We've not yet built the gameover condition which we'll talk about later.(*)

Now we'll build the teleportable walls.

   //wall teleportation Syntax
    if (x < 1)
    {
        x = width - 1;
    }
    else if (x > width - 1)
    {
        x = 1;
    }
    if (y < 1)
    {
        y = height - 1;
    }
    else if (y > height - 1)
    {
        y = 1;
    }

Here, whenever the snake goes beyond the boundary that means the value of co-ordinate variables which is x and y become x < 1 or x > width - 1 and y < 1 or y > height - 1 we'd just have to change the value as x = width - 1 or x = 1 and y = height - 1 or y = 1

So far we've built the basic Snake Game with some major functionalities that we previously talked about.


(*) Now it's time when we'll add the increasing snake length feature and the gameover condition.

There are two possible approaches for increasing the snake length

1. Using Lists

2. Using Arrays

Adding Increasing Snakelength Feature

Here, we'll add a snake node by using two arrays that are snakenodeX[1000] , snakenodeY[1000] where we will store the snakenode co-ordinates. And to increase the snake length we'll use snakelength variable where we will increase the snakelength every time the snake eats a fruit.

We will do the operation using the code below

//Add this codeblock before the switch case operation in logic() function
    int prevX = snakenodeX[0]; // storing the first node coordinate of snakelengthX & Y array to prevX & Y
    int prevY = snakenodeY[0];
    snakenodeX[0] = x;
    snakenodeY[0] = y;

    for (L = 1; L < snakelength; L++)
    {
        int prev2X = snakenodeX[L];
        int prev2Y = snakenodeY[L];
        snakenodeX[L] = prevX;
        snakenodeY[L] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }

Code Explanation:

Here to put the x and y co-ordinates in snakenodeX[0] and snakenodeY[0]. At first we will have to make the snakenodeX[0] and snakenodeY[0] empty. Now to do that we'll simply put the values of preveous snakenodeX[0] and snakenodeY[0] in prevX and prevY variables.

    int prevX = snakenodeX[0];
    int prevY = snakenodeY[0];
    snakenodeX[0] = x;
    snakenodeY[0] = y;

Here everytime the snake moves the values will get refreshed.

Code Explanation

Now , when the snakelength > 1 , we'll make a for loop where L will be initialised as L = 1 .

Now, for our better understanding let's say snakelength = 2

for (L = 1; 1 < 2; L++)
    {
        int prev2X = snakenodeX[1];
        int prev2Y = snakenodeY[1];
        snakenodeX[1] = prevX;
        snakenodeY[1] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }

Here at first we'll store the stored value of snakenodeX[L] in prev2X and snakenodeY[L] in prev2Y this way the snakenodeX[L] and snakenodeY[1] will be empty, so now we can store prevX and prevY there. After this we'll move the stored value from prev2X to prevX and prev2Y to prevY.

Code Explanation

Now if the snakelength = 3

for (L = 1; 1 < 3 L++)
    {
        int prev2X = snakenodeX[2];
        int prev2Y = snakenodeY[2];
        snakenodeX[2] = prevX;
        snakenodeY[2] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }

Code Explanation

In this way we'll store the individual node co-ordinates.

Gameover Condition

Now whenever the snake will touch itself the game will be over. We'll do this operation by using the code below

//Add this codeblock before gameover ASCII art in logic() function
for (L = 0; L < snakelength; L++)
    {
        if (x == snakenodeX[L] && y == snakenodeY[L])
        {
            gameover = 1;
        }
    }

Code Explanation:

Here with the code above we'll simply check the snake co-ordinates x and y never has the same value as node co-ordinates wich are snakenodeX[L] and snakenodeY[L].

After this we'll put some changes in our draw() function, so that we can print the snakenode.

In place of

else
{
    printf(" ");
}

Add the codeblock below in draw() function

//Add this codeblock in draw() function
else
{
    int ch = 0;
    for (P = 0; P < snakelength; P++)
    {
        if (i == snakenodeX[P] && j == snakenodeY[P])
        {
            printf("+");
            ch = 1;
        }
    }
    if (ch == 0)
    {
        printf(" ");
    }
}

Code Explanation:

At first we'll take a for loop under which we'll check whether the conditions

1. i = snakenodeX[P]

2. j = snakenodeY[P]

Now if the condition is satisfied then the snakenode will get printed and ch = 0 and else if the condition isn't satisfied then ch = 0 in that case a blank space will be printed.

Lastly as we don't need the fruit to be printed on our snakenode's location, so to counter that we'll simply change the label3: and label4: in logic() function

//generate a new fruit
label3 : fruitx = rand() % ((width - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
for (L = 0; L < snakelength; L++)
{
    if (fruitx == 0 || fruitx == snakenodeX[L])
    {
        goto label3;
    }
}
label4 : fruity = rand() % ((height - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
for (L = 0; L < snakelength; L++)
{
    if (fruity == 0 || fruity == snakenodeY[L])
    {
        goto label4;
    }
}

Final Code:

//Making the Snake Game
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <unistd.h>
#include <time.h>

int i, j;

// Snake Position
int x, y;

// Snake Node Coordinates
int snakenodeX[1000], snakenodeY[1000];

// Snake Length
int snakelength;
int k, L, P;

// Fruit Position
int fruitx, fruity;

int score, gameover, flag;
int height = 20, width = 56;

//Loading function for printing ASCII art and loading Screen
void loading()
{
    char play;
Start:
    //printing the boundary
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            if (i == 0 || i == height - 1)
            {
                printf("_");
            }
            else if (j == 0 || j == width - 1)
            {
                printf("|");
            }
            else
            {
                printf(" ");
            }
        }
        printf("\n");
    }
    //Printing ASCII art
    gotoxy(4, 8);
    printf(" _____            _          _____                \n");
    gotoxy(4, 9);
    printf("|   __| ___  ___ | |_  ___  |   __| ___  ___  ___ \n");
    gotoxy(4, 10);
    printf("|__   ||   || .’|| ‘_|| -_| |__   || .’|| . || .’|\n");
    gotoxy(4, 11);
    printf("|_____||_|_||__,||_,_||___| |_____||__,||_  ||__,|\n");
    gotoxy(4, 12);
    printf("                                        |___|     \n");

    gotoxy(56, 20);
    printf("\nPress X to Continue!");
    scanf(" %c", &play);

    //Nested Loop for printing the Boundary and Loading...
    if (play == 'x' || play == 'X')
    {
        system("cls");
        for (i = 0; i < height; i++)
        {
            for (j = 0; j < width; j++)
            {
                if (i == 0 || i == height - 1)
                {
                    printf("_");
                }
                else if (j == 0 || j == width - 1)
                {
                    printf("|");
                }
                else
                {
                    printf(" ");
                }
            }
            printf("\n");
        }
        for (int loop = 0; loop < 2; loop++)
        {
            for (int x = 0; x < 4; x++)
            {
                gotoxy(24, 10);
                printf("Loading%.*s   \b\b\b", x, "...");
                fflush(stdout); //force printing as no newline in output
                usleep(700000);
            }
        }
    }
    else
    {
        printf("\nInvalid Input!\n");
        goto Start;
    }
}

// Setup the snake game
void setup()
{
    //Intialise the Snake
    x = width / 2, y = height / 2;
    snakelength = 0;
    score = 0;
    srand(time(0));
// Initialising fruitx position using rand() function
label1:
    fruitx = rand() % ((width - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    if (fruitx == 0 || fruitx == x)
    {
        goto label1;
    }
// Initialising fruity position using rand() function
label2:
    fruity = rand() % ((height - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
    if (fruity == 0 || fruity == y)
    {
        goto label2;
    }
}

// Draw() funtion definiton
void draw()
{
    system("cls");

    //Nested loop for printing the Boundary
    for (j = 0; j < height; j++)
    {
        for (i = 0; i < width; i++)
        {
            if (j == 0 || j == height - 1)
            {
                printf("_");
            }
            else if (i == 0 || i == width - 1)
            {
                printf("|");
            }
            // Printing snake
            else
            {
                if (i == x && j == y)
                {
                    printf("O");
                }
                else if (i == fruitx && j == fruity)
                {
                    printf("*");
                }
                else
                {
                    int ch = 0;
                    for (P = 0; P < snakelength; P++)
                    {
                        if (i == snakenodeX[P] && j == snakenodeY[P])
                        {
                            printf("+");
                            ch = 1;
                        }
                    }
                    if (ch == 0)
                    {
                        printf(" ");
                    }
                }
            }
        }
        printf("\n");
    }
}

// input() function definition
void input()
{ //Using Kbhit() to identify the input and getch() to get the input
    if (kbhit())
    {
        switch (getch())
        {
        case 'A':
            flag = 1;
            break;
        case 'a':
            flag = 1;
            break;
        case 'S':
            flag = 2;
            break;
        case 's':
            flag = 2;
            break;
        case 'D':
            flag = 3;
            break;
        case 'd':
            flag = 3;
            break;
        case 'W':
            flag = 4;
            break;
        case 'w':
            flag = 4;
            break;
        case 'X':
            flag = 5;
            break;
        case 'x':
            flag = 5;
            break;
        }
    }
}

// logic() function definition
void logic()
{
    int delay;
    //when score is 0 delay will be 90000 microseconds
    if (score == 0)
    {
        delay = 90000;
    }
    //when score is >0 delay will be decreased
    else if (score != 0)
    {
        delay = 90000 - score * 10;
    }

    usleep(delay);

    int prevX = snakenodeX[0]; // storing the first node coordinate of snakelengthX & Y array to prevX & Y
    int prevY = snakenodeY[0];
    snakenodeX[0] = x;
    snakenodeY[0] = y;

    for (L = 1; L < snakelength; L++)
    {
        int prev2X = snakenodeX[L];
        int prev2Y = snakenodeY[L];
        snakenodeX[L] = prevX;
        snakenodeY[L] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }
    switch (flag)
    {
    case 1:
        x--;
        break;
    case 2:
        y++;
        break;
    case 3:
        x++;
        break;
    case 4:
        y--;
        break;
    case 5:
        break;
    }
    // After Eating a fruit
    if (x == fruitx && y == fruity)
    {
        score += 10;
        printf("Score %d", score);
        snakelength++;

        //generate a new fruit
    label3:
        fruitx = rand() % ((width - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
        for (L = 0; L < snakelength; L++)
        {
            if (fruitx == 0 || fruitx == snakenodeX[L])
            {
                goto label3;
            }
        }
    label4:
        fruity = rand() % ((height - 3) + 1); //rand() % (upperlimit-(lowerlimit+1)+lowerlimit)
        for (L = 0; L < snakelength; L++)
        {
            if (fruity == 0 || fruity == snakenodeY[L])
            {
                goto label4;
            }
        }
    }
    for (L = 0; L < snakelength; L++)
    {
        if (x == snakenodeX[L] && y == snakenodeY[L])
        {
            gameover = 1;
        }
    }

    if (gameover == 1)
    { //Game Over ASCII art
        gotoxy(8, 8);
        printf(" _____                  _____\n");
        gotoxy(8, 9);
        printf("|   __|___ _____ ___   |     |_ _ ___ ___\n");
        gotoxy(8, 10);
        printf("|  |  | .'|     | -_|  |  |  | | | -_|  _|\n");
        gotoxy(8, 11);
        printf("|_____|__,|_|_|_|___|  |_____|\\_/|___|_|");
    }
    if (gameover == 1)
    {
        gotoxy(56, 20);
        printf("\nScore %d", score);
    }
    //wall teleportation Syntax
    if (x < 1)
    {
        x = width - 1;
    }
    else if (x > width - 1)
    {
        x = 1;
    }
    if (y < 1)
    {
        y = height - 1;
    }
    else if (y > height - 1)
    {
        y = 1;
    }
}

//function declaration
int main()
{
    loading();
    setup();
    // Untill the game is over
    while (!gameover)
    {
        draw();
        input();
        logic();
    }
}

Note: If you are running this on windows then this code will show you errors on gotoxy() and usleep() functions.

Here's an updated code,

Github: github.com/Shreyosgit/Snake-Game

Gameplay:

GAMEPLAY!

Did you find this article valuable?

Support Shreyos Ghosh by becoming a sponsor. Any amount is appreciated!