/* _ _ (_ | : _)NAKE |.'UEL Authored by abakh 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 #include #include #include #include #include #include #include #include #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.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); 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;y3 || (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(len500 || 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(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) ) gameplay(); if( (input=='k' || input==KEY_UP) && p.y>0 && p.direction != DOWN ){ p.direction=UP; } if( (input=='j' || input==KEY_DOWN) && p.y0 && p.direction != RIGHT){ p.direction=LEFT; } if( (input=='l' || input==KEY_RIGHT) && p.x