Click here to Skip to main content
14,664,481 members
Rate this:
Please Sign up or sign in to vote.
See more:
I wrote this simple snake game using c++, all was working fine until I added the tail functionality using double linked lists, the idea is I have a pointer head pointing on a node called body, when the head is in the same position as a fruit a new body is allocated with a pointer tail pointing on it and depending on what buttons are pressed to generate movement the coordinates are added as you can see in the logic function. Now, I don't see where the problem is but when I added the code to display the tail in the display function for some reason the program stops working right before the line to display the tail. What seems to be the issue ?

CODE:

<pre>#include<iostream>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
using namespace std;

bool gameover;
const int width=20;
const int height=20;
int fruitX, fruitY;
enum directions{STOP=0, LEFT, RIGHT, UP, DOWN};
enum directions dir;
int score;



struct body
{
int x;
int y;
body* next;
body* prev;
}*head=NULL;

body* t;
body* tail;
body* q=head;


void create()
{
gameover=false;

dir=STOP;

head=(body*)malloc(sizeof(body));
head->prev=NULL;
head->next=NULL;
head->x=(width/2)-1;
head->y=(height/2)-1;


fruitX=rand()%width;
fruitY=rand()%height;

score=0;
}

void display()
{
system("cls");

for(int i=0;i<width;i++)
    cout<<"x";
cout<<endl;

for(int j=0;j<height;j++)
{
    for(int i=0;i<width;i++)
    {
        if(i == 0 || i == width-1)
           cout<<"x";
        else if(i == head->x && j == head->y)
           cout<<char(254);
        else if(i == fruitX && j == fruitY)
           cout<<"*";
        else
        {
            bool printTail=false;

            while(q != head)
            {
                q=q->next;
            }
            if(i == q->x && j == q->y)
            {
                cout<<char(254);
                printTail=true;
            }
        if(!printTail)     
           cout<<" ";   
        }   
    }
    cout<<endl;
}
for(int i=0;i<width;i++)
    cout<<"x";
cout<<endl;
cout<<"Score:"<<score;
}

void logic()
{
switch(dir)
{
    case UP:head->y--;break;
    case DOWN:head->y++;break;
    case LEFT:head->x--;break;
    case RIGHT:head->x++;break;
}
if(fruitX == head->x && fruitY == head->y)
{
    fruitX=rand()%width;
    fruitY=rand()%height;
    score++;



    body* tail=(body*)malloc(sizeof(body));
    t=head;
    t->next=tail;
    tail->prev=t;
    t=tail;

    if(dir==RIGHT)
    {
        t->x=t->prev->x++;
        t->y=t->prev->y;
    }
    else if(dir==LEFT)
    {
        t->x=t->prev->x--;
        t->y=t->prev->y;
    }
    else if(dir==UP)
    {
        t->x=t->prev->x;
        t->y=t->prev->y++;
    }
    else if(dir==DOWN)
    {
        t->x=t->prev->x;
        t->y=t->prev->y--;
    }
}

if(head->x > width-1)
  head->x=0;
else if(head->x < 0)
  head->x=width-1;
else if(head->y > height)
  head->y=0;
else if(head->y < 0)
  head->y=height-1;


}

void input()
{
if(kbhit())
{
    switch(getch())
    {
        case 'w':dir=UP;break;
        case 's':dir=DOWN;break;
        case 'd':dir=RIGHT;break;
        case 'a':dir=LEFT;break;
        case 'p':gameover=true;break;
    }
}

}

int main()
{
create();

while(!gameover)
{
    display();
    input();
    logic();
    Sleep(100);
}
}


What I have tried:

I tried to remove the the code to display the tail it worked just fine, added it back again and the same thing happens, so apparently the problem is with the display tail line but I cant figure out why.
Posted
Updated 28-Mar-20 16:46pm
v2
Comments
KarstenK 29-Mar-20 5:19am
   
tip: make a struct for your global vars and use the debugger ;-)

Rate this:
Please Sign up or sign in to vote.

Solution 2

Not a direct solution, but an advice on how to proceed to understand what your code really do.
Quote:
I tried to remove the the code to display the tail it worked just fine, added it back again and the same thing happens, so apparently the problem is with the display tail line but I cant figure out why.

Your code do not behave the way you expect, or you don't understand why !

There is an almost universal solution: Run your code on debugger step by step, inspect variables.
The debugger is here to show you what your code is doing and your task is to compare with what it should do.
There is no magic in the debugger, it don't know what your code is supposed to do, it don't find bugs, it just help you to by showing you what is going on. When the code don't do what is expected, you are close to a bug.
To see what your code is doing: Just set a breakpoint and see your code performing, the debugger allow you to execute lines 1 by 1 and to inspect variables as it execute.

Debugger - Wikipedia, the free encyclopedia[^]

Mastering Debugging in Visual Studio 2010 - A Beginner's Guide[^]
Basic Debugging with Visual Studio 2010 - YouTube[^]

1.11 — Debugging your program (stepping and breakpoints) | Learn C++[^]

The debugger is here to only show you what your code is doing and your task is to compare with what it should do.
-----
Your program look like a simplified version of SnakeByte (40 years old).
Advices and improvements on this game:
- Rather that using the TTY standard output, you should use an output that allow you to move cursor as you need, it allow you to update only changed parts instead of regenerating the whole screen every time.
- Problem: when generating a new fruit, you forgot to check if new fruit is on body of snake.
- Problem: as the snake moves, you forgot to check if head crosses the body.
- Advice: Rather than using a double linked list to store the snake, I would make the 2D map of play field stored as a 2D array. It simplify programming the game.

Snake Byte - Wikipedia[^]
search Google or YouTube with "snakebyte game apple" for more.
   
Rate this:
Please Sign up or sign in to vote.

Solution 3

I don't see any code that displays the tail but one thing I noticed is this :
body* tail=(body*)malloc(sizeof(body));
and you also have a global variable called tail. I always use warning level 4 in Visual Studio and it would tell me the local definition is hiding the global one and warnings are errors for me. I think if you remove the body* part of that definition then the global variable would be used and that would allow logic that accesses tail to work correctly.

One more thing, I would adjust the declarations at the top to look like this :
body * head = NULL;
body * tail = NULL;
body * t = NULL;
body * q = NULL;
and I would avoid using global variables with single letter names. That does not tell you anything about what it is used for and that is VERY important for global variables since, in general, they should be avoided.
   
v3
Rate this:
Please Sign up or sign in to vote.

Solution 1

Put a breakpoint at the beginning of offending code and start a debug session. Execute it line-by-line, watching for the values of variables, and compare what they should get to what they actually got. There must be some discrepancy somewhere, you just have to investigate and find where and why.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100