此版本为测试版,还有些细节问题需要改善,不过已经可以正常游戏,没有明显的bug
/****************************************************************************
* snake.c
*
* Author:SamBrown
*
*
* Implements the game of Snake.
***************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<curses.h>
#include<sys/time.h>
#include<signal.h>
#include <unistd.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define Start_Error "Error starting up ncurses!\n"
#define ICON_FOOD '*'
#define ICON_BUG '#'
#define ICON_SNAKE '@'
#define CRASH_WALL 1
#define CRASH_ITSELF 2
#define WIN 3
#define BLANK ' '
#define ARGC_ERR "your input is wrong, eg: ./snake 2"
typedef struct Snake
{
int x, y;
struct Snake * next;
struct Snake * pre;
}Snake;
typedef struct Food_Pos
{
int x, y;
}Food;
int a = 1, b= 1;
Food food;
int dirx, diry;
int speed = 2, control = 2;
int length;
Snake *head;
Snake *tail;
bool Start(); //ok
void Init(); //ok
void F_Dis(); //ok
void S_Init(); //ok
void S_Move(); //ok
void S_Insert( int y, int x ); //ok
void S_Delete(); //ok
int Set_ticker( int n_msecs ); //ok
void Key_Control(); //ok
void S_Free(); //ok
void End(); //ok
void gameover( int n ); //ok
int main( int argc, char * argv[] )
{
if( argc != 2 )
{
fprintf( stderr, ARGC_ERR );
exit( 0 );
}
if( strcmp( argv[1], "1" ) != 0 )
{
fprintf( stderr, "sorry, we just support one player now" );
exit( 0 );
}
if( !Start() )
{
fprintf(stderr, Start_Error );
return 0;
}
Init();
F_Dis();
S_Init();
signal( SIGALRM, S_Move );
Set_ticker( 50 );
Key_Control();
End();
return 0;
}
void S_Move( )
{
char c;
int move = 0;
signal(SIGALRM, SIG_IGN);
/* Crash Wall */
if( (head->y+diry <= 1 && diry == -1) ||
(head->y+diry >= LINES && diry == 1 ) ||
(head->x+dirx <= 1 && dirx == -1 ) ||
(head->x+dirx >=COLS && dirx == 1 )
)
gameover( CRASH_ITSELF );
/* Crash itself */
c = mvinch( head->y+diry, head->x+dirx );
mvprintw( 0, 0, "%c", c );
if( c == '@' )
gameover( CRASH_ITSELF );
if( speed > 0 && control-- == 1 )
{
S_Insert( head->y+diry, head->x+dirx );
/* reset the speed of the snake */
control = speed;
move = 1;
}
if( move )
{
/* Eat the Food */
if( head->y == food.y && head->x == food.x )
{
length++;
if( length > 20 )
gameover( WIN );
F_Dis();
}
else
{
mvaddch( tail->y, tail->x, ' ' );
S_Delete( );
}
/* refresh */
mvaddch( head->y, head->x, ICON_SNAKE );
refresh();
}
signal( SIGALRM, S_Move );
}
void gameover(int n)
{
switch( n )
{
case WIN:
mvaddstr(LINES / 2, COLS / 3 - 4, "Mission Completes,press any key to exit.\n");
break;
case CRASH_WALL:
mvaddstr(LINES/2, COLS/3 - 4, "Game Over, crash the wall,press any key to exit.\n");
break;
case CRASH_ITSELF:
mvaddstr(LINES/2, COLS/3 - 4, "Game Over, crash yourself,press any key to exit.\n");
break;
default:
break;
}
refresh();
/* delete the whole double linked list */
End();
}
void S_Free()
{
Snake *temp;
Snake *ne;
temp = head;
while( temp != tail )
{
ne = temp->pre;
free( temp );
temp = ne;
}
free( tail );
}
void S_Insert( int y, int x )
{
Snake * temp = (Snake *)malloc( sizeof(Snake) );
if( temp == NULL )
perror( "malloc error" );
temp->x = x;
temp->y = y;
head->next = temp;
temp->pre = head;
temp->next = NULL;
head = temp;
}
void S_Delete()
{
Snake *temp;
temp = tail->next;
tail->next = NULL;
free( tail );
tail = temp;
}
void End()
{
/* turn off the timer */
S_Free();
Set_ticker(0);
getchar();
endwin();
exit(0);
}
void Key_Control()
{
int key;
keypad( stdscr, true );
while( key = getch() , key != 'q' )
{
switch( key )
{
case KEY_LEFT:
if( length > 1 && dirx == 1 && diry == 0 )
continue;
dirx = -1;
diry = 0;
break;
case KEY_RIGHT:
if( length > 1 && dirx == -1 && diry == 0 )
continue;
dirx = 1;
diry = 0;
break;
case KEY_UP:
if( length > 1 && dirx == 0 && diry == 1 )
continue;
dirx = 0;
diry = -1;
break;
case KEY_DOWN:
if( length > 1 && dirx == 0 && diry == -1 )
continue;
dirx = 0;
diry = 1;
break;
}
}
}
int Set_ticker(int n_msecs)
{
struct itimerval new_timeset;
long n_sec, n_usecs;
n_sec = n_msecs / 1000; /* int second part */
n_usecs = (n_msecs % 1000) * 1000L; /* microsecond part */
new_timeset.it_interval.tv_sec = n_sec; /* set reload */
new_timeset.it_interval.tv_usec = n_usecs;
new_timeset.it_value.tv_sec = n_sec; /* set new ticker value */
new_timeset.it_value.tv_usec = n_usecs;
return setitimer(ITIMER_REAL, &new_timeset, NULL);
}
void S_Init()
{
dirx = 1;
diry = 0;
/* At the beginning the length of snake is 1 */
length = 1;
Snake *temp = ( Snake* )malloc( sizeof(Snake) );
if( temp == NULL )
perror("malloc");
temp->x = 5;
temp->y = 10;
head = temp;
tail = temp;
temp->next = NULL;
temp->pre = NULL;
mvaddch(temp->y, temp->x, ICON_SNAKE );
refresh();
}
void Init()
{
/* the init interface */
mvprintw( LINES/2, COLS/2, "The Snake...\n" );
mvprintw( LINES/2+1, COLS/2, "Author:SamBrown\n" );
mvprintw( LINES/2+2, COLS/2, "<-^-> Control\n " );
mvprintw( LINES/2+3, COLS/2, "press any key to continue...\n");
getch();
clear();
}
void F_Dis()
{
srand(time(0));
food.x = rand() % (COLS-5);
food.y = rand() % (LINES-5);
// food.x = 20;
// food.y = 10;
mvaddch(food.y, food.x, ICON_FOOD);/* display the food */
refresh();
}
bool Start( )
{
// initialize ncurses
if (initscr() == NULL)
return false;
// prepare for color if possible
if (has_colors())
{
// enable color
if (start_color() == ERR || attron(A_PROTECT) == ERR)
{
endwin();
return false;
}
}
// don't echo keyboard input
if ( noecho() == ERR )
{
endwin();
return false;
}
// disable line buffering and certain signals
if ( raw() == ERR )
{
endwin();
return false;
}
// enable arrow keys
if (keypad(stdscr, true) == ERR)
{
endwin();
return false;
}
/* set cursor invisible */
curs_set(0);
crmode();
// wait 1000 ms at a time for input
timeout(1000);
// w00t
return true;
}