Skip to content

Instantly share code, notes, and snippets.

@benbek
Created December 9, 2016 22:12
Show Gist options
  • Save benbek/ccb773c0eb90cdea0219617818f4f5c7 to your computer and use it in GitHub Desktop.
Save benbek/ccb773c0eb90cdea0219617818f4f5c7 to your computer and use it in GitHub Desktop.
Amateur Snake game homework, October 2003
/* Nibbles/Snake
Programmed during the Sukkot holiday by Ben Bekerman */
#include <conio.h> //Basic header file
#include <stdlib.h> //Required by Randomize() and Random()
#include <string.h> //Required for string functions
#include <time.h> //Required by Randomize()
#include <dos.h> //Required by Delay() and by Sound()
/* Defines (consts) */
//Colors used during game
#define colorSnk YELLOW //The color of the snake's body
#define colorNum BROWN //The color of the numbers
#define colorBack BLUE //The screen's background's color
#define colorObst WHITE //The color of the obstacles
#define colorBordr WHITE //The color of the border
#define colorScore RED //The color of the score display
#define colorCrash BLACK //The color of the crash point
#define colorbCras RED //The background color of the crash point
//Sizes
#define maxRow 78 //Row size of the board
#define maxCol 22 //Coloum size of the board
#define maxNum 5 //Maximum number of the random-generated numbers
#define maxScr 40 //Maximum points the user can have
#define cSpeed 10 //The game speed (for coloum), in nanoseconds
#define rSpeed 7 //The game speed (for row), in nanoseconds
//Identifications
#define arenaSnk maxNum+1 //The snake's representation in the Arena
#define arenaObst maxNum+2 //The obstacle's representation in the Arena
//Signs
#define signSnk 254 //‏ -- The snake's representation on the screen
#define signObst 219 // -- The obstacle's representation on the screen
#define signCras 88 //X -- The crash-point's representation on the screen
/* Global variables */
int Arena[maxRow][maxCol]={0}; //Zeroes the initial values of the array
int SnakeX[maxScr+1]={0}; //The "+1" is just for case...
int SnakeY[maxScr+1]={0};
char KeyPress;
/* Functions */
//"Service" Functions
void DrawBorder(int, int, int, int, int);
void Center(char[80],int);
//Main Functions
void Intro(void);
char GetSkill(void);
void PlayNibbles(int);
int StillWantsToPlay(void);
void Quit(void);
//Other Functions
void DrawGame(unsigned long);
void DrawArena(void);
void DoObstacles(int);
void DoNumber(void);
void Erase(int);
void InitSnake(void);
int DoSnake(int,int);
void ResetArrays(void);
//Sound Functions
void WinTune(void);
void ChangeTune(void);
void DeadTune(void);
void main()
/* Main Subroutine */
{
char _skill;
unsigned int level;
textmode(C80); //Forces color, 80x25 screen
randomize();
Intro();
do
{
_skill=GetSkill();
level=_skill-48; //Getting the real value of the skill (1, 2 or 3)
PlayNibbles(level);
ResetArrays();
}
while(StillWantsToPlay());
Quit();
}
void DrawBorder(int BorderType, int xTop, int yTop, int xBot, int yBot)
/* Sub: DrawBorder
Purpose: Drawing a border, creating a frame
In: BorderType - Line's type (whatever ³ (1-Single) or ÷ (2-Double)
xTop & yTop - Coordinates of the left-topmost spot of the border
xBot & yBot - Coordinates of the right-bottommost spot of the border
Out: Nothing */
{
int count;
if (BorderType==1)
{
gotoxy(xTop, yTop);
cprintf("");
for (count=1; count<(xBot-xTop); count++)
{
gotoxy(xTop+count,yTop);
cprintf("ִ");
}
gotoxy(xBot,yTop);
cprintf("¿");
for (count=1; count<(yBot-yTop); count++)
{
gotoxy(xTop,yTop+count);
cprintf("³");
}
gotoxy(xTop,yBot);
cprintf("ְ");
for (count=1; count<(xBot-xTop); count++)
{
gotoxy(xTop+count,yBot);
cprintf("ִ");
}
for (count=1; count<(yBot-yTop); count++)
{
gotoxy(xBot,yTop+count);
cprintf("³");
}
gotoxy(xBot,yBot);
cprintf("");
} else //Other board type
{
gotoxy(xTop, yTop);
cprintf("ֹ");
for(count=1; count<(xBot-xTop); count++)
{
gotoxy(xTop+count,yTop);
cprintf("ֽ");
}
gotoxy(xBot,yTop);
cprintf("»");
for (count=1; count<(yBot-yTop); count++)
{
gotoxy(xTop,yTop+count);
cprintf("÷");
}
gotoxy(xTop,yBot);
cprintf("ָ");
for (count=1; count<(xBot-xTop); count++)
{
gotoxy(xTop+count,yBot);
cprintf("ֽ");
}
for (count=1; count<(yBot-yTop); count++)
{
gotoxy(xBot,yTop+count);
cprintf("÷");
}
gotoxy(xBot,yBot);
cprintf("¼");
}
}
void Center(char Text[80], int Coloum)
/* Centers the text on the screen */
{
gotoxy((80-strlen(Text))/2, Coloum);
cprintf(Text);
}
void Intro(void)
/* Prints the introduction and the instructions */
{
_setcursortype(_NOCURSOR);
textbackground(BLACK);
clrscr();
textcolor(LIGHTGRAY);
cprintf("Ben Bekerman proudly presents:");
textcolor(LIGHTGREEN);
DrawBorder(2,1,7,80,19);
Center("¹ N I B B L E S ּ",7);
textcolor(WHITE);
window(2,9,79,18);
cprintf(" Instructions:\r\n\n");
cprintf(" - Select one of three skill levels: Easy, medium and hard.\r\n");
cprintf(" - Use the arrow keys to maneuver the snake.\r\n");
cprintf(" - By collecting points (represented by numbers) your body is extended by 1.\r\n");
cprintf(" - Try not to run into yourself, the walls or the obstacle(s) (if exist).\r\n");
cprintf(" - Press 'p' to pause during the game and 'x' to exit.\r\n\n");
cprintf(" And most importantly, have fun!\r\n");
window(1,1,80,25);
textcolor(MAGENTA);
Center("Press any key to continue...",25);
getch();
}
char GetSkill(void)
/* Getting the skill level for the game */
{
char Skill;
textbackground(BLACK);
clrscr();
textcolor(LIGHTBLUE);
DrawBorder(1,24,4,55,6);
Center("´ Type in the skill level: ֳ",4);
textcolor(LIGHTCYAN);
Center("The skill levels are: ",17);
Center("1 - Easy; No obstacles ",18);
Center("2 - Medium; 3 fixed obstacles",19);
Center("3 - Hard; 1 random obstacle ",20);
textcolor(LIGHTGRAY);
_setcursortype(_NORMALCURSOR);
do
{
gotoxy(39,5);
Skill=getch();
}
while(Skill<'1'||Skill>'3');
return Skill;
}
void PrintScore(unsigned long _Score)
/* Placing the player's score */
{
char _ScoreTemp[80]="",Score[80]="";
ultoa(_Score,_ScoreTemp,10);
strcat(Score,"Score: ");
strcat(Score,_ScoreTemp);
gotoxy(80-strlen(Score),1);
textcolor(colorScore);
cprintf("%s",Score);
}
void DrawGame(unsigned long Nikud)
/* Draws the entire game board onto the screen */
{
unsigned int count;
textbackground(colorBack);
window(1,1,80,25);
clrscr();
textcolor(LIGHTGREEN);
cprintf("Nibbles!");
PrintScore(Nikud);
//Drawing the outside border
textcolor(colorBordr);
for (count=1; count<79; count++)
{
gotoxy(1+count,2);
cprintf("");
}
for (count=1; count<23; count++)
{
gotoxy(1,2+count);
cprintf("");
}
for (count=1; count<79; count++)
{
gotoxy(1+count,25);
cprintf("");
}
for (count=1; count<23; count++)
{
gotoxy(80,2+count);
cprintf("");
}
//Drawing from the Arena
DrawArena();
}
void DrawArena(void)
/* Draws the contains of the Arena onto the screen */
{
int i,count;
for(count=0;count<maxRow;count++)
for(i=0;i<maxCol;i++)
switch(Arena[count][i])
{
case arenaSnk:
{
textcolor(colorSnk);
gotoxy(count+2,i+3);
cprintf("%c",signSnk);
break;
}
case arenaObst:
{
textcolor(colorObst);
gotoxy(count+2,i+3);
cprintf("%c",signObst);
break;
}
case 0: break;
default:
{
textcolor(colorNum);
gotoxy(count+2,i+3);
cprintf("%d",Arena[count][i]);
}
}
}
void DoObstacles(int HowMuch)
/* Creates obstacles and positions them */
{
int i,j,obX,obY,kivun,leng,degel;
for(i=1;i<=HowMuch;i++)
{
do
{
//Initialize obstacle
degel=0;
obX=random(maxRow);
obY=random(maxCol);
kivun=(random(4)+1)*2;
leng=random(3)+3;
//Check for bounderies
switch(kivun)
{
case 2:
{ //Down
if(obY+leng>=maxCol)
degel=1; //Errornous flag
break;
}
case 4:
{ //Left
if(obX-leng<0)
degel=1;
break;
}
case 6:
{ //Right
if(obX+leng>=maxRow)
degel=1;
break;
}
case 8:
{ //Up
if(obY-leng<0)
degel=1;
break;
}
}
//Check the arena
if(degel==0)
degel=Arena[obX][obY];
if(degel==0)
{
j=1;
switch(kivun)
{
case 2:
{ //Down
while(degel==0&&j<=leng)
{
degel=Arena[obX][obY+j];
j++;
}
break;
}
case 4:
{ //Left
while(degel==0&&j<=leng)
{
degel=Arena[obX-j][obY];
j++;
}
break;
}
case 6:
{ //Right
while(degel==0&&j<=leng)
{
degel=Arena[obX+j][obY];
j++;
}
break;
}
case 8:
{ //Up
while(degel==0&&j<=leng)
{
degel=Arena[obX][obY-j];
j++;
}
break;
}
}
}
}
while(degel!=0);
//Finally, we have a obstacle!
switch(kivun)
{
case 2:
{ //Down
for(j=0;j<leng;j++)
Arena[obX][obY+j]=arenaObst;
break;
}
case 4:
{ //Left
for(j=0;j<leng;j++)
Arena[obX-j][obY]=arenaObst;
break;
}
case 6:
{ //Right
for(j=0;j<leng;j++)
Arena[obX+j][obY]=arenaObst;
break;
}
case 8:
{ //Up
for(j=0;j<leng;j++)
Arena[obX][obY-j]=arenaObst;
break;
}
}
}
}
void DoNumber(void)
/* Generates a number (for the points) and determines its position */
{
int numX,numY;
do
{
numX=random(maxRow);
numY=random(maxCol);
}
while(Arena[numX][numY]!=0);
Arena[numX][numY]=random(maxNum)+1;
}
void Erase(int ident)
/* Deletes an object from the Arena and from the screen
"ident" represent what to search and destroy; 0 means a number */
{
int i,j;
for(i=0;i<maxRow;i++)
for(j=0;j<maxCol;j++)
{
if(ident==0)
{
if(Arena[i][j]>0&&Arena[i][j]<=maxNum)
{
Arena[i][j]=0;
gotoxy(i+2,j+3);
cprintf(" ");
}
}
else
if(Arena[i][j]==ident)
{
Arena[i][j]=0;
gotoxy(i+2,j+3);
cprintf(" ");
}
}
}
void InitSnake(void)
/* Updating the snake's initiate position */
{
int snkX,snkY;
snkX=random(maxRow-1);
snkY=random(maxCol-1);
Arena[snkX][snkY]=arenaSnk;
SnakeX[0]=snkX;
SnakeY[0]=snkY;
}
int DoSnake(int kivun, int kama)
/* Updating the snake's status
Returns 0 if the snake has moved
1 if the snake has grown
2 if the snake got out of bounds
3 if the snake crashed (into itself or into an obstacle) */
{
int i=0,degel=0;
for(i=kama;i>0;i--)
{
SnakeX[i]=SnakeX[i-1];
SnakeY[i]=SnakeY[i-1];
}
switch(kivun)
{
case 8:
{
SnakeY[0]--;
break;
}
case 6:
{
SnakeX[0]++;
break;
}
case 4:
{
SnakeX[0]--;
break;
}
case 2:
{
SnakeY[0]++;
break;
}
}
if(SnakeX[0]<0||SnakeX[0]>=maxRow||SnakeY[0]<0||SnakeY[0]>=maxCol)
{
degel=2;
}
else if(Arena[SnakeX[0]][SnakeY[0]]>0 && \
Arena[SnakeX[0]][SnakeY[0]]<=maxNum)
{
//Can't update the Arena, the points number is there!
degel=1;
}
else if(Arena[SnakeX[0]][SnakeY[0]]==arenaObst || \
Arena[SnakeX[0]][SnakeY[0]]==arenaSnk)
{
Erase(arenaSnk);
for(i=0;i<kama;i++)
Arena[SnakeX[i]][SnakeY[i]]=arenaSnk;
degel=3;
}
else
{
Erase(arenaSnk);
for(i=0;i<kama;i++)
Arena[SnakeX[i]][SnakeY[i]]=arenaSnk;
}
return degel;
}
void PlayNibbles(int skill)
/* Controlls the game's progress */
{
unsigned long Score=0;
int StopPlay=0;
int direction=0,olddir,len=1,matzav=0;
_setcursortype(_NOCURSOR);
//Place the head of the snake
InitSnake();
//Initialize game board
if(skill==2)
DoObstacles(3);
else if(skill==3)
DoObstacles(1);
DoNumber();
DrawGame(Score);
gotoxy(1,1);
textcolor(LIGHTRED+BLINK);
cprintf("Press one of the arrow keys to start moving to that direction");
do
{
KeyPress=getch();
if(KeyPress==0)
{
KeyPress=getch();
switch(KeyPress) //72 Up key; 80 Down key; 75 Left; 77 Right
{
case 72:
{
direction=8;
break;
}
case 80:
{
direction=2;
break;
}
case 75:
{
direction=4;
break;
}
case 77:
{
direction=6;
break;
}
}
}
}
while(direction==0);
olddir=direction;
DrawGame(Score);
matzav=DoSnake(direction,len);
do //Main Loop
{
//Check the head of the snake
switch(matzav)
{
case 0: break;
case 2:
{
//Bounderies?
/* */
//If we'll draw here the Arena, it will overflow
//Redraw (one last time) it manually
gotoxy(SnakeX[len]+2,SnakeY[len]+3);
cprintf(" ");
gotoxy(SnakeX[0]+2,SnakeY[0]+3);
textcolor(colorSnk);
cprintf("%c",signSnk);
}
case 3:
{
//Obstacles?
//Itself?
gotoxy(SnakeX[0]+2,SnakeY[0]+3);
textcolor(colorCrash);
textbackground(colorbCras);
cprintf("%c",signCras);
textbackground(colorBack);
StopPlay=1;
DeadTune();
break;
}
default:
{
//Numbers!
Score+=Arena[SnakeX[0]][SnakeY[0]];
PrintScore(Score);
if(Score>=maxScr)
{
gotoxy(SnakeX[0]+2,SnakeY[0]+3);
textcolor(colorSnk);
cprintf("%c",signSnk);
WinTune();
StopPlay=1;
}
else
{
if(skill==3)
{
Erase(arenaObst);
DoObstacles(1);
}
len++;
DoNumber();
ChangeTune();
}
break;
}
}
if(kbhit()!=0&&StopPlay==0)
{
KeyPress=getch();
if(KeyPress==0)
{
KeyPress=getch();
switch(KeyPress)
{
case 72:
{
olddir=direction;
direction=8;
if(olddir==2)
direction=olddir;
break;
}
case 80:
{
olddir=direction;
direction=2;
if(olddir==8)
direction=olddir;
break;
}
case 75:
{
olddir=direction;
direction=4;
if(olddir==6)
direction=olddir;
break;
}
case 77:
{
olddir=direction;
direction=6;
if(olddir==4)
direction=olddir;
break;
}
}
}
else
switch(KeyPress)
{
case 'P':
case 'p':
{
gotoxy(SnakeX[0]+2,SnakeY[0]+3);
textcolor(colorSnk+BLINK);
cprintf("%c",signSnk);
gotoxy(1,1);
textcolor(LIGHTRED+BLINK);
textbackground(colorBack);
cprintf("Paused. Press any key to continue...");
getch();
DrawGame(Score);
break;
}
case 'X':
case 'x':
{
StopPlay=1;
break;
}
}
}
if(StopPlay==0)
{
if(direction==4||direction==6)
delay(rSpeed*10);
else
delay(cSpeed*10);
matzav=DoSnake(direction,len);
DrawArena();
}
}
while(StopPlay==0);
gotoxy(1,1);
textcolor(LIGHTRED+BLINK);
textbackground(colorBack);
cprintf("Game over. Press any key to exit...");
getch();
}
void DeadTune(void)
/* Plays the dead tune using the internal speaker */
{
sound(220); // Beep
delay(200); // For 200 ms
sound(320);
delay(200);
sound(500);
delay(200);
nosound(); // Relief!
}
void WinTune(void)
/* Plays the winning tune via the internal speaker */
{
sound(600);
delay(50);
sound(700);
delay(50);
sound(800);
delay(50);
sound(700);
delay(50);
sound(600);
delay(50);
nosound();
}
void ChangeTune(void)
/* Plays a tune when the snake "eats" a number */
{
sound(800);
delay(40);
nosound();
}
int StillWantsToPlay(void)
/* Asks the user if he/she wants to play again */
{
textcolor(LIGHTGREEN);
textbackground(colorBack);
Center("ִִ> Play Again? (Y/N) <ִִ",13);
do
KeyPress=getch();
while(KeyPress!='Y'&&KeyPress!='y'&&KeyPress!='N'&&KeyPress!='n');
switch(KeyPress)
{
case 'Y':
case 'y':
return 1;
break;
default:
return 0;
}
}
void ResetArrays(void)
/* Zeroes the three global arrays */
{
int i,count;
for(i=0; i<maxRow; i++)
for(count=0; count<maxCol; count++)
Arena[i][count]=0;
for(i=0; i<=maxScr; i++)
{
SnakeX[i]=0;
SnakeY[i]=0;
}
}
void Quit(void)
/* Return all settings to normal */
{
textmode(C80);
_setcursortype(_NORMALCURSOR);
textbackground(BLACK);
textcolor(LIGHTGRAY);
clrscr();
cprintf("Thank you for playing Nibbles!\r\n\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment