summaryrefslogtreecommitdiff
path: root/games/bs/bs.c
diff options
context:
space:
mode:
Diffstat (limited to 'games/bs/bs.c')
-rw-r--r--games/bs/bs.c527
1 files changed, 331 insertions, 196 deletions
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 <esr@snark.thyrsus.com>
* 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 <assert.h>
-#include <ctype.h>
#include <curses.h>
#include <signal.h>
+#include <ctype.h>
#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <string.h>
#include <time.h>
@@ -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 */