From 10103488ed19c2a890b41f03f0039d49fe669c99 Mon Sep 17 00:00:00 2001 From: Paul Janzen Date: Thu, 12 Mar 1998 06:17:26 +0000 Subject: Bugfixes and strategical improvements --- games/bs/bs.c | 527 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 331 insertions(+), 196 deletions(-) (limited to 'games') diff --git a/games/bs/bs.c b/games/bs/bs.c index 2e555c5d2a7..fbe8f88f637 100644 --- a/games/bs/bs.c +++ b/games/bs/bs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bs.c,v 1.5 1997/07/23 20:04:49 kstailey Exp $ */ +/* $OpenBSD: bs.c,v 1.6 1998/03/12 06:17:25 pjanzen Exp $ */ /* * bs.c - original author: Bruce Holloway * salvo option by: Chuck A DeGaul @@ -6,13 +6,17 @@ * by Eric S. Raymond * v1.2 with color support and minor portability fixes, November 1990 * v2.0 featuring strict ANSI/POSIX conformance, November 1993. + * v2.1 with ncurses mouse support, September 1995 + * v2.2 with bugfixes and strategical improvements, March 1998. */ +/* #define _POSIX_SOURCE */ -#include -#include #include #include +#include #include +#include +#include #include #include @@ -25,18 +29,7 @@ #define strchr index #endif /* !A_UNDERLINE */ -#ifdef isxdigit /* aha, must be an AT&T system... */ -#define srand(n) srand48(n) -#define rand() lrand48() -#define bzero(s, n) (void)memset((char *)(s), '\0', n) -/* - * Try this if ungetch() fails to resolve. - * - * #define ungetch ungetc - */ -#endif /* isxdigit */ - -static bool checkplace(); +static int getcoord(int atcpu); /* * Constants for tuning the random-fire algorithm. It prefers moves that @@ -76,6 +69,8 @@ static bool checkplace(); #define CXBASE 48 #define CY(y) (CYBASE + (y)) #define CX(x) (CXBASE + (x)*3) +#define CYINV(y) ((y) - CYBASE) +#define CXINV(x) (((x) - CXBASE) / 3) #define cgoto(y, x) (void)move(CY(y), CX(x)) #define ONBOARD(x, y) (x >= 0 && x < BWIDTH && y >= 0 && y < BDEPTH) @@ -125,11 +120,13 @@ typedef struct char symbol; /* symbol for game purposes */ char length; /* length of ship */ char x, y; /* coordinates of ship start point */ - char dir; /* direction of `bow' */ + unsigned char dir; /* direction of `bow' */ bool placed; /* has it been placed on the board? */ } ship_t; +static bool checkplace(int b, ship_t *ss, int vis); + ship_t plyship[SHIPTYPES] = { { carrier, 0, 'A', 5}, @@ -148,6 +145,26 @@ ship_t cpuship[SHIPTYPES] = { ptboat, 0, 'P', 2}, }; +/* The following variables (and associated defines), used for computer + * targetting, must be global so that they can be reset for each new game + * played without restarting the program. + */ +#define POSSIBLE(x, y) (ONBOARD(x, y) && !hits[COMPUTER][x][y]) +#define RANDOM_FIRE 0 +#define RANDOM_HIT 1 +#define HUNT_DIRECT 2 +#define FIRST_PASS 3 +#define REVERSE_JUMP 4 +#define SECOND_PASS 5 + static int next = RANDOM_FIRE; + static int turncount = 0; + static int srchstep = BEGINSTEP; +/* Computer needs to keep track of longest and shortest player ships still + * not sunk, for better targetting. + */ +static int cpushortest; +static int cpulongest; + /* "Hits" board, and main board. */ static char hits[2][BWIDTH][BDEPTH], board[2][BWIDTH][BDEPTH]; @@ -156,21 +173,18 @@ static int plywon=0, cpuwon=0; /* How many games has each won? */ static int salvo, blitz, closepack; -#define PR (void)addstr - -static void uninitgame(sig) +static void uninitgame(int sig) /* end the game, either normally or due to signal */ -int sig; { clear(); (void)refresh(); (void)resetterm(); (void)echo(); (void)endwin(); - exit(0); + exit(sig); } -static void announceopts() +static void announceopts(void) /* announce which game options are enabled */ { if (salvo || blitz || closepack) @@ -194,20 +208,18 @@ static void announceopts() "Playing standard game (noblitz, nosalvo, noclosepack)"); } -static void intro() +static void intro(void) { - extern char *getlogin(); char *tmpname; - srand(time(0L)+getpid()); /* Kick the random number generator */ + srandom((unsigned)(time(0L)+getpid())); /* Kick the random number generator */ (void) signal(SIGINT,uninitgame); (void) signal(SIGINT,uninitgame); - (void) signal(SIGIOT,uninitgame); /* for assert(3) */ if(signal(SIGQUIT,SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT,uninitgame); - if(tmpname = getlogin()) + if ((tmpname = getlogin()) != 0) { (void)strcpy(name,tmpname); name[0] = toupper(name[0]); @@ -225,6 +237,7 @@ static void intro() (void)noecho(); #ifdef PENGUIN +#define PR (void)addstr (void)clear(); (void)mvaddstr(4,29,"Welcome to Battleship!"); (void)move(8,0); @@ -256,13 +269,14 @@ static void intro() init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); #endif /* A_COLOR */ +#ifdef NCURSES_MOUSE_VERSION + (void) mousemask(BUTTON1_CLICKED, (mmask_t *)NULL); +#endif /* NCURSES_MOUSE_VERSION*/ } /* VARARGS1 */ -static void prompt(n, f, s) +static void prompt(int n, char *f, char *s) /* print a message at the prompt line */ -int n; -char *f, *s; { (void) move(PROMPTLINE + n, 0); (void) clrtoeol(); @@ -270,8 +284,7 @@ char *f, *s; (void) refresh(); } -static void error(s) -char *s; +static void error(char *s) { (void) move(PROMPTLINE + 2, 0); (void) clrtoeol(); @@ -282,10 +295,7 @@ char *s; } } -static void placeship(b, ss, vis) -int b; -ship_t *ss; -int vis; +static void placeship(int b, ship_t *ss, int vis) { int l; @@ -304,16 +314,13 @@ int vis; ss->hits = 0; } -static int rnd(n) -int n; +static int rnd(int n) { - return(((rand() & 0x7FFF) % n)); + return(((random() & 0x7FFF) % n)); } -static void randomplace(b, ss) +static void randomplace(int b, ship_t *ss) /* generate a valid random ship placement into px,py */ -int b; -ship_t *ss; { register int bwidth = BWIDTH - ss->length; register int bdepth = BDEPTH - ss->length; @@ -326,7 +333,7 @@ ship_t *ss; (!checkplace(b, ss, FALSE)); } -static void initgame() +static void initgame(void) { int i, j, unplaced; ship_t *ss; @@ -336,14 +343,26 @@ static void initgame() (void) move(PROMPTLINE + 2, 0); announceopts(); - bzero(board, sizeof(char) * BWIDTH * BDEPTH * 2); - bzero(hits, sizeof(char) * BWIDTH * BDEPTH * 2); + /* Set up global CPU algorithm variables. */ + next = RANDOM_FIRE; + turncount = 0; + srchstep = BEGINSTEP; + /* set up cpulongest and cpushortest (computer targetting variables) */ + cpushortest = cpulongest = cpuship->length; + + memset(board, 0, sizeof(char) * BWIDTH * BDEPTH * 2); + memset(hits, 0, sizeof(char) * BWIDTH * BDEPTH * 2); for (i = 0; i < SHIPTYPES; i++) { ss = cpuship + i; ss->x = ss->y = ss->dir = ss->hits = ss->placed = 0; ss = plyship + i; ss->x = ss->y = ss->dir = ss->hits = ss->placed = 0; + + if (ss->length > cpulongest) + cpulongest = ss->length; + if (ss->length < cpushortest) + cpushortest = ss->length; } /* draw empty boards */ @@ -351,7 +370,7 @@ static void initgame() (void) mvaddstr(PYBASE - 1, PXBASE - 3,numbers); for(i=0; i < BDEPTH; ++i) { - (void) mvaddch(PYBASE + i, PXBASE - 3, i + 'A'); + (void) mvaddch(PYBASE + i, PXBASE - 3, (chtype)(i + 'A')); #ifdef A_COLOR if (has_colors()) attron(COLOR_PAIR(COLOR_BLUE)); @@ -363,14 +382,14 @@ static void initgame() attrset(0); #endif /* A_COLOR */ (void) addch(' '); - (void) addch(i + 'A'); + (void) addch((chtype)(i + 'A')); } (void) mvaddstr(PYBASE + BDEPTH, PXBASE - 3,numbers); (void) mvaddstr(CYBASE - 2, CXBASE + 7,"Hit/Miss Board"); (void) mvaddstr(CYBASE - 1, CXBASE - 3, numbers); for(i=0; i < BDEPTH; ++i) { - (void) mvaddch(CYBASE + i, CXBASE - 3, i + 'A'); + (void) mvaddch(CYBASE + i, CXBASE - 3, (chtype)(i + 'A')); #ifdef A_COLOR if (has_colors()) attron(COLOR_PAIR(COLOR_BLUE)); @@ -382,7 +401,7 @@ static void initgame() attrset(0); #endif /* A_COLOR */ (void) addch(' '); - (void) addch(i + 'A'); + (void) addch((chtype)(i + 'A')); } (void) mvaddstr(CYBASE + BDEPTH,CXBASE - 3,numbers); @@ -416,8 +435,6 @@ static void initgame() ss = (ship_t *)NULL; do { - extern char *strchr(); - static char getcoord(); char c, docked[SHIPTYPES + 2], *cp = docked; /* figure which ships still wait to be placed */ @@ -467,7 +484,7 @@ static void initgame() } else if (c == 'R') { - prompt(1, "Placing the rest of your fleet at random..."); + prompt(1, "Placing the rest of your fleet at random...", ""); for (ss = plyship; ss < plyship + SHIPTYPES; ss++) if (!ss->placed) { @@ -518,12 +535,11 @@ static void initgame() (void) mvprintw(HYBASE+5, HXBASE, " "); - (void) prompt(0, "Press any key to start..."); + (void) prompt(0, "Press any key to start...", ""); (void) getch(); } -static int getcoord(atcpu) -int atcpu; +static int getcoord(int atcpu) { int ny, nx, c; @@ -557,19 +573,19 @@ int atcpu; #ifdef KEY_MIN case KEY_DOWN: #endif /* KEY_MIN */ - ny = cury+1; nx = curx; + ny = cury+1; nx = curx; break; case 'h': case '4': #ifdef KEY_MIN case KEY_LEFT: #endif /* KEY_MIN */ - ny = cury; nx = curx+BWIDTH-1; + ny = cury; nx = curx+BWIDTH-1; break; case 'l': case '6': #ifdef KEY_MIN case KEY_RIGHT: #endif /* KEY_MIN */ - ny = cury; nx = curx+1; + ny = cury; nx = curx+1; break; case 'y': case '7': #ifdef KEY_MIN @@ -581,7 +597,7 @@ int atcpu; #ifdef KEY_MIN case KEY_C1: #endif /* KEY_MIN */ - ny = cury+1; nx = curx+BWIDTH-1; + ny = cury+1; nx = curx+BWIDTH-1; break; case 'u': case '9': #ifdef KEY_MIN @@ -593,13 +609,32 @@ int atcpu; #ifdef KEY_MIN case KEY_C3: #endif /* KEY_MIN */ - ny = cury+1; nx = curx+1; + ny = cury+1; nx = curx+1; break; case FF: nx = curx; ny = cury; (void)clearok(stdscr, TRUE); (void)refresh(); break; +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: + { + MEVENT myevent; + + getmouse(&myevent); + if (atcpu + && myevent.y >= CY(0) && myevent.y <= CY(BDEPTH) + && myevent.x >= CX(0) && myevent.x <= CX(BDEPTH)) + { + curx = CXINV(myevent.x); + cury = CYINV(myevent.y); + return(' '); + } + else + beep(); + } + break; +#endif /* NCURSES_MOUSE_VERSION */ default: if (atcpu) (void) mvaddstr(CYBASE + BDEPTH + 1, CXBASE + 11, " "); @@ -613,15 +648,13 @@ int atcpu; } } -static int collidecheck(b, y, x) +static int collidecheck(int b, int y, int x) /* is this location on the selected zboard adjacent to a ship? */ -int b; -int y, x; { int collide; /* anything on the square */ - if (collide = IS_SHIP(board[b][x][y])) + if ((collide = IS_SHIP(board[b][x][y])) != 0) return(collide); /* anything on the neighbors */ @@ -642,16 +675,13 @@ int y, x; return(collide); } -static bool checkplace(b, ss, vis) -int b; -ship_t *ss; -int vis; +static bool checkplace(int b, ship_t *ss, int vis) { int l, xend, yend; /* first, check for board edges */ - xend = ss->x + ss->length * xincr[ss->dir]; - yend = ss->y + ss->length * yincr[ss->dir]; + xend = ss->x + (ss->length - 1) * xincr[ss->dir]; + yend = ss->y + (ss->length - 1) * yincr[ss->dir]; if (!ONBOARD(xend, yend)) { if (vis) @@ -693,7 +723,7 @@ int vis; return(TRUE); } -static int awinna() +static int awinna(void) { int i, j; ship_t *ss; @@ -710,9 +740,8 @@ static int awinna() return(-1); } -static ship_t *hitship(x, y) +static ship_t *hitship(int x, int y) /* register a hit on the targeted ship */ -int x, y; { ship_t *sb, *ss; char sym; @@ -739,16 +768,16 @@ int x, y; for (i = -1; i <= ss->length; ++i) { - int x, y; + int x1, y1; - x = bx + i * xincr[ss->dir]; - y = by + i * yincr[ss->dir]; - if (ONBOARD(x, y)) + x1 = bx + i * xincr[ss->dir]; + y1 = by + i * yincr[ss->dir]; + if (ONBOARD(x1, y1)) { - hits[turn][x][y] = MARK_MISS; - if (turn % 2 == PLAYER) + hits[turn][x1][y1] = MARK_MISS; + if (turn == PLAYER) { - cgoto(y, x); + cgoto(y1, x1); #ifdef A_COLOR if (has_colors()) attron(COLOR_PAIR(COLOR_GREEN)); @@ -764,14 +793,14 @@ int x, y; for (i = 0; i < ss->length; ++i) { - int x = ss->x + i * xincr[ss->dir]; - int y = ss->y + i * yincr[ss->dir]; + int x1 = ss->x + i * xincr[ss->dir]; + int y1 = ss->y + i * yincr[ss->dir]; - hits[turn][x][y] = ss->symbol; - if (turn % 2 == PLAYER) + hits[turn][x1][y1] = ss->symbol; + if (turn == PLAYER) { - cgoto(y, x); - (void) addch(ss->symbol); + cgoto(y1, x1); + (void) addch((chtype)(ss->symbol)); } } @@ -783,19 +812,19 @@ int x, y; return((ship_t *)NULL); } -static int plyturn() +static int plyturn(void) { ship_t *ss; bool hit; - char *m; + char *m = NULL; - prompt(1, "Where do you want to shoot? "); + prompt(1, "Where do you want to shoot? ", ""); for (;;) { (void) getcoord(COMPUTER); if (hits[PLAYER][curx][cury]) { - prompt(1, "You shelled this spot already! Try again."); + prompt(1, "You shelled this spot already! Try again.", ""); beep(); } else @@ -834,18 +863,16 @@ static int plyturn() m = " Glub, glub -- my %s is headed for the bottom!"; break; case 4: - m = " You'll pick up survivors from my my %s, I hope...!"; + m = " You'll pick up survivors from my %s, I hope...!"; break; } (void)printw(m, ss->name); (void)beep(); - return(awinna() == -1); } return(hit); } -static int sgetc(s) -char *s; +static int sgetc(char *s) { char *s1; int ch; @@ -857,72 +884,89 @@ char *s; if (islower(ch)) ch = toupper(ch); if (ch == CTRLC) - uninitgame(); + uninitgame(0); for (s1=s; *s1 && ch != *s1; ++s1) continue; if (*s1) { (void) addch((chtype)ch); - (void)refresh(); + (void) refresh(); return(ch); } } } +static bool cpushipcanfit(int x, int y, int length, int direction) +/* Checks to see if there's room for a ship of a given length in a given + * direction. If direction is negative, check in all directions. Note + * that North and South are equivalent, as are East and West. + */ +{ + int len = 1; + int x1, y1; + + if (direction >= 0) + { + direction %= 4; + while (direction < 8) + { + x1 = x + xincr[direction]; + y1 = y + yincr[direction]; + while (POSSIBLE(x1,y1)) + { + len++; + x1 += xincr[direction]; + y1 += yincr[direction]; + } + direction += 4; + } + return (len >= length); + } + else + { + return ((cpushipcanfit(x,y,length,E)) || + (cpushipcanfit(x,y,length,S))); + } +} + -static void randomfire(px, py) +static void randomfire(int *px, int *py) /* random-fire routine -- implements simple diagonal-striping strategy */ -int *px, *py; { - static int turncount = 0; - static int srchstep = BEGINSTEP; static int huntoffs; /* Offset on search strategy */ int ypossible[BWIDTH * BDEPTH], xpossible[BWIDTH * BDEPTH], nposs; - int ypreferred[BWIDTH * BDEPTH], xpreferred[BWIDTH * BDEPTH], npref; int x, y, i; if (turncount++ == 0) huntoffs = rnd(srchstep); - /* first, list all possible moves */ - nposs = npref = 0; + /* first, list all possible moves on the diagonal stripe */ + nposs = 0; for (x = 0; x < BWIDTH; x++) for (y = 0; y < BDEPTH; y++) - if (!hits[COMPUTER][x][y]) + if ((!hits[COMPUTER][x][y]) && + (((x+huntoffs) % srchstep) == (y % srchstep)) && + (cpushipcanfit(x,y,cpulongest,-1))) { - xpossible[nposs] = x; - ypossible[nposs] = y; - nposs++; - if (((x+huntoffs) % srchstep) != (y % srchstep)) - { - xpreferred[npref] = x; - ypreferred[npref] = y; - npref++; + xpossible[nposs] = x; + ypossible[nposs] = y; + nposs++; } - } - - if (npref) - { - i = rnd(npref); - - *px = xpreferred[i]; - *py = ypreferred[i]; - } - else if (nposs) + if (nposs) { i = rnd(nposs); *px = xpossible[i]; *py = ypossible[i]; - - if (srchstep > 1) - --srchstep; } - else + else if (srchstep > cpulongest) { - error("No moves possible?? Help!"); - exit(1); - /*NOTREACHED*/ + --srchstep; + } + else + { + error("No moves possible?? Help!"); + exit(1); } } @@ -930,17 +974,16 @@ int *px, *py; #define S_HIT 1 #define S_SUNK -1 -static bool cpufire(x, y) +static bool cpufire(int x, int y) /* fire away at given location */ -int x, y; { bool hit, sunk; - ship_t *ss; + ship_t *ss = NULL; hits[COMPUTER][x][y] = (hit = (board[PLAYER][x][y])) ? MARK_HIT : MARK_MISS; (void) mvprintw(PROMPTLINE, 0, "I shoot at %c%d. I %s!", y + 'A', x, hit ? "hit" : "miss"); - if (sunk = (hit && (ss = hitship(x, y)))) + if ((sunk = (hit && (ss = hitship(x, y))))) (void) printw(" I've sunk your %s", ss->name); (void)clrtoeol(); @@ -952,7 +995,7 @@ int x, y; else attron(COLOR_PAIR(COLOR_GREEN)); #endif /* A_COLOR */ - (void)addch((chtype)(hit ? SHOWHIT : SHOWSPLASH)); + (void) addch((chtype)(hit ? SHOWHIT : SHOWSPLASH)); #ifdef A_COLOR attrset(0); #endif /* A_COLOR */ @@ -965,19 +1008,12 @@ int x, y; * unstructuredness below. The five labels are states which need to be held * between computer turns. */ -static bool cputurn() +static bool cputurn(void) { -#define POSSIBLE(x, y) (ONBOARD(x, y) && !hits[COMPUTER][x][y]) -#define RANDOM_FIRE 0 -#define RANDOM_HIT 1 -#define HUNT_DIRECT 2 -#define FIRST_PASS 3 -#define REVERSE_JUMP 4 -#define SECOND_PASS 5 - static int next = RANDOM_FIRE; static bool used[4]; static ship_t ts; int navail, x, y, d, n, hit = S_MISS; + bool closenoshot = FALSE; switch(next) { @@ -995,7 +1031,8 @@ static bool cputurn() break; case RANDOM_HIT: /* last shot was random and hit */ - used[E/2] = used[S/2] = used[W/2] = used[N/2] = FALSE; + used[E/2] = used[W/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,E))); + used[S/2] = used[N/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,S))); /* FALLTHROUGH */ case HUNT_DIRECT: /* last shot hit, we're looking for ship's long axis */ @@ -1011,18 +1048,14 @@ static bool cputurn() goto refire; /* ...so we must random-fire */ else { - for (d = 0, n = rnd(navail) + 1; n; n--) + for (d = 0, n = rnd(navail) + 1; n; n--,d++) while (used[d]) d++; + d--; - assert(d <= 4); - - used[d] = FALSE; x = ts.x + xincr[d*2]; y = ts.y + yincr[d*2]; - assert(POSSIBLE(x, y)); - if (!(hit = cpufire(x, y))) next = HUNT_DIRECT; else @@ -1036,40 +1069,131 @@ static bool cputurn() case FIRST_PASS: /* we have a start and a direction now */ x = ts.x + xincr[ts.dir]; y = ts.y + yincr[ts.dir]; - if (POSSIBLE(x, y) && (hit = cpufire(x, y))) + if (POSSIBLE(x, y)) { - ts.x = x; ts.y = y; ts.hits++; - next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS; + if ((hit = cpufire(x, y))) + { + ts.x = x; ts.y = y; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS; + } + else + next = REVERSE_JUMP; + break; } else next = REVERSE_JUMP; - break; + /* FALL THROUGH */ case REVERSE_JUMP: /* nail down the ship's other end */ - d = ts.dir + 4; - x = ts.x + ts.hits * xincr[d]; - y = ts.y + ts.hits * yincr[d]; - if (POSSIBLE(x, y) && (hit = cpufire(x, y))) - { - ts.x = x; ts.y = y; ts.dir = d; ts.hits++; - next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS; - } - else - next = RANDOM_FIRE; - break; + ts.dir = (ts.dir + 4) % 8; + ts.x += (ts.hits-1) * xincr[ts.dir]; + ts.y += (ts.hits-1) * yincr[ts.dir]; + /* FALL THROUGH */ case SECOND_PASS: /* kill squares not caught on first pass */ x = ts.x + xincr[ts.dir]; y = ts.y + yincr[ts.dir]; - if (POSSIBLE(x, y) && (hit = cpufire(x, y))) + if (POSSIBLE(x, y)) { - ts.x = x; ts.y = y; ts.hits++; - next = (hit == S_SUNK) ? RANDOM_FIRE: SECOND_PASS; - break; + if ((hit = cpufire(x, y))) + { + ts.x = x; ts.y = y; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE: SECOND_PASS; + } + else + { + /* The only way to get here is if closepack is on; otherwise, + * we _have_ sunk the ship. I set hit to S_SUNK just to get + * the additional closepack logic at the end of the switch. + */ +/*assert closepack*/ +if (!closepack) error("Assertion failed: not closepack 1"); + hit = S_SUNK; + next = RANDOM_FIRE; + } } else + { +/*assert closepack*/ +if (!closepack) error("Assertion failed: not closepack 2"); + hit = S_SUNK; + closenoshot = TRUE; /* Didn't shoot yet! */ next = RANDOM_FIRE; + } break; + } /* switch(next) */ + + if (hit == S_SUNK) + { + /* Update cpulongest and cpushortest. We could increase srchstep + * if it's smaller than cpushortest but that makes strategic sense + * only if we've been doing continuous diagonal stripes, and that's + * less interesting to watch. + */ + ship_t *sp = plyship; + + cpushortest = cpulongest; + cpulongest = 0; + for (d=0 ; d < SHIPTYPES; d++, sp++) + { + if (sp->hits < sp->length) + { + cpushortest = (cpushortest < sp->length) ? cpushortest : sp->length; + cpulongest = (cpulongest > sp->length) ? cpulongest : sp->length; + } + } + /* Now, if we're in closepack mode, we may have knocked off part of + * another ship, in which case we shouldn't do RANDOM_FIRE. A + * more robust implementation would probably do this check regardless + * of whether closepack was set or not. + * Note that MARK_HIT is set only for ships that aren't sunk; + * hitship() changes the marker to the ship's character when the + * ship is sunk. + */ + if (closepack) + { + ts.hits = 0; + for (x = 0; x < BWIDTH; x++) + for (y = 0; y < BDEPTH; y++) + { + if (hits[COMPUTER][x][y] == MARK_HIT) + { + /* So we found part of another ship. It may have more + * than one hit on it. Check to see if it does. If no + * hit does, take the last MARK_HIT and be RANDOM_HIT. + */ + ts.x = x; ts.y = y; ts.hits = 1; + for (d = 0; d < 8; d += 2) + { + while ((ONBOARD(ts.x, ts.y)) && + (hits[COMPUTER][(int)ts.x][(int)ts.y] == MARK_HIT)) + { + ts.x += xincr[d]; ts.y += yincr[d]; ts.hits++; + } + if ((--ts.hits > 1) && (ONBOARD(ts.x, ts.y)) && + (hits[COMPUTER][(int)ts.x][(int)ts.y] == 0)) + { + ts.dir = d; + ts.x -= xincr[d]; ts.y -= yincr[d]; + d = 100; /* use as a flag */ + x = BWIDTH; y = BDEPTH; /* end the loop */ + } else { + ts.x = x; ts.y = y; ts.hits = 1; + } + + } + } + if (ts.hits) + { + next = (d >= 100) ? FIRST_PASS : RANDOM_HIT; + } else + next = RANDOM_FIRE; + } + } + if (closenoshot) + { + return(cputurn()); + } } /* check for continuation and/or winner */ @@ -1078,8 +1202,6 @@ static bool cputurn() (void)refresh(); (void)sleep(1); } - if (awinna() != -1) - return(FALSE); #ifdef DEBUG (void) mvprintw(PROMPTLINE + 2, 0, @@ -1089,7 +1211,8 @@ static bool cputurn() return(hit); } -playagain() +static +int playagain(void) { int j; ship_t *ss; @@ -1098,7 +1221,7 @@ playagain() for(j = 0; j < ss->length; j++) { cgoto(ss->y + j * yincr[ss->dir], ss->x + j * xincr[ss->dir]); - (void)addch((chtype)ss->symbol); + (void) addch((chtype)ss->symbol); } if(awinna()) @@ -1106,6 +1229,9 @@ playagain() else ++plywon; j = 18 + strlen(name); + /* If you play a hundred games or more at a go, you deserve a badly + * centred score output. + */ if(plywon >= 10) ++j; if(cpuwon >= 10) @@ -1118,9 +1244,17 @@ playagain() return(sgetc("YN") == 'Y'); } -static void do_options(c,op) -int c; -char *op[]; +void usage() +{ + (void) fprintf(stderr, "Usage: bs [-s | -b] [-c]\n"); + (void) fprintf(stderr, "\tWhere the options are:\n"); + (void) fprintf(stderr, "\t-s : play a salvo game\n"); + (void) fprintf(stderr, "\t-b : play a blitz game\n"); + (void) fprintf(stderr, "\t-c : ships may be adjacent\n"); + exit(1); +} + +static void do_options(int c, char *op[]) { register int i; @@ -1132,12 +1266,7 @@ char *op[]; { default: case '?': - (void) fprintf(stderr, "Usage: battle [-s | -b] [-c]\n"); - (void) fprintf(stderr, "\tWhere the options are:\n"); - (void) fprintf(stderr, "\t-s : play a salvo game\n"); - (void) fprintf(stderr, "\t-b : play a blitz game\n"); - (void) fprintf(stderr, "\t-c : ships may be adjacent\n"); - exit(1); + (void) usage(); break; case '-': switch(op[i][1]) @@ -1163,9 +1292,12 @@ char *op[]; case 'c': closepack = 1; break; + case 'h': + (void) usage(); + break; default: (void) fprintf(stderr, - "Bad arg: type \"%s ?\" for usage message\n", op[0]); + "Bad arg: type \"%s -h\" for usage message\n", op[0]); exit(1); } } @@ -1173,8 +1305,7 @@ char *op[]; } } -static int scount(who) -int who; +static int scount(int who) { register int i, shots; register ship_t *sp; @@ -1194,13 +1325,11 @@ int who; return(shots); } -main(argc, argv) -int argc; -char *argv[]; +int main(int argc, char *argv[]) { /* revoke privs */ - setegid(getgid()); - setgid(getgid()); + /*setegid(getgid()); + setgid(getgid());*/ do_options(argc, argv); @@ -1218,7 +1347,7 @@ char *argv[]; else (void) plyturn(); } - else + else /* salvo */ { register int i; @@ -1238,15 +1367,21 @@ char *argv[]; } } } - else + else /* blitz */ while(turn ? cputurn() : plyturn()) - continue; + { + if (turn) /* Pause between successive computer shots */ + { + (void)refresh(); + (void)sleep(1); + } + if (awinna() != -1) + break; + } turn = OTHER; } } while (playagain()); - uninitgame(); + uninitgame(0); /*NOTREACHED*/ } - -/* bs.c ends here */ -- cgit v1.2.3