This version is a beta version, and some details need to be improved, but the game is ready and there are no obvious bugs.
/**************************************************************************** * 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();//okvoid Init();//okvoid F_Dis();//okvoid S_Init();//okvoid S_Move();//ok void S_Insert( int y, int x );//okvoid S_Delete();//okint Set_ticker( int n_msecs );//okvoid Key_Control();//okvoid S_Free();//okvoid End(); //okvoid gameover( int n ); //okint 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;}