Thread: C++ snake

  1. #1
    Registered User
    Join Date
    Nov 2010
    Posts
    6

    C++ snake

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <conio.h>
    #include <time.h>
    
    void draw(char main[][75], int score);
    void reset(char main[][75]);
    void move(char main[][75], int &parts, int pastCounter, int past[][2], int &apples, int &score, int &quit);
    void check (int &direction);
    void directionn(int direction, int &pastCounter, int past[][2]);
    void apple (int &apples, char main[][75]);
    void quitGame (int score);
    
    int main()
    {   //past is an array to help direct when the snakes body will go, 
    	//did it like this so the behind pieces will follow the snakes head
    	int past[1000][2]; //second bracket: 0 is up, 1 is side
    	int parts = 3; //number of snake pieces
    	char main[23][75];   // 23 down, 73 wide is appropriate screen size
    	int pastCounter = 6;  //used in the use of past 
    	int direction = 0;
    	int apples = 0;
    	int score = 0;
    	int quit = 0;
    	int playAgain = 1;
    	srand(time(0));
    
    	//SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),2);  -- color if wanted
    
    	for (int x = 0; x < 1000; x ++) 
    	{
    		for (int y = 0; y < 2; y ++)
    		{
    			past [x][y] = 0;
    		}
    	}
    	past[pastCounter][0] = 1; //keep the game from crashing because if you hit the wall it kicks you from the wall
    	past[pastCounter][1] = 1;
    	while(quit == 0)
    	{  //main rotation through all the game's functions.
    		draw(main, score);
    		check(direction);
    		directionn(direction, pastCounter, past);
    		reset(main);
    		move(main, parts, pastCounter, past, apples, score, quit);
    		Sleep(25); //pause to keep the game a normal speed...
    		if (apples == 0)
    		{  //place more apples only if they are all gone
    			apple(apples, main); 
    		}
    		
    	}
    	quitGame(score);
    	Sleep (10000);
    	//getch();
    
    }
    void draw(char main[][75], int score)
    {//draws the screen
    	system("cls");
    	printf ("Score : %d\n", score);
    	for (int x = 0; x < 23; x ++)
    	{
    		for (int y = 0; y < 75; y ++)
    		{
    			printf ("%c", main[x][y]);
    		}
    		printf ("\n");
    	}
    
    } 
    
    void reset(char main[][75])
    {//resets the array to keep it from being filled with parts of snake that shouldn't be there after the snake has moved on
    	for (int x = 0; x < 23; x++)
    		{
    			for (int y = 0; y < 75; y++)
    			{
    				if (main[x][y] == '@')
    				{  //doesn't reset the apples
    					main[x][y] == '@';
    				}
    				else
    				{
    					if (x == 0 || x == 22 || y == 0 || y == 74)
    					{//doesnt reset the border
    						main[x][y] = 177;
    					}
    					else
    					{
    						main[x][y] = ' ';
    					}
    				}
    			}
    		}
    }
    
    void move(char main[][75], int &parts, int pastCounter, int past[][2], int &apples, int &score, int &quit)
    {//moves the snake head, and has the body follow it
    	if (past[pastCounter][0] == 22 || past[pastCounter][0] == 0)
    	{  //if te snake is on the border of the game you loose
    		quit = 1;
    	}
    	if (past[pastCounter][1] == 74 || past[pastCounter][1] == 0)
    	{
    		quit = 1;
    	}
    
    	for (int x = 0; x < parts; x++)
    	{
    		if (main[past[pastCounter - x][0]][past[pastCounter - x][1]] == '@')
    		{  //if the snake (technically any part of the snake) eats and apple...
    			apples--;
    			parts++;
    			score += 10;
    		}
    		if (main[past[pastCounter - x][0]][past[pastCounter - x][1]] == 'o')
    		{  //if the snake eats itself
    			quit = 1;
    		}
    		else
    		{  //else the snakes new location is determined
    		main[past[pastCounter - x][0]][past[pastCounter - x][1]] = 'o';
    		}
    	}
    }
    void check (int &direction)
    {//checks if there has been user input
    	int key = 0;
    	if (kbhit())
    	{
    		key = -getch();
    		switch (key)
    		{
    		case -72:
    			direction = 2;
    			break;  //up
    		case -77:
    			direction = 0;
    			break; //right
    		case -80:
    			direction = 3;
    			break; //down
    		case -75:
    			direction = 1;
    			break; //left
    		}
    	}
    		
    }
    void directionn(int direction, int &pastCounter, int past[][2])
    {//based on user input, detects which directing the snake head should be going
    	int right;//adding to the array itself did not work, so i worked around it.
    	int down;
    	right = past[pastCounter][1];
    	down = past[pastCounter][0];
    	switch (direction)
    	{  //directs the snake based on direction
    	case 0:
    		right ++;
    		break;
    	case 1:
    		right --;
    		break;
    	case 2:
    		down --;
    		break;
    	case 3:
    		down ++;
    	}
    
    	pastCounter ++;
    	past[pastCounter][0] = down;
    	past[pastCounter][1] = right;
    }
    void apple (int &apples, char main[][75])
    {//places apples on the screen
    	int up = 0;
    	int left = 0;
    	apples = 3;
    
    	for (int x = 0; x < apples; x ++)
    	{ //places appples, only if theres no border of part of the snake already in the space
    		up = (rand() % 22);
    		left = (rand() % 74);
    
    		if (main[up][left] == 'o')
    		{
    			apple(apples, main);
    		}
    		if (main[up][left] == '*')
    		{
    			apple(apples, main);
    		}
    		else
    		{
    			main[up][left] = '@';
    		}
    	}
    }
    
    
    
    
    void quitGame (int score)
    {//quits and displays score
    	int quit = 0;
    	system ("cls");
    	printf ("GAME OVER!!!!\n\n");
    	printf ("You got a score of %d\n", score);
    
    
    }
    this is a code I found for making a snake game using c++. Can anyone explain the functionality of the "past" 2D array? Even with the comments, I cant understand how this array works or how is it doing whatever its doing

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    It stores the coordinates of the snake parts. The snake can be up to 1000 segments long (while 22 * 74 is 1628!?).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Registered User
    Join Date
    Nov 2010
    Posts
    6
    'past[pastCounter][0] = 1; //keep the game from crashing because if you hit the wall it kicks you from the wall
    past[pastCounter][1] = 1;'

    wats the meaning of this initialization?

  4. #4
    Registered User
    Join Date
    Nov 2010
    Posts
    6
    and couldnt this array (to store snake coordinates) have been a 1D array??

  5. #5
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    That's a rather badly written program. I would not recommend studying it in any detail.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #6
    Registered User
    Join Date
    Nov 2010
    Posts
    6
    Quote Originally Posted by iMalc View Post
    That's a rather badly written program. I would not recommend studying it in any detail.

    Why do you say that? I think it's good because it isn't that complicated and doesn't use anything I haven't studied

  7. #7
    Registered User rogster001's Avatar
    Join Date
    Aug 2006
    Location
    Liverpool UK
    Posts
    1,472
    one reason for me is it's not very intuitive to read, the variable names and conventions used are confusing and there are lots of magic numbers, comments aside.

    int pastCounter = 6; //used in the use of past
    what does that say? non-information

    directionn(direction, pastCounter, past);
    That is just asking for trouble, naming one thing 'direction' and another 'directionn', debugging a large file would be like a game of 'where's wally?', 'direction_n' even is only a slight improvement.

    22, 74, 1, 2, 75, 77,80, 23

    Some magical numbers, they should be defined
    LEFT, RIGHT, SCREEN_H , SCREEN_W, for example.

    main[x][y] = 177
    This is supposed to be a char array and also 'main' is the type of variable name i would avoid,: use mainScreen, mainWin, mainData, whatever. I think it is always good to keep your variable names well clear of protected words, keywords etc.

    'past[pastCounter][0] = 1; //keep the game from crashing because if you hit the wall it kicks you from the wall
    past[pastCounter][1] = 1;'

    wats the meaning of this initialization?
    Exactly, even with a comment there you are left no clearer why the statement is like that.
    if the number was defined descriptively you would have a better idea what is intended.
    Last edited by rogster001; 11-19-2010 at 06:39 AM.
    Thought for the day:
    "Are you sure your sanity chip is fully screwed in sir?" (Kryten)
    FLTK: "The most fun you can have with your clothes on."

    Stroustrup:
    "If I had thought of it and had some marketing sense every computer and just about any gadget would have had a little 'C++ Inside' sticker on it'"

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    One thing that is bad about it, is the abundance of magic values: every function is teeming with literal numbers whose meaning you can only guess. Instead it might use global constants, so that '@' becomes apple_symbol etc.

    Another thing is that it seems to keep incrementing pastCounter, meaning that if you play the game long enough, it will crash (trying to access past[1000][x] and beyond.

    The whole thing seems to be rather hacked together and some things are indeed hard to follow. For example, I can't see where main is initialized before it is drawn for the first time (when you move the declaration before past, the first "frame" makes my computer beep because it indeed is outputting uninitialized values.)

    It is also unclear how the snake is set up initially and your question

    'past[pastCounter][0] = 1; //keep the game from crashing because if you hit the wall it kicks you from the wall
    past[pastCounter][1] = 1;'
    indeed leaves the reader puzzled. The corner of the first frame after the uninitialized one looks like this:

    Code:
    Score : 0
    o▒▒▒▒▒▒▒▒▒▒
    ▒oo
    ▒
    ▒
    ▒
    Why the snake starts off like that?? Probably the author had problems because the snake wasn't properly set up, and discovered the "fix" that stops the program from crashing accidentally. That is, the author himself might have no idea what is happening in the program when the game starts.

    When compiled and run, it flickers like hell (because of system("cls") and redrawing the whole board). Instead, since it is already using conio and windows headers, it might only redraw those characters whose values have changed.

    As to making a snake game, I suppose one way to make a more robust one would be to represent the snake with a deque container. When the snake moves, a new segment (pair of coordinates) is added to the front of it, and the last segment is removed (these are the two locations that need to be overdrawn). If the snake swallows an apple, don't erase the last segment (the snake grows).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Take this function for example:
    Code:
    void move(char main[][75], int &parts, int pastCounter, int past[][2], int &apples, int &score, int &quit)
    The author has gone to great lengths to avoid globals. Everything the function needs is individually passed in to the function instead, and they're mostly passed by reference so that it can get AND set them. To me this is no better than simply using globals.
    What this screams for is OOP!

    The commenting is bad, as previously noted.
    Code:
    	char main[23][75];   // 23 down, 73 wide is appropriate screen size
    When you put constants themselves inside the comments and you're not good at updating comments, then sooner or later your comments disagree with the code. When that happens the comments are basically worse than no comments.

    Okay, now lets say we wantedto change the board heaight from 23 to 39. How many places in the code would have to change? Forget simply doing a search and replace, you'd miss some occurrences of 22 which also need updating.

    Code:
    		key = -getch();
    		switch (key)
    		{
    		case -72:
    			direction = 2;
    			break;  //up
    		case -77:
    			direction = 0;
    			break; //right
    		case -80:
    			direction = 3;
    			break; //down
    		case -75:
    			direction = 1;
    			break; //left
    		}
    What the hell is a -72? If only there were some named constant we could use to make this more readable. Why the hell is key negated anyway?!
    So direction = 2 is up huh? Adding comments to tell us that is not the best way to do it. The best code needs no explanation. enums such as this are exactly how it should be done:
    Code:
    enum Direction { RIGHT, LEFT, UP, DOWN };
    So yeah there's plenty of bad habbits one could learn form that code.
    Last edited by iMalc; 11-19-2010 at 01:25 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    Registered User NeonBlack's Avatar
    Join Date
    Nov 2007
    Posts
    431
    Quote Originally Posted by iMalc View Post
    That's a rather badly written program. I would not recommend studying it in any detail.
    I disagree. I've learned a great deal about good code and design from studying (and fixing) poorly written programs. You can teach someone good habits and practices, but he might not understand why it's good until he's directly experienced the pain of doing it the wrong way.
    I copied it from the last program in which I passed a parameter, which would have been pre-1989 I guess. - esbo

  11. #11
    Registered User
    Join Date
    Nov 2010
    Posts
    6
    Quote Originally Posted by anon View Post

    Code:
    Score : 0
    o▒▒▒▒▒▒▒▒▒▒
    ▒oo
    ▒
    ▒
    ▒
    Okay so now I understand most of the things of this program but this corner of the window still puzzles me. Why is this happening?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with snake game in sdl/c
    By joellllmal in forum Game Programming
    Replies: 4
    Last Post: 08-22-2010, 12:14 AM
  2. A snake game - Memory problem
    By gavra in forum C Programming
    Replies: 29
    Last Post: 11-23-2008, 12:58 PM
  3. Need help with a snake game (ncurses)
    By Adam4444 in forum C Programming
    Replies: 11
    Last Post: 01-17-2007, 03:41 PM
  4. Contest - Snake Numbers
    By pianorain in forum Contests Board
    Replies: 46
    Last Post: 06-15-2006, 07:52 AM
  5. Snake
    By Grantyt3 in forum Game Programming
    Replies: 2
    Last Post: 05-24-2006, 01:35 PM