/* _ _ (_ | : _)NAKE |.'UEL Authored by abakh 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 . */ #include "common.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}; /* 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=MINLEN,wid=MINWID; #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.xy_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.yenemy.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_nlen+wid){ return max_n; } } reports("Then the maximum became:"); reportd(max_n); } if(maxdirection); 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); 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;yMAXLEN){ fprintf(stderr,"Length too high or low.\n"); } autoset=0; break; case 'w': wid=atoi(optarg); if(widMAXWID){ fprintf(stderr,"Width too high or low.\n"); } autoset=0; break; case 'h': default: printf("Usage:%s [options]\n -l length\n -w width\n -h help\n",argv[0]); return EXIT_FAILURE; break; } } #endif initscr(); #ifndef NO_VLA if(autoset){ len=LINES-7; if(lenMAXLEN) len=MAXLEN; wid=COLS-5; if(widMAXWID) 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)||input=='!') ) gameplay(); if( (input=='k' || (input==KEY_UP||input=='w')) && p.y>0 && p.direction != DOWN ){ p.direction=UP; } if( (input=='j' || (input==KEY_DOWN||input=='s')) && p.y0 && p.direction != RIGHT){ p.direction=LEFT; } if( (input=='l' || (input==KEY_RIGHT||input=='d')) && p.x