mirror of
https://github.com/abakh/nbsdgames.git
synced 2024-12-04 14:46:22 -05:00
781 lines
16 KiB
C
781 lines
16 KiB
C
/*
|
|
_ _
|
|
(_ | :
|
|
_)NAKE |.'UEL
|
|
|
|
|
|
Authored by abakh <abakh@tuta.io>
|
|
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
|
|
|
|
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
*/
|
|
#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;
|
|
}
|