mirror of
https://github.com/abakh/nbsdgames.git
synced 2025-01-03 14:56:23 -05:00
test exe
This commit is contained in:
parent
45514a6cc8
commit
4a90dff198
622
battleship_test.exe
Normal file
622
battleship_test.exe
Normal file
@ -0,0 +1,622 @@
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#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 <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 -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<type) || (type==6 && l<3) ; l++){//there are two kinds of ship sized 3 tiles
|
||||
if( y<0 || x<0 || y>=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<type) || (type==6 && l<3) ; l++){//there are two kinds of ship sized 3 tiles
|
||||
if( y<0 || x<0 || y>=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]<score[!side] && rand()%2 ){
|
||||
cheat(side);
|
||||
return;
|
||||
}
|
||||
while(1){
|
||||
y = rand()%10;
|
||||
x = rand()%10;
|
||||
r = shoot(side,y,x);
|
||||
if(r == 1){
|
||||
firstinrowy=y;
|
||||
firstinrowx=x;
|
||||
}
|
||||
if(r != NOTHING)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if( lastinrowy ==NOTHING ){
|
||||
if(goindirection == NOTHING)
|
||||
goindirection = rand()%4;
|
||||
while(1){
|
||||
y= firstinrowy;//we know there is hit already
|
||||
x= firstinrowx;
|
||||
MID(&y,&x,goindirection);
|
||||
r= shoot(side,y,x);
|
||||
if( r != 1 ){
|
||||
goindirection = (goindirection+1)%4;//the ship is oriented in another way then
|
||||
shotinvain++;
|
||||
|
||||
if(shotinvain==4){ // this only occurs in case of a ship being shot before but not sunk ( e.g. in exprimenting for the direction)
|
||||
shotinvain=0;
|
||||
y=firstinrowy;
|
||||
x=firstinrowx;
|
||||
goindirection = (goindirection+1)%4;
|
||||
while(game[!side][y][x]==HIT){//go till you reach an unshot tile
|
||||
MID(&y,&x,goindirection);
|
||||
if( (y<0 || x<0 || y>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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user