Created
December 9, 2016 22:12
-
-
Save benbek/ccb773c0eb90cdea0219617818f4f5c7 to your computer and use it in GitHub Desktop.
Amateur Snake game homework, October 2003
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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