mirror of
https://github.com/abakh/nbsdgames.git
synced 2024-11-02 16:27:18 -04:00
779 lines
15 KiB
C
779 lines
15 KiB
C
/*
|
|
_ _
|
|
(_ | :
|
|
_)NAKE |.'UEL
|
|
|
|
Authored by abakh <abakh@tuta.io>
|
|
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
|
|
|
|
compile with -lm -lncurses
|
|
*/
|
|
#include <curses.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include "config.h"
|
|
#define SAVE_TO_NUM 10
|
|
#define MINLEN 10
|
|
#define MAXLEN 127
|
|
#define MINWID 40
|
|
#define MAXWID 127
|
|
#define LOSE -(MAXWID*MAXLEN)
|
|
#define WIN_LIMIT 5
|
|
//#define REPORT 0
|
|
#ifdef REPORT
|
|
#define reportif(x) if(x){fprintf(lol,#x" is true\n");fflush(lol);}
|
|
#define reportd(x) if(REPORT){fprintf(lol, #x": %ld\n",(long)x);fflush(lol);}
|
|
#define reports(x) if(REPORT){fprintf(lol, "line %d: %s\n",__LINE__,x);fflush(lol);}
|
|
#else
|
|
#define reportif(x)
|
|
#define reportd(x)
|
|
#define reports(x)
|
|
#endif
|
|
|
|
enum {UP=0,RIGHT,DOWN,LEFT};
|
|
enum {BLOCK=0,SURVIVAL,MIRROR,IMITATE};
|
|
typedef signed char byte;
|
|
/* The Plan9 compiler can not handle VLAs */
|
|
#ifdef NO_VLA
|
|
#define len 36
|
|
#define wid 80
|
|
|
|
#ifdef Plan9
|
|
int usleep(long usec) {
|
|
int second = usec/1000000;
|
|
long nano = usec*1000 - second*1000000;
|
|
struct timespec sleepy = {0};
|
|
sleepy.tv_sec = second;
|
|
sleepy.tv_nsec = nano;
|
|
nanosleep(&sleepy, (struct timespec *) NULL);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
#else
|
|
int len,wid;
|
|
#endif//NO_VLA
|
|
typedef struct snake{
|
|
int y;
|
|
int x;
|
|
byte direction;
|
|
byte fp;
|
|
byte strategy;
|
|
byte score;
|
|
chtype color;
|
|
} snake;
|
|
snake p;//player
|
|
snake c;//computer
|
|
byte pscore;
|
|
byte cscore;
|
|
chtype colors[6]={0};
|
|
byte constant_change={0};
|
|
|
|
bool must_win=0;
|
|
FILE* lol;
|
|
|
|
void logo(void){
|
|
mvaddstr(0,0," _ _");
|
|
mvaddstr(1,0,"(_ | : ");
|
|
mvaddstr(2,0," _)NAKE |.'UEL");
|
|
}
|
|
void rectangle(void){
|
|
for(int y=0;y<=len;++y){
|
|
mvaddch(3+y,0,ACS_VLINE);
|
|
mvaddch(4+y,1+wid,ACS_VLINE);
|
|
}
|
|
for(int x=0;x<=wid;++x){
|
|
mvaddch(3,x,ACS_HLINE);
|
|
mvaddch(4+len,x,ACS_HLINE);
|
|
}
|
|
mvaddch(3,0,ACS_ULCORNER);
|
|
mvaddch(4+len,0,ACS_LLCORNER);
|
|
mvaddch(3,1+wid,ACS_URCORNER);
|
|
mvaddch(4+len,1+wid,ACS_LRCORNER);
|
|
}
|
|
|
|
void swap(byte* a,byte* b){
|
|
byte s= *a;
|
|
*a=*b;
|
|
*b=s;
|
|
}
|
|
void swap_long(long* a,long* b){
|
|
long s= *a;
|
|
*a=*b;
|
|
*b=s;
|
|
}
|
|
byte opposite(byte direction){
|
|
switch(direction){
|
|
case UP:
|
|
return DOWN;
|
|
case DOWN:
|
|
return UP;
|
|
case LEFT:
|
|
return RIGHT;
|
|
case RIGHT:
|
|
return LEFT;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
snake fake_move(snake s){
|
|
switch(s.direction){
|
|
case UP:
|
|
s.y=s.y-1;
|
|
break;
|
|
case DOWN:
|
|
s.y=s.y+1;
|
|
break;
|
|
case LEFT:
|
|
s.x=s.x-1;
|
|
break;
|
|
case RIGHT:
|
|
s.x=s.x+1;
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
bool blocked(byte board[len][wid],snake s){
|
|
s=fake_move(s);
|
|
return ( s.y<0 || s.y >=len || s.x<0 || s.x>=wid || board[s.y][s.x] );
|
|
}
|
|
bool better_change_way(byte board[len][wid],snake s){
|
|
if(blocked(board,s)){
|
|
return 1;
|
|
}
|
|
s=fake_move(s);
|
|
if(blocked(board,s)){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
void putfp(byte board[len][wid],snake s){
|
|
if(s.x>=0 && s.y>=0 && s.x<wid && s.y<len){
|
|
board[s.y][s.x]=s.fp+opposite(s.direction);//putting direction for wiping
|
|
}
|
|
}
|
|
void move_snake(byte board[len][wid],snake *s){
|
|
assert(!blocked(board,*s));
|
|
*s=fake_move(*s);
|
|
putfp(board,*s);
|
|
}
|
|
void purs(snake me,int y,int x,byte directions[4]){
|
|
if(me.y<y){
|
|
directions[0]=DOWN;
|
|
directions[3]=UP;
|
|
}
|
|
else{
|
|
directions[0]=UP;
|
|
directions[3]=DOWN;
|
|
}
|
|
|
|
if(me.x<x){
|
|
directions[1]=RIGHT;
|
|
directions[2]=LEFT;
|
|
}
|
|
else{
|
|
directions[1]=LEFT;
|
|
directions[2]=RIGHT;
|
|
}
|
|
int x_dist=abs(x-me.x);
|
|
int y_dist=abs(y-me.y);
|
|
|
|
if(x_dist>y_dist){
|
|
swap(&directions[0],&directions[1]);
|
|
}
|
|
if(x_dist==y_dist && x_dist<3 && directions[0]==me.direction){
|
|
swap(&directions[0],&directions[1]);
|
|
}
|
|
|
|
}
|
|
void avoid(snake me,int y, int x, byte directions[4]){
|
|
purs(me,y,x,directions);
|
|
for(byte i=0;i<4;++i){
|
|
directions[i]=opposite(directions[i]);
|
|
}
|
|
}
|
|
void shuffle(byte directions[4]){
|
|
byte a=rand()%4;
|
|
byte b=rand()%4;
|
|
swap(&directions[a],&directions[b]);
|
|
}
|
|
void enemy_avoid(snake me,snake enemy,byte directions[4]){
|
|
avoid(me,enemy.y,enemy.x,directions);
|
|
}
|
|
void enemy_pursue(snake me,snake enemy,byte directions[4]){
|
|
purs(me,enemy.y,enemy.x,directions);
|
|
}
|
|
void enemy_block(byte board[len][wid],snake me, snake enemy,byte directions[4]){
|
|
snake ahead=enemy;
|
|
switch(enemy.direction){
|
|
case UP:
|
|
if(me.y>enemy.y)//me is to the down of the enemy, so cannot plan to block it's way in advance
|
|
goto JustPursue;
|
|
break;
|
|
case DOWN:
|
|
if(me.y<enemy.y)
|
|
goto JustPursue;
|
|
break;
|
|
case RIGHT:
|
|
if(me.x<enemy.x)
|
|
goto JustPursue;
|
|
break;
|
|
case LEFT:
|
|
if(me.x>enemy.x)
|
|
goto JustPursue;
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
for(byte i=0;i<10;++i){
|
|
if(blocked(board,ahead)||ahead.y==me.y||ahead.x==me.x){
|
|
purs(me,ahead.y,ahead.x,directions);
|
|
return;
|
|
}
|
|
ahead=fake_move(ahead);
|
|
}
|
|
JustPursue:
|
|
purs(me,ahead.y,ahead.x,directions);
|
|
}
|
|
void enemy_mirror(snake me,snake enemy,byte directions[4]){
|
|
int y,x;
|
|
y=len-1-enemy.y;
|
|
x=wid-1-enemy.x;
|
|
purs(me,y,x,directions);
|
|
}
|
|
void enemy_block_mirror(snake me,snake enemy,byte directions[4]){
|
|
int y_dist=abs(me.y-enemy.y);
|
|
int x_dist=abs(me.x-enemy.x);
|
|
|
|
if(y_dist>x_dist){
|
|
purs(me,len-1-enemy.y,enemy.x,directions);
|
|
}
|
|
else{
|
|
purs(me,enemy.y,wid-1-enemy.x,directions);
|
|
}
|
|
}
|
|
void move_to_top(byte array[4],byte index){
|
|
byte newtop=array[index];
|
|
for(byte i=index;i>0;--i){
|
|
array[i]=array[i-1];
|
|
}
|
|
array[0]=newtop;
|
|
}
|
|
void leave_escapes(byte board[len][wid],snake me,byte directions[4]){
|
|
byte s=3;
|
|
for(byte i=0;i<4;i++){
|
|
me.direction=directions[s];
|
|
if(!better_change_way(board,me)){
|
|
move_to_top(directions,s);
|
|
}
|
|
else{
|
|
--s;
|
|
}
|
|
}
|
|
}
|
|
long go_deep(byte board[len][wid],snake me,bool randomize){
|
|
reports("****go deep***");
|
|
if(randomize){
|
|
reports("randomize");
|
|
}
|
|
long m=0;
|
|
byte bumps=0;
|
|
static byte inc=1;
|
|
if(randomize){
|
|
inc=-inc;
|
|
}
|
|
while(!blocked(board,me)){
|
|
me=fake_move(me);
|
|
++m;
|
|
if(m>len+wid){
|
|
return m;
|
|
}
|
|
if(blocked(board,me)||(randomize&&!(rand()%10))){
|
|
snake f=me;
|
|
byte i;
|
|
|
|
if(randomize){
|
|
f.direction=rand()%4;
|
|
}
|
|
|
|
for(i=0;i<4;++i){
|
|
if(f.direction!=opposite(me.direction) || blocked(board,f)){
|
|
me=f;
|
|
break;
|
|
}
|
|
else{
|
|
f.direction+=4+inc;
|
|
f.direction%=4;
|
|
}
|
|
}
|
|
|
|
reports("***BUMP!***");
|
|
reportd(bumps);
|
|
reportd(m);
|
|
|
|
if(bumps==4){
|
|
return m;
|
|
}
|
|
else{
|
|
++bumps;
|
|
}
|
|
|
|
}
|
|
}
|
|
return m;
|
|
|
|
}
|
|
long mnvrblty(byte board[len][wid],snake me,byte depth){
|
|
long m=0;
|
|
long max=0,n,max_n;
|
|
while(m<=4 && !blocked(board,me)){
|
|
me=fake_move(me);
|
|
++m;
|
|
if(depth){
|
|
snake f=me;
|
|
max_n=0;
|
|
for(byte i=0;i<4;++i){
|
|
n=0;
|
|
if(i==opposite(me.direction)){
|
|
continue;
|
|
}
|
|
f.direction=i;
|
|
for(byte j=0;j<10;++j){
|
|
n=go_deep(board,f,j%2);
|
|
if(max_n<n){
|
|
max_n=n;
|
|
}
|
|
if(max_n>len+wid){
|
|
return max_n;
|
|
}
|
|
}
|
|
reports("Then the maximum became:");
|
|
reportd(max_n);
|
|
}
|
|
if(max<m+max_n){
|
|
max=m+max_n;
|
|
}
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
void sort_directions(long data[4],byte directions[4]){
|
|
bool not_sorted=1;
|
|
while(not_sorted){
|
|
not_sorted=0;
|
|
for(byte i=0;i<3;++i){
|
|
if(data[i]<data[i+1]){
|
|
swap_long(&data[i],&data[i+1]);
|
|
swap(&directions[i],&directions[i+1]);
|
|
not_sorted=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void rank_for_survival(byte board[len][wid],snake me,long advantages[4],byte directions[4]){
|
|
long max_adv,adv,sum,sum_positives;
|
|
for(byte i=0;i<4;++i){
|
|
reports("inspecting various directions");
|
|
reportd(i);
|
|
adv=sum=sum_positives=0;
|
|
max_adv=LONG_MIN;
|
|
me.direction= directions[i];
|
|
adv=mnvrblty(board,me,2);//advantage(board,*me,*enemy,depth-1);
|
|
reports("advantage is");
|
|
reportd(adv);
|
|
if(max_adv<adv){
|
|
max_adv=adv;
|
|
}
|
|
advantages[i]=max_adv;
|
|
|
|
reportd(advantages[i]);
|
|
}
|
|
|
|
sort_directions(advantages,directions);
|
|
reportd(advantages[0]);
|
|
reportd(directions[0]);
|
|
reportd(advantages[1]);
|
|
reportd(directions[1]);
|
|
reportd(advantages[2]);
|
|
reportd(directions[2]);
|
|
reportd(advantages[3]);
|
|
reportd(directions[3]);
|
|
}
|
|
void draw(byte board[len][wid]){
|
|
int y,x;
|
|
rectangle();
|
|
mvprintw(1,16,"Computer's wins: %d",c.score);
|
|
mvprintw(2,16,"Your wins: %d",p.score);
|
|
for(y=0;y<len;++y){
|
|
for(x=0;x<wid;++x){
|
|
switch(board[y][x]/4){
|
|
case 1:
|
|
mvaddch(4+y,x+1,' '|A_STANDOUT|c.color);
|
|
break;
|
|
case 2:
|
|
mvaddch(4+y,x+1,' '|A_STANDOUT|p.color);
|
|
break;
|
|
}
|
|
if(board[y][x]<0)
|
|
mvaddch(4+y,x+1,'0'-board[y][x]);
|
|
}
|
|
}
|
|
}
|
|
void help(void){
|
|
nocbreak();
|
|
cbreak();
|
|
erase();
|
|
logo();
|
|
attron(A_BOLD);
|
|
mvprintw(3,0," **** THE CONTROLS ****");
|
|
attroff(A_BOLD);
|
|
mvprintw(4,0,"hjkl/ARROW KEYS : Change direction");
|
|
mvprintw(5,0,"q : Quit");
|
|
mvprintw(6,0,"F1 & F2: Help on controls & gameplay");
|
|
mvprintw(8,0,"Press a key to continue");
|
|
refresh();
|
|
getch();
|
|
erase();
|
|
halfdelay(1);
|
|
}
|
|
void gameplay(void){
|
|
nocbreak();
|
|
cbreak();
|
|
erase();
|
|
logo();
|
|
attron(A_BOLD);
|
|
mvprintw(3,0," **** THE GAMEPLAY ****");
|
|
attroff(A_BOLD);
|
|
move(4,0);
|
|
printw("Don't hit the walls, the other snake and yourself. Kill the other snake.\n");
|
|
refresh();
|
|
getch();
|
|
erase();
|
|
halfdelay(1);
|
|
}
|
|
void sigint_handler(int x){
|
|
endwin();
|
|
puts("Quit.");
|
|
exit(x);
|
|
}
|
|
long decide(byte board[len][wid],snake *me,snake *enemy){
|
|
//do the move that gives the enemy least advantage (or move randomly at depth 0)
|
|
//return 0 if you fail to find a way out
|
|
snake f=*me;//f:future
|
|
static long turn=0;
|
|
reports(" **MOVE***********");
|
|
reportd(turn);
|
|
++turn;
|
|
reportd(me->direction);
|
|
int y_dist=(abs(me->y-enemy->y));
|
|
int x_dist=(abs(me->x-enemy->x));
|
|
int dist=(y_dist+x_dist);
|
|
long g=go_deep(board,*me,1);
|
|
reportd(g);
|
|
long max_survival;
|
|
byte directions[4]={0,1,2,3};
|
|
long advantages[4]={0};
|
|
if(me->strategy==IMITATE ){
|
|
if(abs(me->y-(len-1-enemy->y))+abs(me->x-(wid-1-enemy->x))>3){
|
|
me->strategy=SURVIVAL;
|
|
}
|
|
else{
|
|
me->strategy=IMITATE;
|
|
}
|
|
}
|
|
else if(g<20){
|
|
me->strategy=SURVIVAL;
|
|
}
|
|
else if( dist<20){
|
|
me->strategy=BLOCK;
|
|
}
|
|
else{
|
|
me->strategy=MIRROR;
|
|
}
|
|
bool change_path=0;
|
|
if(better_change_way(board,*me)){
|
|
change_path=1;
|
|
}
|
|
else if(me->strategy==IMITATE){
|
|
change_path=1;
|
|
}
|
|
else if(me->strategy==SURVIVAL){
|
|
reports("SURVIVAL!@#");
|
|
change_path=1;
|
|
}
|
|
else if(me->strategy==MIRROR){
|
|
change_path=better_change_way(board,*me) || ((me->x%2)&&(me->y%3==2)) || ((me->x%2==0)&&(me->y%3==0));
|
|
if(better_change_way(board,*me) && !change_path){
|
|
reports("fuck you");
|
|
}
|
|
}
|
|
else if(me->strategy==BLOCK){
|
|
reports("BLOCK!@#");
|
|
change_path= !(rand()%(dist+1)) || !(rand()%(x_dist+1)) || !(rand()%(y_dist+1));//this one wants to leave escapes
|
|
|
|
if(!change_path && dist<40 && !(rand()%(dist/2+1))){//this one wants to kill
|
|
change_path=1;
|
|
}
|
|
}
|
|
|
|
if(change_path){
|
|
if(me->strategy==IMITATE){
|
|
enemy_mirror(*me,*enemy,directions);
|
|
}
|
|
if(me->strategy==MIRROR){
|
|
enemy_mirror(*me,*enemy,directions);
|
|
//shuffle(directions);
|
|
leave_escapes(board,*me,directions);
|
|
reports("did the leave escapes shit");
|
|
reports("MIRROR");
|
|
}
|
|
else if(me->strategy==BLOCK){
|
|
if(dist<7){
|
|
enemy_pursue(*me,*enemy,directions);
|
|
}
|
|
/*else if(dist<20){
|
|
enemy_block(board,*me,*enemy,directions);
|
|
}*/
|
|
else{
|
|
enemy_block(board,*me,*enemy,directions);
|
|
}
|
|
leave_escapes(board,*me,directions);
|
|
reports("BLOCK");
|
|
}
|
|
|
|
else if(me->strategy==SURVIVAL){
|
|
rank_for_survival(board,*me,advantages,directions);
|
|
reports("SURVIVAL and I am acting upon it");
|
|
|
|
}
|
|
|
|
for(byte i=0;i<4;++i){//if one way is blocked, go for others
|
|
reportd(directions[i]);
|
|
f.direction=directions[i];
|
|
if(!blocked(board,f)){
|
|
if(better_change_way(board,f)){
|
|
reports("YET THIS MOTHER FUCKER CHOSE:");
|
|
reportd(i);
|
|
}
|
|
*me=f;
|
|
move_snake(board,me);
|
|
return 1;
|
|
}
|
|
else{
|
|
reports("this fucker didn't choose:");
|
|
reportd(directions[i]);
|
|
reports("because that way was supposedly blocked.");
|
|
}
|
|
}
|
|
return LOSE;
|
|
}
|
|
|
|
reports("went on");
|
|
move_snake(board,me);
|
|
return 1;
|
|
}
|
|
void init_game(byte board[len][wid]){
|
|
if(p.score>c.score+2 && rand()%2){
|
|
must_win=1;
|
|
}
|
|
if(must_win && p.score>c.score){
|
|
c.strategy=IMITATE;
|
|
}
|
|
else{
|
|
c.strategy=MIRROR;
|
|
}
|
|
|
|
c.direction=0;
|
|
c.y=len/2;
|
|
c.x=wid*9/20;
|
|
c.fp=4;
|
|
c.color=colors[rand()%6];
|
|
p.direction=0;
|
|
p.y=len/2;
|
|
p.x=wid*11/20;
|
|
p.fp=8;
|
|
|
|
do{
|
|
p.color=colors[rand()%6];
|
|
}while(p.color==c.color);
|
|
|
|
for(byte y=0;y<len;++y){
|
|
for(byte x=0;x<wid;++x){
|
|
board[y][x]=0;
|
|
}
|
|
}
|
|
}
|
|
int main(int argc, char** argv){
|
|
#ifdef REPORT
|
|
lol=fopen("lol","w");
|
|
fflush(lol);
|
|
#endif
|
|
bool autoset=0;
|
|
signal(SIGINT,sigint_handler);
|
|
#ifndef NO_VLA
|
|
if(argc>3 || (argc==2 && !strcmp("help",argv[1])) ){
|
|
printf("Usage: %s [len wid]\n",argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if(argc==2){
|
|
puts("Give both dimensions.");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if(argc==3){
|
|
bool lool = sscanf(argv[1],"%d",&len) && sscanf(argv[2],"%d",&wid);
|
|
if(!lool){
|
|
puts("Invalid input.");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if(len<MINLEN || wid<MINWID || len>500 || wid>500){
|
|
puts("At least one of your given dimensions is either too small or too big.");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
}
|
|
else{
|
|
autoset=1;
|
|
}
|
|
#endif
|
|
initscr();
|
|
#ifndef NO_VLA
|
|
if(autoset){
|
|
len=LINES-7;
|
|
if(len<MINLEN)
|
|
len=MINLEN;
|
|
else if(len>MAXLEN)
|
|
len=MAXLEN;
|
|
|
|
wid=COLS-5;
|
|
if(wid<MINWID)
|
|
wid=MINWID;
|
|
else if(wid>MAXWID)
|
|
wid=MAXWID;
|
|
}
|
|
#endif
|
|
srand(time(NULL)%UINT_MAX);
|
|
byte board[len][wid];
|
|
byte win_limit=WIN_LIMIT;
|
|
|
|
reportd(len);
|
|
reportd(wid);
|
|
noecho();
|
|
cbreak();
|
|
keypad(stdscr,1);
|
|
if(has_colors()){
|
|
start_color();
|
|
use_default_colors();
|
|
init_pair(1,COLOR_RED,-1);
|
|
init_pair(2,COLOR_YELLOW,-1);
|
|
init_pair(3,COLOR_GREEN,-1);
|
|
init_pair(4,COLOR_CYAN,-1);
|
|
init_pair(5,COLOR_MAGENTA,-1);
|
|
init_pair(6,COLOR_BLUE,-1);
|
|
for(byte b= 0;b<6;++b){
|
|
colors[b]=COLOR_PAIR(b+1);
|
|
}
|
|
colors[1]|=A_BOLD;
|
|
}
|
|
Start:
|
|
if(c.score==win_limit || p.score==win_limit){
|
|
win_limit=WIN_LIMIT;
|
|
c.score=p.score=0;
|
|
must_win=0;
|
|
}
|
|
if(c.score==p.score && p.score==win_limit-1){
|
|
++win_limit;
|
|
}
|
|
curs_set(0);
|
|
halfdelay(1);
|
|
init_game(board);
|
|
erase();
|
|
int preinput=0,input=0;
|
|
while(1){
|
|
logo();
|
|
draw(board);
|
|
refresh();
|
|
preinput=input;
|
|
input = getch();
|
|
if( input == KEY_F(1) || input=='?' )
|
|
help();
|
|
if( input==KEY_F(2) )
|
|
gameplay();
|
|
if( (input=='k' || input==KEY_UP) && p.y>0 && p.direction != DOWN ){
|
|
p.direction=UP;
|
|
}
|
|
if( (input=='j' || input==KEY_DOWN) && p.y<len-1 && p.direction != UP ){
|
|
p.direction=DOWN;
|
|
}
|
|
if( (input=='h' || input==KEY_LEFT) && p.x>0 && p.direction != RIGHT){
|
|
p.direction=LEFT;
|
|
}
|
|
if( (input=='l' || input==KEY_RIGHT) && p.x<wid-1 && p.direction != LEFT){
|
|
p.direction=RIGHT;
|
|
}
|
|
if( input=='q')
|
|
sigint_handler(0);
|
|
if( input=='p'){
|
|
nocbreak();
|
|
cbreak();
|
|
erase();
|
|
logo();
|
|
attron(A_BOLD);
|
|
mvaddstr(1,13,"PAUSED");
|
|
attroff(A_BOLD);
|
|
getch();
|
|
halfdelay(1);
|
|
}
|
|
if(input!=ERR){
|
|
if(preinput==input){//if it wasn't there, hitting two keys in less than 0.1 sec would not work
|
|
usleep(100000);
|
|
flushinp();
|
|
}
|
|
}
|
|
|
|
|
|
for(byte i=0;i<2;++i){
|
|
if(blocked(board,p)){
|
|
++c.score;
|
|
reports("player died");
|
|
goto Die;
|
|
}
|
|
else{
|
|
move_snake(board,&p);
|
|
}
|
|
|
|
/*if(decide(board,&p,&c) == LOSE){//move, if failed die.
|
|
++c.score;
|
|
reports("computer died");
|
|
goto Die;
|
|
}*/
|
|
if(decide(board,&c,&p) == LOSE){//move, if failed die.
|
|
++p.score;
|
|
reports("computer died");
|
|
goto Die;
|
|
}
|
|
}
|
|
refresh();
|
|
}
|
|
Die:
|
|
nocbreak();
|
|
cbreak();
|
|
draw(board);
|
|
refresh();
|
|
mvprintw(5+len,0,"Game over! Wanna play again?(y/n)");
|
|
curs_set(1);
|
|
input=getch();
|
|
if( input!= 'N' && input!= 'n' && input!='q')
|
|
goto Start;
|
|
endwin();
|
|
return EXIT_SUCCESS;
|
|
}
|