From 4a90dff198ef6670fe372b946b602e53075ef4e2 Mon Sep 17 00:00:00 2001 From: untakenstupidnick Date: Sat, 3 Aug 2019 19:58:27 +0430 Subject: [PATCH] test exe --- battleship_test.exe | 622 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 battleship_test.exe diff --git a/battleship_test.exe b/battleship_test.exe new file mode 100644 index 0000000..40f41df --- /dev/null +++ b/battleship_test.exe @@ -0,0 +1,622 @@ +#include +#include +#include +#include +#include +#include +#define MISS -2 +#define SEA -1 +#define HIT 0 +#define ENGLISH_LETTERS 26 +#define NOTHING -1 +#define ALL 0x7c +#define RED 3 +#define CYAN 2 +/* + _ +|_) +|_)ATTLESHIP + +Authored by Hossein Bakhtiarifar +No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law. + +compile with -lncurses +*/ +typedef signed char byte; +typedef unsigned char bitbox; +bool multiplayer; +byte py,px;//cursor + +chtype colors[4]={0}; + +byte game[2][10][10];//main board +bool computer[2] = {0}; +byte score[2] = {0};//set by header() +bitbox sunk[2]={0}; +byte just_sunk[2]={0};//to be displayed for human players + +byte firstinrowy , firstinrowx ; +byte lastinrowy ,lastinrowx; +byte goindirection; +byte shotinvain; +void sigint_handler(int x){ + endwin(); + puts("Quit."); + exit(x); +} +void mouseinput(bool ingame){ + MEVENT minput; + #ifdef PDCURSES + nc_getmouse(&minput); + #else + getmouse(&minput); + #endif + if(minput.bstate & (BUTTON1_CLICKED|BUTTON1_RELEASED)){ + if( minput.y-4 < 10){ + if( (ingame && minput.x-23<20 && minput.x-23>=0 ) || (!ingame && minput.x-1<20) ){//it most be on the trackboard if ingame is true + py=minput.y-4; + px=(minput.x-1-(ingame*2)) /2; + } + } + else + return; + } + if(minput.bstate & (BUTTON1_CLICKED|BUTTON1_RELEASED)) + ungetch('\n'); + if(minput.bstate & (BUTTON2_CLICKED|BUTTON2_RELEASED|BUTTON3_CLICKED|BUTTON3_RELEASED) ) + ungetch('r'); +} +void rectangle(byte sy,byte sx){ + for(byte y=0;y<=10+1;y++){ + mvaddch(sy+y,sx,ACS_VLINE); + mvaddch(sy+y,sx+10*2,ACS_VLINE); + } + for(byte x=0;x<=10*2;x++){ + mvaddch(sy,sx+x,ACS_HLINE); + mvaddch(sy+10+1,sx+x,ACS_HLINE); + } + mvaddch(sy,sx,ACS_ULCORNER); + mvaddch(sy+10+1,sx,ACS_LLCORNER); + mvaddch(sy,sx+10*2,ACS_URCORNER); + mvaddch(sy+10+1,sx+10*2,ACS_LRCORNER); +} +void print_type(byte type){ + switch(type){ + case(2): + addstr("patrol boat"); + break; + case(3): + addstr("destroyer"); + break; + case(4): + addstr("battleship"); + break; + case(5): + addstr("carrier"); + break; + case(6): + addstr("submarine"); + break; + } +} +void MID(byte *y , byte *x, byte direction){ + switch(direction){ + case(0): + *x=*x-1; + break; + case(1): + *y=*y-1; + break; + case(2): + *x=*x+1; + break; + case(3): + *y=*y+1; + break; + } +} +void genocide(bool side , byte type){ + byte y,x; + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + if(game[side][y][x] == type) + game[side][y][x] = SEA; + } + } +} +void header(bool side){ + score[0]=score[1]=0; + byte y,x; + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + if(game[!side][y][x] == HIT) + score[side]++; + if(game[side][y][x] == HIT) + score[!side]++; + } + } + mvaddch(0,1, '_'); + mvprintw(1,0,"|_) %2d:%2d",score[side],score[!side]); + mvprintw(2,0,"|_)ATTLESHIP "); +} + +void draw(bool side,byte sy,byte sx){//the game's board + rectangle(sy,sx); + chtype ch ; + byte y,x; + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + ch =A_NORMAL; + if(y==py && x==px) + ch |= A_STANDOUT; + if(game[side][y][x] == HIT) + ch |= 'X'|colors[RED]; + else if(game[side][y][x] > 0 ) + ch |= ACS_BLOCK|colors[side]; + else if(game[side][y][x]== MISS) + ch |= 'O'|colors[CYAN]; + else + ch |= '~'|colors[CYAN]; + + mvaddch(sy+1+y,sx+x*2+1,ch); + } + } +} +void draw_trackboard(bool side,byte sy,byte sx){ + rectangle(sy,sx); + chtype ch ; + byte y,x; + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + ch =A_NORMAL; + if(y==py && x==px-10) + ch |= A_STANDOUT; + + if(game[!side][y][x] == HIT) + ch |= '*'|colors[RED]; + else if(game[!side][y][x]== MISS) + ch |= '~'|colors[CYAN]; + else + ch |= '.'; + + mvaddch(sy+1+y,sx+x*2+1,ch); + } + } + refresh(); +} + +void autoset(bool side){ + byte y=0,x=0,direction=0, invain=0; + byte realy,realx; + byte l; + for(byte type=2;type<7;type++){ + SetLocation: + realy=rand()%10; + realx=rand()%10; + invain=0; + SetDirection: + y=realy; + x=realx; + direction=rand()%4; + for(l=0;(type != 6 && l=10 || x>=10 || game[side][y][x] != SEA ){ + genocide(side,type); + invain++; + direction= (direction+1)%4; + if(invain<4) + goto SetDirection; + else + goto SetLocation;//endless loop + } + else{ + game[side][y][x]=type; + MID(&y,&x,direction); + } + } + } +} + +void set_the_board(bool side){ + if( computer[side] ){ + autoset(side); + return; + } + erase(); + mvaddch(0,1, '_'); + mvaddstr(1,0,"|_) Set your board"); + mvaddstr(2,0,"|_)ATTLESHIP"); + mvaddstr(16,0,"Press RETURN to specify the location and press R to rotate the ship."); + int input; + byte y=0,x=0,direction=0, invain=0; + byte realy,realx; + byte l; + py=px=0; + for(byte type=2;type<7;type++){ + mvaddstr(15,0,"Put your "); + print_type(type); + addstr(" in its position: "); + SetLocation: + while(1){ + draw(side,3,0); + refresh(); + input = getch(); + if( input == KEY_MOUSE ) + mouseinput(0); + if( (input=='k' || input==KEY_UP) && py>0) + py--; + if( (input=='j' || input==KEY_DOWN) && py<9) + py++; + if( (input=='h' || input==KEY_LEFT) && px>0) + px--; + if( (input=='l' || input==KEY_RIGHT) && px<9) + px++; + if( input=='\n' ) + break; + if( input=='q' ) + sigint_handler(EXIT_SUCCESS); + } + + + realy=y=py; + realx=x=px; + invain=0; + SetDirection: + y=realy; + x=realx; + for(l=0;(type != 6 && l=10 || x>=10 || game[side][y][x] != SEA ){ + genocide(side,type); + invain++; + direction= (direction+1)%4; + if(invain<4) + goto SetDirection; + else + goto SetLocation;//endless loop + } + else{ + game[side][y][x]=type; + MID(&y,&x,direction); + } + } + while(1){ + invain=0; + draw(side,3,0); + input=getch(); + if( input== 'r' || input == 'R' ){ + genocide(side,type); + direction= (direction+1)%4; + goto SetDirection; + } + else if(input == KEY_MOUSE) + mouseinput(0); + else + break; + } + } +} + +void turn_shift(void){ + if(!multiplayer) + return; + char key = 'a'+(rand()%ENGLISH_LETTERS); + int input1,input2,input3; + input1=input2=input3=0; + erase(); + beep(); + mvaddch(0,1, '_'); + mvaddstr(1,0,"|_) Anti-cheater"); + mvaddstr(2,0,"|_)ATTLESHIP"); + mvaddstr(4,0,"********************"); + mvprintw(5,0," Type '%c' 3 times ",key); + mvaddstr(6,0," before "); + mvaddstr(7,0," proceeding "); + mvaddstr(8,0," to the game "); + mvaddstr(10,0,"********************"); + refresh(); + while(1){ + input3=input2; + input2=input1; + input1=getch(); + if( (input1==input2) && (input2==input3) && (input3==key) ) + break; + } + erase(); +} +byte shoot(bool turn, byte y , byte x){ + byte s = game[!turn][y][x]; + if(s>0){ + game[!turn][y][x]=HIT; + return 1; + } + else if(s==HIT || s==MISS || y<0 || x<0 || y>9 || x>9 ){ //didn't shoot at all + return NOTHING; + } + else{ + game[!turn][y][x]=MISS; + return 0; + } + +} +void sink_announce(bool side){ + byte type,y,x; + for(type=2;type<7;type++){ + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + if( game[!side][y][x] == type ) + goto Next; + } + } + //there is no instance of 'type' in the opponet's board + if( ( (1 << type) | sunk[!side] ) != sunk[!side] ){ + sunk[!side] |= (1 << type); + if(computer[side]){ + lastinrowy=lastinrowx=firstinrowy=firstinrowx=-1; + shotinvain=0; + } + else{ + just_sunk[!side]=type;//leave to be displayed by you_sunk + } + return; + } + + + Next: + continue; + } +} +void you_sunk(bool side){ + if( just_sunk[!side] == 3) + mvaddstr(15,0,"You have destroyed my destroyer!!"); + else if( just_sunk[!side]){ + mvaddstr(15,0,"You have sunk my "); + print_type(just_sunk[!side]); + addstr("!!"); + } + just_sunk[!side]=0; +} +void cheat(bool side){ + /* its actually an anti-cheat, the player can place all their ships adjacent to the others and in the same direction, + and the algorithm will often play in a way that it will be left with one or two isolated tiles being unshot (with their respective ships being shot before). + in a such a situation a human will *very easily* find the tiles with logical thinking, but the computer shoots randomly and it will take such a long time for it + that it will often lose the winning game. + + this function still doesn't make a win,it's randomly executed.*/ + byte y,x; + for(y=0;y<10;y++){ + for(x=0;x<10;x++){ + if(game[!side][y][x]>0){ + shoot(side,y,x); + firstinrowy=y; + firstinrowx=x; + return; + } + } + } +} +void decide(bool side){// sink_announce is responsible for unsetting the global variables involved + byte y,x,r; + Again: + if( firstinrowy == NOTHING ){ + if( score[side] > 14 && score[side]9 || x>9) && r==NOTHING){ + goto Again; + } + } + r= shoot(side,y,x);//(y,x) may be MISS, but its impossible for it to be empty water, as executing this means it has tested every direction before + if(r==1){ + lastinrowy=y;//continue from the imaginary firstinrow + lastinrowx=x; + } + if(r==NOTHING) + goto Again; + } + + } + else{ + lastinrowy= y; + lastinrowx= x; + } + + if( r != NOTHING ) + return; + } + } + else{ + y=lastinrowy; + x=lastinrowx; + MID(&y,&x,goindirection); + r=shoot(side,y,x); + if( r == 1 ){ + lastinrowy=y; + lastinrowx=x; + } + else{ + lastinrowy=lastinrowx=NOTHING; + goindirection=(goindirection+2)%4; + } + if( r != NOTHING ) + return; + else{ + goto Again; + } + } +} +void help(bool side){//side is only there to feed header() + erase(); + header(side); + attron(A_BOLD); + mvprintw(3,0," **** THE CONTROLS ****"); + mvprintw(9,0,"YOU CAN ALSO USE THE MOUSE!"); + attroff(A_BOLD); + mvprintw(4,0,"RETURN/ENTER : Shoot"); + mvprintw(5,0,"R : Rotate"); + mvprintw(6,0,"hjkl/ARROW KEYS : Move cursor"); + mvprintw(7,0,"q : Quit"); + mvprintw(8,0,"F1 & F2 : Help on controls & gameplay"); + mvprintw(11,0,"Press a key to continue"); + getch(); + erase(); +} +void gameplay(bool side){//side is only there to feed header() + erase(); + header(side); + attron(A_BOLD); + mvprintw(3,0," **** THE GAMEPLAY ****"); + attroff(A_BOLD); + move(4,0); + printw("Guess the location of your opponet's\n"); + printw("ships and sink them! The player\n"); + printw("who sinks all the opponet's ships wins."); + getch(); + erase(); +} +int main(void){ + initscr(); + mousemask(ALL_MOUSE_EVENTS,NULL); + curs_set(0); + noecho(); + cbreak(); + keypad(stdscr,1); + if( has_colors() ){ + start_color(); + use_default_colors(); + init_pair(1,COLOR_GREEN,-1); + init_pair(2,COLOR_YELLOW,-1); + init_pair(3,COLOR_CYAN,-1); + init_pair(4,COLOR_RED,-1); + for(byte b=0;b<4;b++) + colors[b]=COLOR_PAIR(b+1); + } + int input; + printw("Choose type of the game:\n"); + printw("1 : Single Player*\n"); + printw("2 : Multi Player\n"); + input=getch(); + if(input == '2'){ + multiplayer=1; + computer[1]=computer[0]=0; + } + else{ + multiplayer=0; + computer[1]=1; + computer[0]=0; + } + Start: + firstinrowy=firstinrowx=lastinrowy=lastinrowx=goindirection=-1; + shotinvain=0; + sunk[0]=sunk[1]=0; + memset(game,SEA,200); + srand(time(NULL)%UINT_MAX); + erase(); + + set_the_board(0); + turn_shift(); + set_the_board(1); + bool won; + bool turn=1; + Turn: + px=10; + py=0; + sink_announce(turn); + if( sunk[0]==ALL ){ + won=1; + goto End; + } + else if( sunk[1]==ALL ){ + won=0; + goto End; + } + //the turn starts HERE + turn=!turn; + turn_shift(); + if( computer[turn] ){ + decide(turn); + goto Turn; + } + else{ + erase(); + you_sunk(turn); + while(1){ + header(turn); + draw(turn,3,0); + draw_trackboard(turn,3,22); + refresh(); + input=getch(); + if(input == KEY_F(1) || input=='?' ) + help(turn); + if(input == KEY_F(2) ) + gameplay(turn); + if(input == KEY_MOUSE) + mouseinput(1); + if( (input=='k' || input==KEY_UP) && py>0) + py--; + if( (input=='j' || input==KEY_DOWN) && py<9) + py++; + if( (input=='h' || input==KEY_LEFT) && px>10) + px--; + if( (input=='l' || input==KEY_RIGHT) && px<19) + px++; + if( input=='q') + sigint_handler(EXIT_SUCCESS); + if( input=='\n'){ + byte r=shoot(turn,py,px-10); + if(r != -1){ + goto Turn; + } + } + } + } + End: + erase(); + header(won); + draw(won,3,0); + draw_trackboard(won,3,22); + if( computer[won] ) + mvaddstr(15,0,"Hahaha! I won! "); + else + mvprintw(15,0,"Player %d won the game.",won+1); + addstr(" Wanna play again? (y/n)"); + refresh(); + curs_set(1); + input=getch(); + if( input!='n' && input !='N' && input!='q' ){ + curs_set(0); + goto Start; + } + endwin(); + return 0; +}