|
|
@@ -0,0 +1,221 @@ |
|
|
|
/* |
|
|
|
* conio-snake snake game using the <conio.h> API |
|
|
|
* Copyright (c) 2003-2004 Simon Huggins <webmaster#simonhuggins.com> |
|
|
|
* All Rights Reserved |
|
|
|
* |
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any |
|
|
|
* purpose with or without fee is hereby granted, provided that the above |
|
|
|
* copyright notice and this permission notice appear in all copies. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <caca_conio.h> |
|
|
|
|
|
|
|
/* prototypes */ |
|
|
|
void draw_line(int col, int row); |
|
|
|
void show_score(); |
|
|
|
void add_segment(); |
|
|
|
void setup_level(); |
|
|
|
|
|
|
|
/* constants */ |
|
|
|
const int maxrow=15, maxcol=77; |
|
|
|
const int snake_start_col=33,snake_start_row=7; |
|
|
|
const char up_key='a', down_key='z', left_key='o', right_key='p'; |
|
|
|
const int pause_length=500000; |
|
|
|
|
|
|
|
/* global variables */ |
|
|
|
int score, snake_length, speed, obstacles, level, firstpress, high_score=0; |
|
|
|
char screen_grid[maxrow][maxcol]; |
|
|
|
char direction = right_key; |
|
|
|
struct snake_segment { |
|
|
|
int row,col; |
|
|
|
} snake[100]; |
|
|
|
|
|
|
|
int main() |
|
|
|
{ |
|
|
|
|
|
|
|
/* Variable declarations within main() only */ |
|
|
|
char keypress; |
|
|
|
|
|
|
|
do /* restart game loop */ |
|
|
|
{ |
|
|
|
obstacles=4; level=1; score=0; speed=14; |
|
|
|
|
|
|
|
//randomize(); /* Ensure random seed initiated */ |
|
|
|
|
|
|
|
setup_level(); |
|
|
|
|
|
|
|
/* main loop */ |
|
|
|
do |
|
|
|
{ |
|
|
|
delay(speed * pause_length / 50000); /*pause*/ |
|
|
|
|
|
|
|
/* If key has been hit, then check it is a direction key - if so, |
|
|
|
change direction */ |
|
|
|
if (kbhit()) |
|
|
|
{ |
|
|
|
keypress=(char)getch(); |
|
|
|
if((keypress==right_key)||(keypress==left_key)|| |
|
|
|
(keypress==up_key)||(keypress==down_key)) |
|
|
|
direction = keypress; |
|
|
|
} |
|
|
|
|
|
|
|
/* Add a segment to the end of the snake */ |
|
|
|
add_segment(); |
|
|
|
|
|
|
|
/* Blank last segment of snake */ |
|
|
|
gotoxy(snake[0].col,snake[0].row); |
|
|
|
cprintf(" "); |
|
|
|
/* ... and remove it from the array */ |
|
|
|
for (int i=1;i<=snake_length;i++) |
|
|
|
snake[i-1]=snake[i]; |
|
|
|
/* Display snake in yellow */ |
|
|
|
textcolor(YELLOW); |
|
|
|
for (int i=0;i<=snake_length;i++) |
|
|
|
{ |
|
|
|
gotoxy(snake[i].col,snake[i].row); |
|
|
|
cprintf("O"); |
|
|
|
} |
|
|
|
/* keeps cursor flashing in one place instead of following snake */ |
|
|
|
gotoxy(1,1); |
|
|
|
|
|
|
|
/* If first press on each level, pause until a key is pressed */ |
|
|
|
if (firstpress) { while(!kbhit()); firstpress = 0; } |
|
|
|
|
|
|
|
/* Collision detection - walls (bad!) */ |
|
|
|
if ((snake[snake_length-1].row>maxrow+1)||(snake[snake_length-1].row<=1)|| |
|
|
|
(snake[snake_length-1].col>maxcol+1)||(snake[snake_length-1].col<=1)|| |
|
|
|
/* Collision detection - obstacles (bad!) */ |
|
|
|
(screen_grid[snake[snake_length-1].row-2][snake[snake_length-1].col-2]=='x')) |
|
|
|
keypress='x'; /* i.e. exit loop - game over */ |
|
|
|
/* Collision detection - snake (bad!) */ |
|
|
|
for (int i=0;i<snake_length-1;i++) |
|
|
|
if ( (snake[snake_length-1].row)==(snake[i].row) && |
|
|
|
(snake[snake_length-1].col)==(snake[i].col)) |
|
|
|
{ |
|
|
|
keypress='x'; /* i.e. exit loop - game over */ |
|
|
|
break; /* no need to check any more segments */ |
|
|
|
} |
|
|
|
/* Collision detection - food (good!) */ |
|
|
|
if (screen_grid[snake[snake_length-1].row-2][snake[snake_length-1].col-2]=='.') |
|
|
|
{ |
|
|
|
/* increase score and length of snake */ |
|
|
|
score+=snake_length*obstacles; show_score(); snake_length++; add_segment(); |
|
|
|
/* if length of snake reaches certain size, onto next level */ |
|
|
|
if (snake_length==(level+3)*2) |
|
|
|
{ |
|
|
|
score+=level*1000; obstacles+=2; level++; /* add to obstacles */ |
|
|
|
if ((level%5==0)&&(speed>1)) speed--; /* increase speed every 5 levels */ |
|
|
|
setup_level(); /* display next level */ |
|
|
|
} |
|
|
|
} |
|
|
|
} while (keypress!='x'); |
|
|
|
|
|
|
|
/* game over message */ |
|
|
|
if (score > high_score) high_score = score; |
|
|
|
show_score(); |
|
|
|
gotoxy(30,6); textcolor(LIGHTRED); cprintf("G A M E O V E R"); |
|
|
|
gotoxy(30,9); textcolor(YELLOW); cprintf("Another Game (y/n)? "); |
|
|
|
do keypress=getch(); while((keypress!='y')&&(keypress!='n')); |
|
|
|
|
|
|
|
} while (keypress=='y'); |
|
|
|
} |
|
|
|
|
|
|
|
void setup_level() |
|
|
|
{ |
|
|
|
|
|
|
|
/* variables local to setup_level() */ |
|
|
|
int row,col; |
|
|
|
|
|
|
|
/* Set up global variables for new level */ |
|
|
|
snake_length=level+4; direction = right_key; |
|
|
|
firstpress = 1; |
|
|
|
/* Fill grid with blanks */ |
|
|
|
for(row=0;row<maxrow;row++) |
|
|
|
for(col=0;col<maxcol;col++) |
|
|
|
screen_grid[row][col]= ' '; |
|
|
|
|
|
|
|
/* Fill grid with Xs and food */ |
|
|
|
for(int i=0;i<obstacles*2;i++) |
|
|
|
{ |
|
|
|
row= rand()%maxrow; |
|
|
|
col= rand()%maxcol; |
|
|
|
if(i<obstacles) |
|
|
|
screen_grid[row][col]='x'; |
|
|
|
else |
|
|
|
screen_grid[row][col]='.'; |
|
|
|
} |
|
|
|
|
|
|
|
/* Create snake array of length snake_length */ |
|
|
|
for(int i=0;i<snake_length;i++) |
|
|
|
{ |
|
|
|
snake[i].row=snake_start_row; |
|
|
|
snake[i].col=snake_start_col+i; |
|
|
|
} |
|
|
|
|
|
|
|
/* Draw playing board */ |
|
|
|
draw_line(1,1); |
|
|
|
for(row=0;row<maxrow;row++) |
|
|
|
{ |
|
|
|
gotoxy(1,row+2); |
|
|
|
textcolor(LIGHTBLUE); cprintf("|"); |
|
|
|
textcolor(WHITE); |
|
|
|
for(col=0;col<maxcol;col++) |
|
|
|
cprintf("%c",screen_grid[row][col]); |
|
|
|
textcolor(LIGHTBLUE); |
|
|
|
cprintf("|"); |
|
|
|
} |
|
|
|
draw_line(1,maxrow+2); |
|
|
|
|
|
|
|
show_score(); |
|
|
|
gotoxy(2,maxrow+5); |
|
|
|
textcolor(LIGHTRED); |
|
|
|
cprintf("~~ SNAKE GAME~~ Left: %c, Right: %c, Up: %c, Down: %c, Exit: x. Any key to start.", |
|
|
|
left_key,right_key,up_key,down_key); |
|
|
|
} |
|
|
|
|
|
|
|
void draw_line(int col, int row) |
|
|
|
{ |
|
|
|
gotoxy(col,row); textcolor(LIGHTBLUE); |
|
|
|
for (col=0;col<maxcol+2;col++) cprintf("="); |
|
|
|
} |
|
|
|
|
|
|
|
void show_score() |
|
|
|
{ |
|
|
|
textcolor(LIGHTCYAN); |
|
|
|
gotoxy(2,maxrow+3); |
|
|
|
cprintf("Level: %05d",level); |
|
|
|
gotoxy(40,maxrow+3); |
|
|
|
textcolor(LIGHTGREEN); |
|
|
|
cprintf("Score: %05d",score); |
|
|
|
gotoxy(60,maxrow+3); |
|
|
|
textcolor(LIGHTMAGENTA); |
|
|
|
cprintf("High Score: %05d",high_score); |
|
|
|
} |
|
|
|
void add_segment() |
|
|
|
{ |
|
|
|
switch(direction) |
|
|
|
{ |
|
|
|
case(right_key): snake[snake_length].row=snake[snake_length-1].row; |
|
|
|
snake[snake_length].col=snake[snake_length-1].col+1; |
|
|
|
break; |
|
|
|
case(left_key) : snake[snake_length].row=snake[snake_length-1].row; |
|
|
|
snake[snake_length].col=snake[snake_length-1].col-1; |
|
|
|
break; |
|
|
|
case(up_key) : snake[snake_length].row=snake[snake_length-1].row-1; |
|
|
|
snake[snake_length].col=snake[snake_length-1].col; |
|
|
|
break; |
|
|
|
case(down_key) : snake[snake_length].row=snake[snake_length-1].row+1; |
|
|
|
snake[snake_length].col=snake[snake_length-1].col; |
|
|
|
} |
|
|
|
} |
|
|
|
|