1*bda84ce9Smestre /* $OpenBSD: bs.c,v 1.42 2021/10/23 11:22:48 mestre Exp $ */
23eb18cd7Spjanzen /*
33eb18cd7Spjanzen * Copyright (c) 1986, Bruce Holloway
43eb18cd7Spjanzen * All rights reserved.
53eb18cd7Spjanzen *
63eb18cd7Spjanzen * Redistribution and use in source and binary forms, with or without
73eb18cd7Spjanzen * modification, are permitted provided that the following conditions are
83eb18cd7Spjanzen * met:
93eb18cd7Spjanzen *
103eb18cd7Spjanzen * - Redistributions of source code must retain the above copyright
113eb18cd7Spjanzen * notice, this list of conditions and the following disclaimer.
123eb18cd7Spjanzen * - Redistributions in binary form must reproduce the above copyright
133eb18cd7Spjanzen * notice, this list of conditions and the following disclaimer in the
143eb18cd7Spjanzen * documentation and/or other materials provided with the distribution.
153eb18cd7Spjanzen * - Neither the name of the <ORGANIZATION> nor the names of its
163eb18cd7Spjanzen * contributors may be used to endorse or promote products derived from
173eb18cd7Spjanzen * this software without specific prior written permission.
183eb18cd7Spjanzen *
193eb18cd7Spjanzen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
203eb18cd7Spjanzen * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
213eb18cd7Spjanzen * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
223eb18cd7Spjanzen * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
233eb18cd7Spjanzen * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
243eb18cd7Spjanzen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
253eb18cd7Spjanzen * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
263eb18cd7Spjanzen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
273eb18cd7Spjanzen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
283eb18cd7Spjanzen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
293eb18cd7Spjanzen * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
303eb18cd7Spjanzen */
317f482600Sdownsj /*
327f482600Sdownsj * bs.c - original author: Bruce Holloway
337f482600Sdownsj * salvo option by: Chuck A DeGaul
347f482600Sdownsj * with improved user interface, autoconfiguration and code cleanup
357f482600Sdownsj * by Eric S. Raymond <esr@snark.thyrsus.com>
367f482600Sdownsj * v1.2 with color support and minor portability fixes, November 1990
377f482600Sdownsj * v2.0 featuring strict ANSI/POSIX conformance, November 1993.
38efc3f44dSpjanzen * v2.1 with ncurses mouse support, September 1995
39efc3f44dSpjanzen * v2.2 with bugfixes and strategical improvements, March 1998.
407f482600Sdownsj */
41ecbe4913Spjanzen
42a60bcfa4Spjanzen #include <ctype.h>
4344d3f3fbSmestre #include <curses.h>
44a60bcfa4Spjanzen #include <err.h>
4534278d36Sguenther #include <limits.h>
46a60bcfa4Spjanzen #include <signal.h>
47a60bcfa4Spjanzen #include <stdlib.h>
48f7d92492Sniklas #include <string.h>
49a60bcfa4Spjanzen #include <unistd.h>
507f482600Sdownsj
5115d5404dStb typedef struct {
5215d5404dStb char *name; /* name of the ship type */
5315d5404dStb char hits; /* how many times has this ship been hit? */
5415d5404dStb char symbol; /* symbol for game purposes */
5515d5404dStb char length; /* length of ship */
5615d5404dStb signed char x, y; /* coordinates of ship start point */
5715d5404dStb unsigned char dir; /* direction of `bow' */
5815d5404dStb bool placed; /* has it been placed on the board? */
5915d5404dStb } ship_t;
6015d5404dStb
6115d5404dStb static void announceopts(void);
6215d5404dStb static int awinna(void);
6315d5404dStb static bool checkplace(int, ship_t *, int);
6415d5404dStb static int collidecheck(int, int, int);
6515d5404dStb static int cpufire(int, int);
6615d5404dStb static bool cpushipcanfit(int, int, int, int);
6715d5404dStb static int cputurn(void);
6815d5404dStb static void do_options(int, char *[]);
6915d5404dStb static void error(char *);
7015d5404dStb static int getcoord(int);
7115d5404dStb static ship_t *hitship(int, int);
7215d5404dStb static void initgame(void);
7315d5404dStb static void intro(void);
7415d5404dStb static void placeship(int, ship_t *, int);
7515d5404dStb static int playagain(void);
7615d5404dStb static int plyturn(void);
7715d5404dStb static void prompt(int, const char *, ...)
7815d5404dStb __attribute__((__format__ (printf, 2, 3)));
7915d5404dStb static void randomfire(int *, int *);
8015d5404dStb static void randomplace(int, ship_t *);
8115d5404dStb static int rnd(int);
8215d5404dStb static int scount(int);
8315d5404dStb static int sgetc(char *);
847ad55f55Smestre __dead static void uninitgame(int);
8515d5404dStb __dead void usage(void);
867f482600Sdownsj
877f482600Sdownsj /*
887f482600Sdownsj * Constants for tuning the random-fire algorithm. It prefers moves that
897f482600Sdownsj * diagonal-stripe the board with a stripe separation of srchstep. If
907f482600Sdownsj * no such preferred moves are found, srchstep is decremented.
917f482600Sdownsj */
927f482600Sdownsj #define BEGINSTEP 3 /* initial value of srchstep */
937f482600Sdownsj
947f482600Sdownsj /* miscellaneous constants */
957f482600Sdownsj #define SHIPTYPES 5
967f482600Sdownsj #define OTHER (1-turn)
977f482600Sdownsj #define PLAYER 0
987f482600Sdownsj #define COMPUTER 1
997f482600Sdownsj #define MARK_HIT 'H'
1007f482600Sdownsj #define MARK_MISS 'o'
1017f482600Sdownsj #define CTRLC '\003' /* used as terminate command */
1027f482600Sdownsj #define FF '\014' /* used as redraw command */
1037f482600Sdownsj
1047f482600Sdownsj /* coordinate handling */
1057f482600Sdownsj #define BWIDTH 10
1067f482600Sdownsj #define BDEPTH 10
1077f482600Sdownsj
1087f482600Sdownsj /* display symbols */
1097f482600Sdownsj #define SHOWHIT '*'
1107f482600Sdownsj #define SHOWSPLASH ' '
1117f482600Sdownsj #define IS_SHIP(c) isupper(c)
1127f482600Sdownsj
1137f482600Sdownsj /* how to position us on player board */
1147f482600Sdownsj #define PYBASE 3
1157f482600Sdownsj #define PXBASE 3
1167f482600Sdownsj #define PY(y) (PYBASE + (y))
1177f482600Sdownsj #define PX(x) (PXBASE + (x)*3)
1187f482600Sdownsj #define pgoto(y, x) (void)move(PY(y), PX(x))
1197f482600Sdownsj
1207f482600Sdownsj /* how to position us on cpu board */
1217f482600Sdownsj #define CYBASE 3
1227f482600Sdownsj #define CXBASE 48
1237f482600Sdownsj #define CY(y) (CYBASE + (y))
1247f482600Sdownsj #define CX(x) (CXBASE + (x)*3)
125efc3f44dSpjanzen #define CYINV(y) ((y) - CYBASE)
126efc3f44dSpjanzen #define CXINV(x) (((x) - CXBASE) / 3)
1277f482600Sdownsj #define cgoto(y, x) (void)move(CY(y), CX(x))
1287f482600Sdownsj
1297f482600Sdownsj #define ONBOARD(x, y) (x >= 0 && x < BWIDTH && y >= 0 && y < BDEPTH)
1307f482600Sdownsj
1317f482600Sdownsj /* other board locations */
1327f482600Sdownsj #define COLWIDTH 80
1337f482600Sdownsj #define PROMPTLINE 21 /* prompt line */
1347f482600Sdownsj #define SYBASE CYBASE + BDEPTH + 3 /* move key diagram */
1357f482600Sdownsj #define SXBASE 63
1367f482600Sdownsj #define MYBASE SYBASE - 1 /* diagram caption */
1377f482600Sdownsj #define MXBASE 64
1387f482600Sdownsj #define HYBASE SYBASE - 1 /* help area */
1397f482600Sdownsj #define HXBASE 0
1407f482600Sdownsj
1417f482600Sdownsj /* this will need to be changed if BWIDTH changes */
1427f482600Sdownsj static char numbers[] = " 0 1 2 3 4 5 6 7 8 9";
1437f482600Sdownsj
1447f482600Sdownsj static char carrier[] = "Aircraft Carrier";
1457f482600Sdownsj static char battle[] = "Battleship";
1467f482600Sdownsj static char sub[] = "Submarine";
1477f482600Sdownsj static char destroy[] = "Destroyer";
1487f482600Sdownsj static char ptboat[] = "PT Boat";
1497f482600Sdownsj
15034278d36Sguenther static char name[LOGIN_NAME_MAX];
1517f482600Sdownsj static char dftname[] = "stranger";
1527f482600Sdownsj
1537f482600Sdownsj /* direction constants */
1547f482600Sdownsj #define E 0
1557f482600Sdownsj #define SE 1
1567f482600Sdownsj #define S 2
1577f482600Sdownsj #define SW 3
1587f482600Sdownsj #define W 4
1597f482600Sdownsj #define NW 5
1607f482600Sdownsj #define N 6
1617f482600Sdownsj #define NE 7
1627f482600Sdownsj static int xincr[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
1637f482600Sdownsj static int yincr[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
1647f482600Sdownsj
1657f482600Sdownsj /* current ship position and direction */
1667f482600Sdownsj static int curx = (BWIDTH / 2);
1677f482600Sdownsj static int cury = (BDEPTH / 2);
1687f482600Sdownsj
1697f482600Sdownsj ship_t plyship[SHIPTYPES] =
1707f482600Sdownsj {
171e29de8b1Spjanzen { carrier, 0, 'A', 5, 0, 0, 0, FALSE },
172e29de8b1Spjanzen { battle, 0, 'B', 4, 0, 0, 0, FALSE },
173e29de8b1Spjanzen { destroy, 0, 'D', 3, 0, 0, 0, FALSE },
174e29de8b1Spjanzen { sub, 0, 'S', 3, 0, 0, 0, FALSE },
175e29de8b1Spjanzen { ptboat, 0, 'P', 2, 0, 0, 0, FALSE }
1767f482600Sdownsj };
1777f482600Sdownsj
1787f482600Sdownsj ship_t cpuship[SHIPTYPES] =
1797f482600Sdownsj {
180e29de8b1Spjanzen { carrier, 0, 'A', 5, 0, 0, 0, FALSE },
181e29de8b1Spjanzen { battle, 0, 'B', 4, 0, 0, 0, FALSE },
182e29de8b1Spjanzen { destroy, 0, 'D', 3, 0, 0, 0, FALSE },
183e29de8b1Spjanzen { sub, 0, 'S', 3, 0, 0, 0, FALSE },
184e29de8b1Spjanzen { ptboat, 0, 'P', 2, 0, 0, 0, FALSE }
1857f482600Sdownsj };
1867f482600Sdownsj
187efc3f44dSpjanzen /* The following variables (and associated defines), used for computer
188efc3f44dSpjanzen * targetting, must be global so that they can be reset for each new game
189efc3f44dSpjanzen * played without restarting the program.
190efc3f44dSpjanzen */
191efc3f44dSpjanzen #define POSSIBLE(x, y) (ONBOARD(x, y) && !hits[COMPUTER][x][y])
192efc3f44dSpjanzen #define RANDOM_FIRE 0
193efc3f44dSpjanzen #define RANDOM_HIT 1
194efc3f44dSpjanzen #define HUNT_DIRECT 2
195efc3f44dSpjanzen #define FIRST_PASS 3
196efc3f44dSpjanzen #define REVERSE_JUMP 4
197efc3f44dSpjanzen #define SECOND_PASS 5
198efc3f44dSpjanzen static int next = RANDOM_FIRE;
199efc3f44dSpjanzen static int turncount = 0;
200efc3f44dSpjanzen static int srchstep = BEGINSTEP;
201efc3f44dSpjanzen /* Computer needs to keep track of longest and shortest player ships still
202efc3f44dSpjanzen * not sunk, for better targetting.
203efc3f44dSpjanzen */
204efc3f44dSpjanzen static int cpushortest;
205efc3f44dSpjanzen static int cpulongest;
206efc3f44dSpjanzen
2077f482600Sdownsj /* "Hits" board, and main board. */
2087f482600Sdownsj static char hits[2][BWIDTH][BDEPTH], board[2][BWIDTH][BDEPTH];
2097f482600Sdownsj
2107f482600Sdownsj static int turn; /* 0=player, 1=computer */
2117f482600Sdownsj static int plywon=0, cpuwon=0; /* How many games has each won? */
2127f482600Sdownsj
2137f482600Sdownsj static int salvo, blitz, closepack;
2147f482600Sdownsj
2157f482600Sdownsj /* end the game, either normally or due to signal */
216cd84dbdaSmestre static void
uninitgame(int sig)217cd84dbdaSmestre uninitgame(int sig)
2187f482600Sdownsj {
2197f482600Sdownsj clear();
2207f482600Sdownsj (void)refresh();
2217f482600Sdownsj (void)resetterm();
2227f482600Sdownsj (void)echo();
2237f482600Sdownsj (void)endwin();
224efc3f44dSpjanzen exit(sig);
2257f482600Sdownsj }
2267f482600Sdownsj
2277f482600Sdownsj /* announce which game options are enabled */
228cd84dbdaSmestre static void
announceopts(void)229cd84dbdaSmestre announceopts(void)
2307f482600Sdownsj {
2317f482600Sdownsj if (salvo || blitz || closepack)
2327f482600Sdownsj {
2337f482600Sdownsj (void) printw("Playing optional game (");
2347f482600Sdownsj if (salvo)
2357f482600Sdownsj (void) printw("salvo, ");
2367f482600Sdownsj else
2377f482600Sdownsj (void) printw("nosalvo, ");
2387f482600Sdownsj if (blitz)
2397f482600Sdownsj (void) printw("blitz ");
2407f482600Sdownsj else
2417f482600Sdownsj (void) printw("noblitz, ");
2427f482600Sdownsj if (closepack)
2437f482600Sdownsj (void) printw("closepack)");
2447f482600Sdownsj else
2457f482600Sdownsj (void) printw("noclosepack)");
2467f482600Sdownsj }
2477f482600Sdownsj else
2487f482600Sdownsj (void) printw(
2497f482600Sdownsj "Playing standard game (noblitz, nosalvo, noclosepack)");
2507f482600Sdownsj }
2517f482600Sdownsj
252cd84dbdaSmestre static void
intro(void)253cd84dbdaSmestre intro(void)
2547f482600Sdownsj {
2557f482600Sdownsj char *tmpname;
2567f482600Sdownsj
2577f482600Sdownsj (void) signal(SIGINT,uninitgame);
2587f482600Sdownsj if(signal(SIGQUIT,SIG_IGN) != SIG_IGN)
2597f482600Sdownsj (void)signal(SIGQUIT,uninitgame);
2607f482600Sdownsj
261e29de8b1Spjanzen if ((tmpname = getlogin()) != NULL)
2627f482600Sdownsj {
263e29de8b1Spjanzen (void)strlcpy(name, tmpname, sizeof(name));
264866f718fSmmcc name[0] = toupper((unsigned char)name[0]);
2657f482600Sdownsj }
2667f482600Sdownsj else
267e29de8b1Spjanzen (void)strlcpy(name, dftname, sizeof(name));
2687f482600Sdownsj
2697f482600Sdownsj (void)initscr();
2707f482600Sdownsj keypad(stdscr, TRUE);
2717f482600Sdownsj (void)saveterm();
2727f482600Sdownsj (void)nonl();
2737f482600Sdownsj (void)cbreak();
2747f482600Sdownsj (void)noecho();
2757f482600Sdownsj
276a60bcfa4Spjanzen if ((LINES < PROMPTLINE + 3) || (COLS < COLWIDTH)) {
277a60bcfa4Spjanzen endwin();
278a60bcfa4Spjanzen errx(1, "screen must be at least %dx%d.", PROMPTLINE + 3, COLWIDTH);
279a60bcfa4Spjanzen }
280a60bcfa4Spjanzen
281efc3f44dSpjanzen #define PR (void)addstr
2827f482600Sdownsj (void)clear();
2837f482600Sdownsj (void)mvaddstr(4,29,"Welcome to Battleship!");
2847f482600Sdownsj (void)move(8,0);
2857f482600Sdownsj PR(" \\\n");
2867f482600Sdownsj PR(" \\ \\ \\\n");
2877f482600Sdownsj PR(" \\ \\ \\ \\ \\_____________\n");
2887f482600Sdownsj PR(" \\ \\ \\_____________ \\ \\/ |\n");
28968413d08Stedu PR(" \\ \\/ \\__/ \\ \\/ |\n");
29068413d08Stedu PR(" \\/ \\/ \\/ \\_____/ |__\n");
29168413d08Stedu PR(" ________________/ /\\/ ..\\/ |\n");
29268413d08Stedu PR(" \\ S.S. Puffy \\/\\___o/ |\n");
29368413d08Stedu PR(" \\ / /\\ \\ /\n");
2947f482600Sdownsj PR(" \\___________________________________________________/\n");
2957f482600Sdownsj
2967f482600Sdownsj (void) mvaddstr(22,27,"Hit any key to continue..."); (void)refresh();
2977f482600Sdownsj (void) getch();
2987f482600Sdownsj
2997f482600Sdownsj start_color();
3007f482600Sdownsj
3017f482600Sdownsj init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
3027f482600Sdownsj init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
3037f482600Sdownsj init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
3047f482600Sdownsj init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
3057f482600Sdownsj init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
3067f482600Sdownsj init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
3077f482600Sdownsj init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
3087f482600Sdownsj init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
3097f482600Sdownsj
310efc3f44dSpjanzen (void) mousemask(BUTTON1_CLICKED, (mmask_t *)NULL);
3117f482600Sdownsj }
3127f482600Sdownsj
3137f482600Sdownsj /* print a message at the prompt line */
3143e07b96bSguenther static void
prompt(int n,const char * f,...)3153e07b96bSguenther prompt(int n, const char *f, ...)
3167f482600Sdownsj {
3173e07b96bSguenther va_list va;
3183e07b96bSguenther
3197f482600Sdownsj (void) move(PROMPTLINE + n, 0);
3207f482600Sdownsj (void) clrtoeol();
3213e07b96bSguenther va_start(va, f);
3223e07b96bSguenther (void) vw_printw(stdscr, f, va);
3233e07b96bSguenther va_end(va);
3247f482600Sdownsj (void) refresh();
3257f482600Sdownsj }
3267f482600Sdownsj
327cd84dbdaSmestre static void
error(char * s)328cd84dbdaSmestre error(char *s)
3297f482600Sdownsj {
3307f482600Sdownsj (void) move(PROMPTLINE + 2, 0);
3317f482600Sdownsj (void) clrtoeol();
3327f482600Sdownsj if (s)
3337f482600Sdownsj {
3347f482600Sdownsj (void) addstr(s);
3357f482600Sdownsj (void) beep();
3367f482600Sdownsj }
3377f482600Sdownsj }
3387f482600Sdownsj
339cd84dbdaSmestre static void
placeship(int b,ship_t * ss,int vis)340cd84dbdaSmestre placeship(int b, ship_t *ss, int vis)
3417f482600Sdownsj {
3427f482600Sdownsj int l;
3437f482600Sdownsj
3447f482600Sdownsj for(l = 0; l < ss->length; ++l)
3457f482600Sdownsj {
3467f482600Sdownsj int newx = ss->x + l * xincr[ss->dir];
3477f482600Sdownsj int newy = ss->y + l * yincr[ss->dir];
3487f482600Sdownsj
3497f482600Sdownsj board[b][newx][newy] = ss->symbol;
3507f482600Sdownsj if (vis)
3517f482600Sdownsj {
3527f482600Sdownsj pgoto(newy, newx);
3537f482600Sdownsj (void) addch((chtype)ss->symbol);
3547f482600Sdownsj }
3557f482600Sdownsj }
3567f482600Sdownsj ss->hits = 0;
3577f482600Sdownsj }
3587f482600Sdownsj
359cd84dbdaSmestre static int
rnd(int n)360cd84dbdaSmestre rnd(int n)
3617f482600Sdownsj {
36266e49541Snaddy return(arc4random_uniform(n));
3637f482600Sdownsj }
3647f482600Sdownsj
3657f482600Sdownsj /* generate a valid random ship placement into px,py */
366cd84dbdaSmestre static void
randomplace(int b,ship_t * ss)367cd84dbdaSmestre randomplace(int b, ship_t *ss)
3687f482600Sdownsj {
3697f482600Sdownsj do {
3707f482600Sdownsj ss->dir = rnd(2) ? E : S;
3715e29f442Spjanzen ss->x = rnd(BWIDTH - (ss->dir == E ? ss->length : 0));
3725e29f442Spjanzen ss->y = rnd(BDEPTH - (ss->dir == S ? ss->length : 0));
3737f482600Sdownsj } while
3747f482600Sdownsj (!checkplace(b, ss, FALSE));
3757f482600Sdownsj }
3767f482600Sdownsj
377cd84dbdaSmestre static void
initgame(void)378cd84dbdaSmestre initgame(void)
3797f482600Sdownsj {
3807f482600Sdownsj int i, j, unplaced;
3817f482600Sdownsj ship_t *ss;
3827f482600Sdownsj
3837f482600Sdownsj (void) clear();
3847f482600Sdownsj (void) mvaddstr(0,35,"BATTLESHIPS");
3857f482600Sdownsj (void) move(PROMPTLINE + 2, 0);
3867f482600Sdownsj announceopts();
3877f482600Sdownsj
388efc3f44dSpjanzen /* Set up global CPU algorithm variables. */
389efc3f44dSpjanzen next = RANDOM_FIRE;
390efc3f44dSpjanzen turncount = 0;
391efc3f44dSpjanzen srchstep = BEGINSTEP;
392efc3f44dSpjanzen /* set up cpulongest and cpushortest (computer targetting variables) */
393efc3f44dSpjanzen cpushortest = cpulongest = cpuship->length;
394efc3f44dSpjanzen
395efc3f44dSpjanzen memset(board, 0, sizeof(char) * BWIDTH * BDEPTH * 2);
396efc3f44dSpjanzen memset(hits, 0, sizeof(char) * BWIDTH * BDEPTH * 2);
3977f482600Sdownsj for (i = 0; i < SHIPTYPES; i++)
3987f482600Sdownsj {
3997f482600Sdownsj ss = cpuship + i;
40001ee717fSpjanzen ss->x = ss->y = ss->dir = ss->hits = 0;
40101ee717fSpjanzen ss->placed = FALSE;
4027f482600Sdownsj ss = plyship + i;
40301ee717fSpjanzen ss->x = ss->y = ss->dir = ss->hits = 0;
40401ee717fSpjanzen ss->placed = FALSE;
405efc3f44dSpjanzen
406efc3f44dSpjanzen if (ss->length > cpulongest)
407efc3f44dSpjanzen cpulongest = ss->length;
408efc3f44dSpjanzen if (ss->length < cpushortest)
409efc3f44dSpjanzen cpushortest = ss->length;
4107f482600Sdownsj }
4117f482600Sdownsj
4127f482600Sdownsj /* draw empty boards */
4137f482600Sdownsj (void) mvaddstr(PYBASE - 2, PXBASE + 5, "Main Board");
4147f482600Sdownsj (void) mvaddstr(PYBASE - 1, PXBASE - 3,numbers);
4157f482600Sdownsj for(i=0; i < BDEPTH; ++i)
4167f482600Sdownsj {
417efc3f44dSpjanzen (void) mvaddch(PYBASE + i, PXBASE - 3, (chtype)(i + 'A'));
4187f482600Sdownsj if (has_colors())
4197f482600Sdownsj attron(COLOR_PAIR(COLOR_BLUE));
4207f482600Sdownsj (void) addch(' ');
4217f482600Sdownsj for (j = 0; j < BWIDTH; j++)
4227f482600Sdownsj (void) addstr(" . ");
4237f482600Sdownsj attrset(0);
4247f482600Sdownsj (void) addch(' ');
425efc3f44dSpjanzen (void) addch((chtype)(i + 'A'));
4267f482600Sdownsj }
4277f482600Sdownsj (void) mvaddstr(PYBASE + BDEPTH, PXBASE - 3,numbers);
4287f482600Sdownsj (void) mvaddstr(CYBASE - 2, CXBASE + 7,"Hit/Miss Board");
4297f482600Sdownsj (void) mvaddstr(CYBASE - 1, CXBASE - 3, numbers);
4307f482600Sdownsj for(i=0; i < BDEPTH; ++i)
4317f482600Sdownsj {
432efc3f44dSpjanzen (void) mvaddch(CYBASE + i, CXBASE - 3, (chtype)(i + 'A'));
4337f482600Sdownsj if (has_colors())
4347f482600Sdownsj attron(COLOR_PAIR(COLOR_BLUE));
4357f482600Sdownsj (void) addch(' ');
4367f482600Sdownsj for (j = 0; j < BWIDTH; j++)
4377f482600Sdownsj (void) addstr(" . ");
4387f482600Sdownsj attrset(0);
4397f482600Sdownsj (void) addch(' ');
440efc3f44dSpjanzen (void) addch((chtype)(i + 'A'));
4417f482600Sdownsj }
4427f482600Sdownsj
4437f482600Sdownsj (void) mvaddstr(CYBASE + BDEPTH,CXBASE - 3,numbers);
4447f482600Sdownsj
4457f482600Sdownsj (void) mvprintw(HYBASE, HXBASE,
4467f482600Sdownsj "To position your ships: move the cursor to a spot, then");
4477f482600Sdownsj (void) mvprintw(HYBASE+1,HXBASE,
4487f482600Sdownsj "type the first letter of a ship type to select it, then");
4497f482600Sdownsj (void) mvprintw(HYBASE+2,HXBASE,
4507f482600Sdownsj "type a direction ([hjkl] or [4862]), indicating how the");
4517f482600Sdownsj (void) mvprintw(HYBASE+3,HXBASE,
4527f482600Sdownsj "ship should be pointed. You may also type a ship letter");
4537f482600Sdownsj (void) mvprintw(HYBASE+4,HXBASE,
4547f482600Sdownsj "followed by `r' to position it randomly, or type `R' to");
4557f482600Sdownsj (void) mvprintw(HYBASE+5,HXBASE,
4567f482600Sdownsj "place all remaining ships randomly.");
4577f482600Sdownsj
4587f482600Sdownsj (void) mvaddstr(MYBASE, MXBASE, "Aiming keys:");
4597f482600Sdownsj (void) mvaddstr(SYBASE, SXBASE, "y k u 7 8 9");
4607f482600Sdownsj (void) mvaddstr(SYBASE+1, SXBASE, " \\|/ \\|/ ");
4617f482600Sdownsj (void) mvaddstr(SYBASE+2, SXBASE, "h-+-l 4-+-6");
4627f482600Sdownsj (void) mvaddstr(SYBASE+3, SXBASE, " /|\\ /|\\ ");
4637f482600Sdownsj (void) mvaddstr(SYBASE+4, SXBASE, "b j n 1 2 3");
4647f482600Sdownsj
4657f482600Sdownsj /* have the computer place ships */
4667f482600Sdownsj for(ss = cpuship; ss < cpuship + SHIPTYPES; ss++)
4677f482600Sdownsj {
4687f482600Sdownsj randomplace(COMPUTER, ss);
4697f482600Sdownsj placeship(COMPUTER, ss, FALSE);
4707f482600Sdownsj }
4717f482600Sdownsj
4727f482600Sdownsj ss = (ship_t *)NULL;
4737f482600Sdownsj do {
4746e5a188aStedu char docked[SHIPTYPES + 2], *cp = docked;
4756e5a188aStedu int c;
4767f482600Sdownsj
4777f482600Sdownsj /* figure which ships still wait to be placed */
4787f482600Sdownsj *cp++ = 'R';
4797f482600Sdownsj for (i = 0; i < SHIPTYPES; i++)
4807f482600Sdownsj if (!plyship[i].placed)
4817f482600Sdownsj *cp++ = plyship[i].symbol;
4827f482600Sdownsj *cp = '\0';
4837f482600Sdownsj
4847f482600Sdownsj /* get a command letter */
4857f482600Sdownsj prompt(1, "Type one of [%s] to pick a ship.", docked+1);
4867f482600Sdownsj do {
4877f482600Sdownsj c = getcoord(PLAYER);
4887f482600Sdownsj } while
4897f482600Sdownsj (!strchr(docked, c));
4907f482600Sdownsj
4917f482600Sdownsj if (c == 'R')
4927f482600Sdownsj (void) ungetch('R');
4937f482600Sdownsj else
4947f482600Sdownsj {
4957f482600Sdownsj /* map that into the corresponding symbol */
4967f482600Sdownsj for (ss = plyship; ss < plyship + SHIPTYPES; ss++)
4977f482600Sdownsj if (ss->symbol == c)
4987f482600Sdownsj break;
4997f482600Sdownsj
5007f482600Sdownsj prompt(1, "Type one of [hjklrR] to place your %s.", ss->name);
5017f482600Sdownsj pgoto(cury, curx);
5027f482600Sdownsj }
5036e5a188aStedu regetchar:
5047f482600Sdownsj c = getch();
5056e5a188aStedu switch (c) {
5066e5a188aStedu case FF:
5077f482600Sdownsj (void)clearok(stdscr, TRUE);
5087f482600Sdownsj (void)refresh();
5096e5a188aStedu break;
5106e5a188aStedu case 'r':
5117f482600Sdownsj prompt(1, "Random-placing your %s", ss->name);
5127f482600Sdownsj randomplace(PLAYER, ss);
5137f482600Sdownsj placeship(PLAYER, ss, TRUE);
5147dd160a5Smestre error(NULL);
5157f482600Sdownsj ss->placed = TRUE;
5166e5a188aStedu break;
5176e5a188aStedu case 'R':
5183e07b96bSguenther prompt(1, "Placing the rest of your fleet at random...");
5197f482600Sdownsj for (ss = plyship; ss < plyship + SHIPTYPES; ss++)
5207f482600Sdownsj if (!ss->placed)
5217f482600Sdownsj {
5227f482600Sdownsj randomplace(PLAYER, ss);
5237f482600Sdownsj placeship(PLAYER, ss, TRUE);
5247f482600Sdownsj ss->placed = TRUE;
5257f482600Sdownsj }
5267dd160a5Smestre error(NULL);
5276e5a188aStedu break;
5286e5a188aStedu
5296e5a188aStedu case 'k': case 'j': case 'h': case 'l':
5306e5a188aStedu case '8': case '2': case '4': case '6':
5316e5a188aStedu case KEY_LEFT: case KEY_RIGHT: case KEY_UP: case KEY_DOWN:
5327f482600Sdownsj ss->x = curx;
5337f482600Sdownsj ss->y = cury;
5347f482600Sdownsj
5357f482600Sdownsj switch(c)
5367f482600Sdownsj {
5376e5a188aStedu case 'k': case '8': case KEY_UP: ss->dir = N; break;
5386e5a188aStedu case 'j': case '2': case KEY_DOWN: ss->dir = S; break;
5396e5a188aStedu case 'h': case '4': case KEY_LEFT: ss->dir = W; break;
5406e5a188aStedu case 'l': case '6': case KEY_RIGHT: ss->dir = E; break;
5417f482600Sdownsj }
5427f482600Sdownsj
5437f482600Sdownsj if (checkplace(PLAYER, ss, TRUE))
5447f482600Sdownsj {
5457f482600Sdownsj placeship(PLAYER, ss, TRUE);
5467dd160a5Smestre error(NULL);
5477f482600Sdownsj ss->placed = TRUE;
5487f482600Sdownsj }
5496e5a188aStedu break;
5506e5a188aStedu default:
5516e5a188aStedu goto regetchar;
5527f482600Sdownsj }
5537f482600Sdownsj
5547f482600Sdownsj for (unplaced = i = 0; i < SHIPTYPES; i++)
5557f482600Sdownsj unplaced += !plyship[i].placed;
5567f482600Sdownsj } while
5577f482600Sdownsj (unplaced);
5587f482600Sdownsj
5597f482600Sdownsj turn = rnd(2);
5607f482600Sdownsj
5617f482600Sdownsj (void) mvprintw(HYBASE, HXBASE,
5627f482600Sdownsj "To fire, move the cursor to your chosen aiming point ");
5637f482600Sdownsj (void) mvprintw(HYBASE+1, HXBASE,
5647f482600Sdownsj "and strike any key other than a motion key. ");
5657f482600Sdownsj (void) mvprintw(HYBASE+2, HXBASE,
5667f482600Sdownsj " ");
5677f482600Sdownsj (void) mvprintw(HYBASE+3, HXBASE,
5687f482600Sdownsj " ");
5697f482600Sdownsj (void) mvprintw(HYBASE+4, HXBASE,
5707f482600Sdownsj " ");
5717f482600Sdownsj (void) mvprintw(HYBASE+5, HXBASE,
5727f482600Sdownsj " ");
5737f482600Sdownsj
5743e07b96bSguenther (void) prompt(0, "Press any key to start...");
5757f482600Sdownsj (void) getch();
5767f482600Sdownsj }
5777f482600Sdownsj
578cd84dbdaSmestre static int
getcoord(int atcpu)579cd84dbdaSmestre getcoord(int atcpu)
5807f482600Sdownsj {
5817f482600Sdownsj int ny, nx, c;
5827f482600Sdownsj
5837f482600Sdownsj if (atcpu)
5847f482600Sdownsj cgoto(cury,curx);
5857f482600Sdownsj else
5867f482600Sdownsj pgoto(cury, curx);
5877f482600Sdownsj (void)refresh();
5887f482600Sdownsj for (;;)
5897f482600Sdownsj {
5907f482600Sdownsj if (atcpu)
5917f482600Sdownsj {
5927f482600Sdownsj (void) mvprintw(CYBASE + BDEPTH+1, CXBASE+11, "(%d, %c)", curx, 'A'+cury);
5937f482600Sdownsj cgoto(cury, curx);
5947f482600Sdownsj }
5957f482600Sdownsj else
5967f482600Sdownsj {
5977f482600Sdownsj (void) mvprintw(PYBASE + BDEPTH+1, PXBASE+11, "(%d, %c)", curx, 'A'+cury);
5987f482600Sdownsj pgoto(cury, curx);
5997f482600Sdownsj }
6007f482600Sdownsj
6017f482600Sdownsj switch(c = getch())
6027f482600Sdownsj {
6037f482600Sdownsj case 'k': case '8':
6047f482600Sdownsj case KEY_UP:
6057f482600Sdownsj ny = cury+BDEPTH-1; nx = curx;
6067f482600Sdownsj break;
6077f482600Sdownsj case 'j': case '2':
6087f482600Sdownsj case KEY_DOWN:
6097f482600Sdownsj ny = cury+1; nx = curx;
6107f482600Sdownsj break;
6117f482600Sdownsj case 'h': case '4':
6127f482600Sdownsj case KEY_LEFT:
6137f482600Sdownsj ny = cury; nx = curx+BWIDTH-1;
6147f482600Sdownsj break;
6157f482600Sdownsj case 'l': case '6':
6167f482600Sdownsj case KEY_RIGHT:
6177f482600Sdownsj ny = cury; nx = curx+1;
6187f482600Sdownsj break;
6197f482600Sdownsj case 'y': case '7':
6207f482600Sdownsj case KEY_A1:
6217f482600Sdownsj ny = cury+BDEPTH-1; nx = curx+BWIDTH-1;
6227f482600Sdownsj break;
6237f482600Sdownsj case 'b': case '1':
6247f482600Sdownsj case KEY_C1:
6257f482600Sdownsj ny = cury+1; nx = curx+BWIDTH-1;
6267f482600Sdownsj break;
6277f482600Sdownsj case 'u': case '9':
6287f482600Sdownsj case KEY_A3:
6297f482600Sdownsj ny = cury+BDEPTH-1; nx = curx+1;
6307f482600Sdownsj break;
6317f482600Sdownsj case 'n': case '3':
6327f482600Sdownsj case KEY_C3:
6337f482600Sdownsj ny = cury+1; nx = curx+1;
6347f482600Sdownsj break;
6357f482600Sdownsj case FF:
6367f482600Sdownsj nx = curx; ny = cury;
6377f482600Sdownsj (void)clearok(stdscr, TRUE);
6387f482600Sdownsj (void)refresh();
6397f482600Sdownsj break;
640efc3f44dSpjanzen case KEY_MOUSE:
641efc3f44dSpjanzen {
642efc3f44dSpjanzen MEVENT myevent;
643efc3f44dSpjanzen
644efc3f44dSpjanzen getmouse(&myevent);
645efc3f44dSpjanzen if (atcpu
6467a13a1fbSpjanzen && myevent.y >= CY(0) && myevent.y < CY(BDEPTH)
6477a13a1fbSpjanzen && myevent.x >= CX(0) && myevent.x < CX(BWIDTH))
648efc3f44dSpjanzen {
649efc3f44dSpjanzen curx = CXINV(myevent.x);
650efc3f44dSpjanzen cury = CYINV(myevent.y);
651efc3f44dSpjanzen return(' ');
652efc3f44dSpjanzen }
653efc3f44dSpjanzen else
654efc3f44dSpjanzen beep();
655efc3f44dSpjanzen }
656efc3f44dSpjanzen break;
657859369c2Spjanzen case ERR:
658859369c2Spjanzen uninitgame(1);
659859369c2Spjanzen break;
6607f482600Sdownsj default:
6617f482600Sdownsj if (atcpu)
6627f482600Sdownsj (void) mvaddstr(CYBASE + BDEPTH + 1, CXBASE + 11, " ");
6637f482600Sdownsj else
6647f482600Sdownsj (void) mvaddstr(PYBASE + BDEPTH + 1, PXBASE + 11, " ");
6657f482600Sdownsj return(c);
6667f482600Sdownsj }
6677f482600Sdownsj
6687f482600Sdownsj curx = nx % BWIDTH;
6697f482600Sdownsj cury = ny % BDEPTH;
6707f482600Sdownsj }
6717f482600Sdownsj }
6727f482600Sdownsj
6737f482600Sdownsj /* is this location on the selected zboard adjacent to a ship? */
674cd84dbdaSmestre static int
collidecheck(int b,int y,int x)675cd84dbdaSmestre collidecheck(int b, int y, int x)
6767f482600Sdownsj {
6777f482600Sdownsj int collide;
6787f482600Sdownsj
6797f482600Sdownsj /* anything on the square */
680efc3f44dSpjanzen if ((collide = IS_SHIP(board[b][x][y])) != 0)
6817f482600Sdownsj return(collide);
6827f482600Sdownsj
6837f482600Sdownsj /* anything on the neighbors */
6847f482600Sdownsj if (!closepack)
6857f482600Sdownsj {
6867f482600Sdownsj int i;
6877f482600Sdownsj
6887f482600Sdownsj for (i = 0; i < 8; i++)
6897f482600Sdownsj {
6907f482600Sdownsj int xend, yend;
6917f482600Sdownsj
6927f482600Sdownsj yend = y + yincr[i];
6937f482600Sdownsj xend = x + xincr[i];
6947f482600Sdownsj if (ONBOARD(xend, yend))
6957f482600Sdownsj collide += IS_SHIP(board[b][xend][yend]);
6967f482600Sdownsj }
6977f482600Sdownsj }
6987f482600Sdownsj return(collide);
6997f482600Sdownsj }
7007f482600Sdownsj
701cd84dbdaSmestre static bool
checkplace(int b,ship_t * ss,int vis)702cd84dbdaSmestre checkplace(int b, ship_t *ss, int vis)
7037f482600Sdownsj {
7047f482600Sdownsj int l, xend, yend;
7057f482600Sdownsj
7067f482600Sdownsj /* first, check for board edges */
707efc3f44dSpjanzen xend = ss->x + (ss->length - 1) * xincr[ss->dir];
708efc3f44dSpjanzen yend = ss->y + (ss->length - 1) * yincr[ss->dir];
7097f482600Sdownsj if (!ONBOARD(xend, yend))
7107f482600Sdownsj {
7117f482600Sdownsj if (vis)
7127f482600Sdownsj switch(rnd(3))
7137f482600Sdownsj {
7147f482600Sdownsj case 0:
7157f482600Sdownsj error("Ship is hanging from the edge of the world");
7167f482600Sdownsj break;
7177f482600Sdownsj case 1:
7187f482600Sdownsj error("Try fitting it on the board");
7197f482600Sdownsj break;
7207f482600Sdownsj case 2:
7217f482600Sdownsj error("Figure I won't find it if you put it there?");
7227f482600Sdownsj break;
7237f482600Sdownsj }
72401ee717fSpjanzen return(FALSE);
7257f482600Sdownsj }
7267f482600Sdownsj
7277f482600Sdownsj for(l = 0; l < ss->length; ++l)
7287f482600Sdownsj {
7297f482600Sdownsj if(collidecheck(b, ss->y+l*yincr[ss->dir], ss->x+l*xincr[ss->dir]))
7307f482600Sdownsj {
7317f482600Sdownsj if (vis)
7327f482600Sdownsj switch(rnd(3))
7337f482600Sdownsj {
7347f482600Sdownsj case 0:
7357f482600Sdownsj error("There's already a ship there");
7367f482600Sdownsj break;
7377f482600Sdownsj case 1:
7387f482600Sdownsj error("Collision alert! Aaaaaagh!");
7397f482600Sdownsj break;
7407f482600Sdownsj case 2:
7417f482600Sdownsj error("Er, Admiral, what about the other ship?");
7427f482600Sdownsj break;
7437f482600Sdownsj }
7447f482600Sdownsj return(FALSE);
7457f482600Sdownsj }
7467f482600Sdownsj }
7477f482600Sdownsj return(TRUE);
7487f482600Sdownsj }
7497f482600Sdownsj
750cd84dbdaSmestre static int
awinna(void)751cd84dbdaSmestre awinna(void)
7527f482600Sdownsj {
7537f482600Sdownsj int i, j;
7547f482600Sdownsj ship_t *ss;
7557f482600Sdownsj
7567f482600Sdownsj for(i=0; i<2; ++i)
7577f482600Sdownsj {
7587f482600Sdownsj ss = (i) ? cpuship : plyship;
7597f482600Sdownsj for(j=0; j < SHIPTYPES; ++j, ++ss)
7607f482600Sdownsj if(ss->length > ss->hits)
7617f482600Sdownsj break;
7627f482600Sdownsj if (j == SHIPTYPES)
7637f482600Sdownsj return(OTHER);
7647f482600Sdownsj }
7657f482600Sdownsj return(-1);
7667f482600Sdownsj }
7677f482600Sdownsj
7687f482600Sdownsj /* register a hit on the targeted ship */
769cd84dbdaSmestre static ship_t *
hitship(int x,int y)770cd84dbdaSmestre hitship(int x, int y)
7717f482600Sdownsj {
7727f482600Sdownsj ship_t *sb, *ss;
7737f482600Sdownsj char sym;
7747f482600Sdownsj int oldx, oldy;
7757f482600Sdownsj
7767f482600Sdownsj getyx(stdscr, oldy, oldx);
7777f482600Sdownsj sb = (turn) ? plyship : cpuship;
7787f482600Sdownsj if(!(sym = board[OTHER][x][y]))
7797f482600Sdownsj return((ship_t *)NULL);
7807f482600Sdownsj for(ss = sb; ss < sb + SHIPTYPES; ++ss)
7817f482600Sdownsj if(ss->symbol == sym)
7827f482600Sdownsj {
7837f482600Sdownsj if (++ss->hits < ss->length) /* still afloat? */
7847f482600Sdownsj return((ship_t *)NULL);
7857f482600Sdownsj else /* sunk! */
7867f482600Sdownsj {
7877f482600Sdownsj int i, j;
7887f482600Sdownsj
7897f482600Sdownsj if (!closepack)
7907f482600Sdownsj for (j = -1; j <= 1; j++)
7917f482600Sdownsj {
7927f482600Sdownsj int bx = ss->x + j * xincr[(ss->dir + 2) % 8];
7937f482600Sdownsj int by = ss->y + j * yincr[(ss->dir + 2) % 8];
7947f482600Sdownsj
7957f482600Sdownsj for (i = -1; i <= ss->length; ++i)
7967f482600Sdownsj {
797efc3f44dSpjanzen int x1, y1;
7987f482600Sdownsj
799efc3f44dSpjanzen x1 = bx + i * xincr[ss->dir];
800efc3f44dSpjanzen y1 = by + i * yincr[ss->dir];
801efc3f44dSpjanzen if (ONBOARD(x1, y1))
8027f482600Sdownsj {
803efc3f44dSpjanzen hits[turn][x1][y1] = MARK_MISS;
804efc3f44dSpjanzen if (turn == PLAYER)
8057f482600Sdownsj {
806efc3f44dSpjanzen cgoto(y1, x1);
8077f482600Sdownsj if (has_colors())
8087f482600Sdownsj attron(COLOR_PAIR(COLOR_GREEN));
8097f482600Sdownsj (void)addch(MARK_MISS);
8107f482600Sdownsj attrset(0);
8117f482600Sdownsj }
8127f482600Sdownsj }
8137f482600Sdownsj }
8147f482600Sdownsj }
8157f482600Sdownsj
8167f482600Sdownsj for (i = 0; i < ss->length; ++i)
8177f482600Sdownsj {
818efc3f44dSpjanzen int x1 = ss->x + i * xincr[ss->dir];
819efc3f44dSpjanzen int y1 = ss->y + i * yincr[ss->dir];
8207f482600Sdownsj
821efc3f44dSpjanzen hits[turn][x1][y1] = ss->symbol;
822efc3f44dSpjanzen if (turn == PLAYER)
8237f482600Sdownsj {
824efc3f44dSpjanzen cgoto(y1, x1);
825efc3f44dSpjanzen (void) addch((chtype)(ss->symbol));
8267f482600Sdownsj }
8277f482600Sdownsj }
8287f482600Sdownsj
8297f482600Sdownsj (void) move(oldy, oldx);
8307f482600Sdownsj return(ss);
8317f482600Sdownsj }
8327f482600Sdownsj }
8337f482600Sdownsj (void) move(oldy, oldx);
8347f482600Sdownsj return((ship_t *)NULL);
8357f482600Sdownsj }
8367f482600Sdownsj
837cd84dbdaSmestre static int
plyturn(void)838cd84dbdaSmestre plyturn(void)
8397f482600Sdownsj {
8407f482600Sdownsj ship_t *ss;
84101ee717fSpjanzen int hit;
842efc3f44dSpjanzen char *m = NULL;
8437f482600Sdownsj
8443e07b96bSguenther prompt(1, "Where do you want to shoot? ");
8457f482600Sdownsj for (;;)
8467f482600Sdownsj {
8477f482600Sdownsj (void) getcoord(COMPUTER);
8487f482600Sdownsj if (hits[PLAYER][curx][cury])
8497f482600Sdownsj {
8503e07b96bSguenther prompt(1, "You shelled this spot already! Try again.");
8517f482600Sdownsj beep();
8527f482600Sdownsj }
8537f482600Sdownsj else
8547f482600Sdownsj break;
8557f482600Sdownsj }
8567f482600Sdownsj hit = IS_SHIP(board[COMPUTER][curx][cury]);
8577f482600Sdownsj hits[PLAYER][curx][cury] = hit ? MARK_HIT : MARK_MISS;
8587f482600Sdownsj cgoto(cury, curx);
85901ee717fSpjanzen if (has_colors()) {
8607f482600Sdownsj if (hit)
8617f482600Sdownsj attron(COLOR_PAIR(COLOR_RED));
8627f482600Sdownsj else
8637f482600Sdownsj attron(COLOR_PAIR(COLOR_GREEN));
86401ee717fSpjanzen }
8657f482600Sdownsj (void) addch((chtype)hits[PLAYER][curx][cury]);
8667f482600Sdownsj attrset(0);
8677f482600Sdownsj
8687f482600Sdownsj prompt(1, "You %s.", hit ? "scored a hit" : "missed");
8697f482600Sdownsj if(hit && (ss = hitship(curx, cury)))
8707f482600Sdownsj {
8717f482600Sdownsj switch(rnd(5))
8727f482600Sdownsj {
8737f482600Sdownsj case 0:
8747f482600Sdownsj m = " You sank my %s!";
8757f482600Sdownsj break;
8767f482600Sdownsj case 1:
8777f482600Sdownsj m = " I have this sinking feeling about my %s....";
8787f482600Sdownsj break;
8797f482600Sdownsj case 2:
8807f482600Sdownsj m = " My %s has gone to Davy Jones's locker!";
8817f482600Sdownsj break;
8827f482600Sdownsj case 3:
8837f482600Sdownsj m = " Glub, glub -- my %s is headed for the bottom!";
8847f482600Sdownsj break;
8857f482600Sdownsj case 4:
886efc3f44dSpjanzen m = " You'll pick up survivors from my %s, I hope...!";
8877f482600Sdownsj break;
8887f482600Sdownsj }
8897f482600Sdownsj (void)printw(m, ss->name);
8907f482600Sdownsj (void)beep();
8917f482600Sdownsj }
8927f482600Sdownsj return(hit);
8937f482600Sdownsj }
8947f482600Sdownsj
895cd84dbdaSmestre static int
sgetc(char * s)896cd84dbdaSmestre sgetc(char *s)
8977f482600Sdownsj {
8987f482600Sdownsj char *s1;
8997f482600Sdownsj int ch;
9007f482600Sdownsj
9017f482600Sdownsj (void)refresh();
9027f482600Sdownsj for(;;)
9037f482600Sdownsj {
9047f482600Sdownsj ch = getch();
9057f482600Sdownsj if (islower(ch))
9067f482600Sdownsj ch = toupper(ch);
9077f482600Sdownsj if (ch == CTRLC)
908efc3f44dSpjanzen uninitgame(0);
9097f482600Sdownsj for (s1=s; *s1 && ch != *s1; ++s1)
9107f482600Sdownsj continue;
9117f482600Sdownsj if (*s1)
9127f482600Sdownsj {
9137f482600Sdownsj (void) addch((chtype)ch);
9147f482600Sdownsj (void) refresh();
9157f482600Sdownsj return(ch);
9167f482600Sdownsj }
9177f482600Sdownsj }
9187f482600Sdownsj }
9197f482600Sdownsj
920efc3f44dSpjanzen /* Checks to see if there's room for a ship of a given length in a given
921efc3f44dSpjanzen * direction. If direction is negative, check in all directions. Note
922efc3f44dSpjanzen * that North and South are equivalent, as are East and West.
923efc3f44dSpjanzen */
924cd84dbdaSmestre static bool
cpushipcanfit(int x,int y,int length,int direction)925cd84dbdaSmestre cpushipcanfit(int x, int y, int length, int direction)
9267f482600Sdownsj {
927efc3f44dSpjanzen int len = 1;
928efc3f44dSpjanzen int x1, y1;
929efc3f44dSpjanzen
930efc3f44dSpjanzen if (direction >= 0)
931efc3f44dSpjanzen {
932efc3f44dSpjanzen direction %= 4;
933efc3f44dSpjanzen while (direction < 8)
934efc3f44dSpjanzen {
935efc3f44dSpjanzen x1 = x + xincr[direction];
936efc3f44dSpjanzen y1 = y + yincr[direction];
937efc3f44dSpjanzen while (POSSIBLE(x1,y1))
938efc3f44dSpjanzen {
939efc3f44dSpjanzen len++;
940efc3f44dSpjanzen x1 += xincr[direction];
941efc3f44dSpjanzen y1 += yincr[direction];
942efc3f44dSpjanzen }
943efc3f44dSpjanzen direction += 4;
944efc3f44dSpjanzen }
945efc3f44dSpjanzen return (len >= length);
946efc3f44dSpjanzen }
947efc3f44dSpjanzen else
948efc3f44dSpjanzen {
949efc3f44dSpjanzen return ((cpushipcanfit(x,y,length,E)) ||
950efc3f44dSpjanzen (cpushipcanfit(x,y,length,S)));
951efc3f44dSpjanzen }
952efc3f44dSpjanzen }
953efc3f44dSpjanzen
954efc3f44dSpjanzen /* random-fire routine -- implements simple diagonal-striping strategy */
955cd84dbdaSmestre static void
randomfire(int * px,int * py)956cd84dbdaSmestre randomfire(int *px, int *py)
957efc3f44dSpjanzen {
9587f482600Sdownsj static int huntoffs; /* Offset on search strategy */
9597f482600Sdownsj int ypossible[BWIDTH * BDEPTH], xpossible[BWIDTH * BDEPTH], nposs;
9607f482600Sdownsj int x, y, i;
9617f482600Sdownsj
9627f482600Sdownsj if (turncount++ == 0)
9637f482600Sdownsj huntoffs = rnd(srchstep);
9647f482600Sdownsj
965efc3f44dSpjanzen /* first, list all possible moves on the diagonal stripe */
966efc3f44dSpjanzen nposs = 0;
9677f482600Sdownsj for (x = 0; x < BWIDTH; x++)
9687f482600Sdownsj for (y = 0; y < BDEPTH; y++)
969efc3f44dSpjanzen if ((!hits[COMPUTER][x][y]) &&
970efc3f44dSpjanzen (((x+huntoffs) % srchstep) == (y % srchstep)) &&
971efc3f44dSpjanzen (cpushipcanfit(x,y,cpulongest,-1)))
9727f482600Sdownsj {
9737f482600Sdownsj xpossible[nposs] = x;
9747f482600Sdownsj ypossible[nposs] = y;
9757f482600Sdownsj nposs++;
9767f482600Sdownsj }
977efc3f44dSpjanzen if (nposs)
9787f482600Sdownsj {
9797f482600Sdownsj i = rnd(nposs);
9807f482600Sdownsj
9817f482600Sdownsj *px = xpossible[i];
9827f482600Sdownsj *py = ypossible[i];
983efc3f44dSpjanzen }
984efc3f44dSpjanzen else if (srchstep > cpulongest)
985efc3f44dSpjanzen {
9867f482600Sdownsj --srchstep;
987cbddbf59Spjanzen randomfire(px, py);
9887f482600Sdownsj }
9897f482600Sdownsj else
9907f482600Sdownsj {
9917f482600Sdownsj error("No moves possible?? Help!");
9927f482600Sdownsj exit(1);
9937f482600Sdownsj }
9947f482600Sdownsj }
9957f482600Sdownsj
9967f482600Sdownsj #define S_MISS 0
9977f482600Sdownsj #define S_HIT 1
9987f482600Sdownsj #define S_SUNK -1
9997f482600Sdownsj
10007f482600Sdownsj /* fire away at given location */
1001cd84dbdaSmestre static int
cpufire(int x,int y)1002cd84dbdaSmestre cpufire(int x, int y)
10037f482600Sdownsj {
100401ee717fSpjanzen int hit;
100501ee717fSpjanzen bool sunk;
1006efc3f44dSpjanzen ship_t *ss = NULL;
10077f482600Sdownsj
10087f482600Sdownsj hits[COMPUTER][x][y] = (hit = (board[PLAYER][x][y])) ? MARK_HIT : MARK_MISS;
10097f482600Sdownsj (void) mvprintw(PROMPTLINE, 0,
10107f482600Sdownsj "I shoot at %c%d. I %s!", y + 'A', x, hit ? "hit" : "miss");
1011efc3f44dSpjanzen if ((sunk = (hit && (ss = hitship(x, y)))))
10127f482600Sdownsj (void) printw(" I've sunk your %s", ss->name);
10137f482600Sdownsj (void)clrtoeol();
10147f482600Sdownsj
10157f482600Sdownsj pgoto(y, x);
101601ee717fSpjanzen if (has_colors()) {
10177f482600Sdownsj if (hit)
10187f482600Sdownsj attron(COLOR_PAIR(COLOR_RED));
10197f482600Sdownsj else
10207f482600Sdownsj attron(COLOR_PAIR(COLOR_GREEN));
102101ee717fSpjanzen }
10227f482600Sdownsj (void) addch((chtype)(hit ? SHOWHIT : SHOWSPLASH));
10237f482600Sdownsj attrset(0);
10247f482600Sdownsj
10257f482600Sdownsj return(hit ? (sunk ? S_SUNK : S_HIT) : S_MISS);
10267f482600Sdownsj }
10277f482600Sdownsj
10287f482600Sdownsj /*
10297f482600Sdownsj * This code implements a fairly irregular FSM, so please forgive the rampant
10307f482600Sdownsj * unstructuredness below. The five labels are states which need to be held
10317f482600Sdownsj * between computer turns.
10327f482600Sdownsj */
1033cd84dbdaSmestre static int
cputurn(void)1034cd84dbdaSmestre cputurn(void)
10357f482600Sdownsj {
10367f482600Sdownsj static bool used[4];
10377f482600Sdownsj static ship_t ts;
10387f482600Sdownsj int navail, x, y, d, n, hit = S_MISS;
1039efc3f44dSpjanzen bool closenoshot = FALSE;
10407f482600Sdownsj
10417f482600Sdownsj switch(next)
10427f482600Sdownsj {
10437f482600Sdownsj case RANDOM_FIRE: /* last shot was random and missed */
10447f482600Sdownsj refire:
10457f482600Sdownsj randomfire(&x, &y);
10467f482600Sdownsj if (!(hit = cpufire(x, y)))
10477f482600Sdownsj next = RANDOM_FIRE;
10487f482600Sdownsj else
10497f482600Sdownsj {
10507f482600Sdownsj ts.x = x; ts.y = y;
10517f482600Sdownsj ts.hits = 1;
10527f482600Sdownsj next = (hit == S_SUNK) ? RANDOM_FIRE : RANDOM_HIT;
10537f482600Sdownsj }
10547f482600Sdownsj break;
10557f482600Sdownsj
10567f482600Sdownsj case RANDOM_HIT: /* last shot was random and hit */
1057efc3f44dSpjanzen used[E/2] = used[W/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,E)));
1058efc3f44dSpjanzen used[S/2] = used[N/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,S)));
10597f482600Sdownsj /* FALLTHROUGH */
10607f482600Sdownsj
10617f482600Sdownsj case HUNT_DIRECT: /* last shot hit, we're looking for ship's long axis */
10627f482600Sdownsj for (d = navail = 0; d < 4; d++)
10637f482600Sdownsj {
10647f482600Sdownsj x = ts.x + xincr[d*2]; y = ts.y + yincr[d*2];
10657f482600Sdownsj if (!used[d] && POSSIBLE(x, y))
10667f482600Sdownsj navail++;
10677f482600Sdownsj else
10687f482600Sdownsj used[d] = TRUE;
10697f482600Sdownsj }
10707f482600Sdownsj if (navail == 0) /* no valid places for shots adjacent... */
10717f482600Sdownsj goto refire; /* ...so we must random-fire */
10727f482600Sdownsj else
10737f482600Sdownsj {
1074efc3f44dSpjanzen for (d = 0, n = rnd(navail) + 1; n; n--,d++)
10757f482600Sdownsj while (used[d])
10767f482600Sdownsj d++;
1077efc3f44dSpjanzen d--;
10787f482600Sdownsj
10797f482600Sdownsj x = ts.x + xincr[d*2];
10807f482600Sdownsj y = ts.y + yincr[d*2];
10817f482600Sdownsj
10827f482600Sdownsj if (!(hit = cpufire(x, y)))
10837f482600Sdownsj next = HUNT_DIRECT;
10847f482600Sdownsj else
10857f482600Sdownsj {
10867f482600Sdownsj ts.x = x; ts.y = y; ts.dir = d*2; ts.hits++;
10877f482600Sdownsj next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
10887f482600Sdownsj }
10897f482600Sdownsj }
10907f482600Sdownsj break;
10917f482600Sdownsj
10927f482600Sdownsj case FIRST_PASS: /* we have a start and a direction now */
10937f482600Sdownsj x = ts.x + xincr[ts.dir];
10947f482600Sdownsj y = ts.y + yincr[ts.dir];
1095efc3f44dSpjanzen if (POSSIBLE(x, y))
1096efc3f44dSpjanzen {
1097efc3f44dSpjanzen if ((hit = cpufire(x, y)))
10987f482600Sdownsj {
10997f482600Sdownsj ts.x = x; ts.y = y; ts.hits++;
11007f482600Sdownsj next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
11017f482600Sdownsj }
11027f482600Sdownsj else
11037f482600Sdownsj next = REVERSE_JUMP;
11047f482600Sdownsj break;
11057f482600Sdownsj }
11067f482600Sdownsj else
1107efc3f44dSpjanzen next = REVERSE_JUMP;
1108efc3f44dSpjanzen /* FALL THROUGH */
1109efc3f44dSpjanzen
1110efc3f44dSpjanzen case REVERSE_JUMP: /* nail down the ship's other end */
1111efc3f44dSpjanzen ts.dir = (ts.dir + 4) % 8;
1112efc3f44dSpjanzen ts.x += (ts.hits-1) * xincr[ts.dir];
1113efc3f44dSpjanzen ts.y += (ts.hits-1) * yincr[ts.dir];
1114efc3f44dSpjanzen /* FALL THROUGH */
11157f482600Sdownsj
11167f482600Sdownsj case SECOND_PASS: /* kill squares not caught on first pass */
11177f482600Sdownsj x = ts.x + xincr[ts.dir];
11187f482600Sdownsj y = ts.y + yincr[ts.dir];
1119efc3f44dSpjanzen if (POSSIBLE(x, y))
1120efc3f44dSpjanzen {
1121efc3f44dSpjanzen if ((hit = cpufire(x, y)))
11227f482600Sdownsj {
11237f482600Sdownsj ts.x = x; ts.y = y; ts.hits++;
11247f482600Sdownsj next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS;
11257f482600Sdownsj }
11267f482600Sdownsj else
1127efc3f44dSpjanzen {
1128efc3f44dSpjanzen /* The only way to get here is if closepack is on; otherwise,
1129efc3f44dSpjanzen * we _have_ sunk the ship. I set hit to S_SUNK just to get
1130efc3f44dSpjanzen * the additional closepack logic at the end of the switch.
1131efc3f44dSpjanzen */
1132efc3f44dSpjanzen /*assert closepack*/
1133efc3f44dSpjanzen if (!closepack) error("Assertion failed: not closepack 1");
1134efc3f44dSpjanzen hit = S_SUNK;
11357f482600Sdownsj next = RANDOM_FIRE;
1136efc3f44dSpjanzen }
1137efc3f44dSpjanzen }
1138efc3f44dSpjanzen else
1139efc3f44dSpjanzen {
1140efc3f44dSpjanzen /*assert closepack*/
1141efc3f44dSpjanzen if (!closepack) error("Assertion failed: not closepack 2");
1142efc3f44dSpjanzen hit = S_SUNK;
1143efc3f44dSpjanzen closenoshot = TRUE; /* Didn't shoot yet! */
1144efc3f44dSpjanzen next = RANDOM_FIRE;
1145efc3f44dSpjanzen }
11467f482600Sdownsj break;
1147efc3f44dSpjanzen } /* switch(next) */
1148efc3f44dSpjanzen
1149efc3f44dSpjanzen if (hit == S_SUNK)
1150efc3f44dSpjanzen {
1151efc3f44dSpjanzen /* Update cpulongest and cpushortest. We could increase srchstep
1152efc3f44dSpjanzen * if it's smaller than cpushortest but that makes strategic sense
1153efc3f44dSpjanzen * only if we've been doing continuous diagonal stripes, and that's
1154efc3f44dSpjanzen * less interesting to watch.
1155efc3f44dSpjanzen */
1156efc3f44dSpjanzen ship_t *sp = plyship;
1157efc3f44dSpjanzen
1158efc3f44dSpjanzen cpushortest = cpulongest;
1159efc3f44dSpjanzen cpulongest = 0;
1160efc3f44dSpjanzen for (d=0 ; d < SHIPTYPES; d++, sp++)
1161efc3f44dSpjanzen {
1162efc3f44dSpjanzen if (sp->hits < sp->length)
1163efc3f44dSpjanzen {
1164efc3f44dSpjanzen cpushortest = (cpushortest < sp->length) ? cpushortest : sp->length;
1165efc3f44dSpjanzen cpulongest = (cpulongest > sp->length) ? cpulongest : sp->length;
1166efc3f44dSpjanzen }
1167efc3f44dSpjanzen }
1168efc3f44dSpjanzen /* Now, if we're in closepack mode, we may have knocked off part of
1169efc3f44dSpjanzen * another ship, in which case we shouldn't do RANDOM_FIRE. A
1170efc3f44dSpjanzen * more robust implementation would probably do this check regardless
1171efc3f44dSpjanzen * of whether closepack was set or not.
1172efc3f44dSpjanzen * Note that MARK_HIT is set only for ships that aren't sunk;
1173efc3f44dSpjanzen * hitship() changes the marker to the ship's character when the
1174efc3f44dSpjanzen * ship is sunk.
1175efc3f44dSpjanzen */
1176efc3f44dSpjanzen if (closepack)
1177efc3f44dSpjanzen {
1178efc3f44dSpjanzen ts.hits = 0;
1179efc3f44dSpjanzen for (x = 0; x < BWIDTH; x++)
1180efc3f44dSpjanzen for (y = 0; y < BDEPTH; y++)
1181efc3f44dSpjanzen {
1182efc3f44dSpjanzen if (hits[COMPUTER][x][y] == MARK_HIT)
1183efc3f44dSpjanzen {
1184efc3f44dSpjanzen /* So we found part of another ship. It may have more
1185efc3f44dSpjanzen * than one hit on it. Check to see if it does. If no
1186efc3f44dSpjanzen * hit does, take the last MARK_HIT and be RANDOM_HIT.
1187efc3f44dSpjanzen */
1188efc3f44dSpjanzen ts.x = x; ts.y = y; ts.hits = 1;
1189efc3f44dSpjanzen for (d = 0; d < 8; d += 2)
1190efc3f44dSpjanzen {
1191efc3f44dSpjanzen while ((ONBOARD(ts.x, ts.y)) &&
1192efc3f44dSpjanzen (hits[COMPUTER][(int)ts.x][(int)ts.y] == MARK_HIT))
1193efc3f44dSpjanzen {
1194efc3f44dSpjanzen ts.x += xincr[d]; ts.y += yincr[d]; ts.hits++;
1195efc3f44dSpjanzen }
1196efc3f44dSpjanzen if ((--ts.hits > 1) && (ONBOARD(ts.x, ts.y)) &&
1197efc3f44dSpjanzen (hits[COMPUTER][(int)ts.x][(int)ts.y] == 0))
1198efc3f44dSpjanzen {
1199efc3f44dSpjanzen ts.dir = d;
1200efc3f44dSpjanzen ts.x -= xincr[d]; ts.y -= yincr[d];
1201efc3f44dSpjanzen d = 100; /* use as a flag */
1202efc3f44dSpjanzen x = BWIDTH; y = BDEPTH; /* end the loop */
1203efc3f44dSpjanzen } else {
1204efc3f44dSpjanzen ts.x = x; ts.y = y; ts.hits = 1;
1205efc3f44dSpjanzen }
1206efc3f44dSpjanzen
1207efc3f44dSpjanzen }
1208efc3f44dSpjanzen }
1209efc3f44dSpjanzen if (ts.hits)
1210efc3f44dSpjanzen {
1211efc3f44dSpjanzen next = (d >= 100) ? FIRST_PASS : RANDOM_HIT;
1212efc3f44dSpjanzen } else
1213efc3f44dSpjanzen next = RANDOM_FIRE;
1214efc3f44dSpjanzen }
1215efc3f44dSpjanzen }
1216efc3f44dSpjanzen if (closenoshot)
1217efc3f44dSpjanzen {
1218efc3f44dSpjanzen return(cputurn());
1219efc3f44dSpjanzen }
12207f482600Sdownsj }
12217f482600Sdownsj
12227f482600Sdownsj /* check for continuation and/or winner */
12237f482600Sdownsj if (salvo)
12247f482600Sdownsj {
12257f482600Sdownsj (void)refresh();
12267f482600Sdownsj (void)sleep(1);
12277f482600Sdownsj }
12287f482600Sdownsj
12297f482600Sdownsj return(hit);
12307f482600Sdownsj }
12317f482600Sdownsj
1232cd84dbdaSmestre static int
playagain(void)1233cd84dbdaSmestre playagain(void)
12347f482600Sdownsj {
12357f482600Sdownsj int j;
12367f482600Sdownsj ship_t *ss;
12377f482600Sdownsj
12387f482600Sdownsj for (ss = cpuship; ss < cpuship + SHIPTYPES; ss++)
12397f482600Sdownsj for(j = 0; j < ss->length; j++)
12407f482600Sdownsj {
12417f482600Sdownsj cgoto(ss->y + j * yincr[ss->dir], ss->x + j * xincr[ss->dir]);
12427f482600Sdownsj (void) addch((chtype)ss->symbol);
12437f482600Sdownsj }
12447f482600Sdownsj
12457f482600Sdownsj if(awinna())
12467f482600Sdownsj ++cpuwon;
12477f482600Sdownsj else
12487f482600Sdownsj ++plywon;
12497f482600Sdownsj j = 18 + strlen(name);
1250efc3f44dSpjanzen /* If you play a hundred games or more at a go, you deserve a badly
1251efc3f44dSpjanzen * centred score output.
1252efc3f44dSpjanzen */
12537f482600Sdownsj if(plywon >= 10)
12547f482600Sdownsj ++j;
12557f482600Sdownsj if(cpuwon >= 10)
12567f482600Sdownsj ++j;
12577f482600Sdownsj (void) mvprintw(1,(COLWIDTH-j)/2,
12587f482600Sdownsj "%s: %d Computer: %d",name,plywon,cpuwon);
12597f482600Sdownsj
12607f482600Sdownsj prompt(2, (awinna()) ? "Want to be humiliated again, %s [yn]? "
12617f482600Sdownsj : "Going to give me a chance for revenge, %s [yn]? ",name);
12627f482600Sdownsj return(sgetc("YN") == 'Y');
12637f482600Sdownsj }
12647f482600Sdownsj
1265cd84dbdaSmestre __dead void
usage(void)1266cd84dbdaSmestre usage(void)
1267efc3f44dSpjanzen {
12686fa5e1daSmestre (void) fprintf(stderr, "usage: %s [-b | -s] [-c]\n", getprogname());
1269efc3f44dSpjanzen (void) fprintf(stderr, "\tWhere the options are:\n");
1270efc3f44dSpjanzen (void) fprintf(stderr, "\t-b : play a blitz game\n");
1271d90ff1a6Ssobrado (void) fprintf(stderr, "\t-s : play a salvo game\n");
1272efc3f44dSpjanzen (void) fprintf(stderr, "\t-c : ships may be adjacent\n");
1273efc3f44dSpjanzen exit(1);
1274efc3f44dSpjanzen }
1275efc3f44dSpjanzen
1276cd84dbdaSmestre static void
do_options(int c,char * op[])1277cd84dbdaSmestre do_options(int c, char *op[])
12787f482600Sdownsj {
127995bd4873Sguenther int ch;
12807f482600Sdownsj
128195bd4873Sguenther while ((ch = getopt(c, op, "bchs")) != -1) {
128295bd4873Sguenther switch (ch) {
12837f482600Sdownsj case 'b':
12847f482600Sdownsj blitz = 1;
12857f482600Sdownsj if (salvo == 1)
12867f482600Sdownsj {
12877f482600Sdownsj (void) fprintf(stderr,
12887f482600Sdownsj "Bad Arg: -b and -s are mutually exclusive\n");
12897f482600Sdownsj exit(1);
12907f482600Sdownsj }
12917f482600Sdownsj break;
12927f482600Sdownsj case 's':
12937f482600Sdownsj salvo = 1;
12947f482600Sdownsj if (blitz == 1)
12957f482600Sdownsj {
12967f482600Sdownsj (void) fprintf(stderr,
12977f482600Sdownsj "Bad Arg: -s and -b are mutually exclusive\n");
12987f482600Sdownsj exit(1);
12997f482600Sdownsj }
13007f482600Sdownsj break;
13017f482600Sdownsj case 'c':
13027f482600Sdownsj closepack = 1;
13037f482600Sdownsj break;
1304efc3f44dSpjanzen case 'h':
13057f482600Sdownsj default:
130695bd4873Sguenther (void) usage();
13077f482600Sdownsj exit(1);
13087f482600Sdownsj }
13097f482600Sdownsj }
131095bd4873Sguenther if (op[optind] != NULL)
131195bd4873Sguenther (void) usage();
13127f482600Sdownsj }
13137f482600Sdownsj
1314cd84dbdaSmestre static int
scount(int who)1315cd84dbdaSmestre scount(int who)
13167f482600Sdownsj {
131797419aa0Spjanzen int i, shots;
131897419aa0Spjanzen ship_t *sp;
13197f482600Sdownsj
13207f482600Sdownsj if (who)
13217f482600Sdownsj sp = cpuship; /* count cpu shots */
13227f482600Sdownsj else
13237f482600Sdownsj sp = plyship; /* count player shots */
13247f482600Sdownsj
13257f482600Sdownsj for (i = 0, shots = 0; i < SHIPTYPES; i++, sp++)
13267f482600Sdownsj {
13277f482600Sdownsj if (sp->hits >= sp->length)
13287f482600Sdownsj continue; /* dead ship */
13297f482600Sdownsj else
13307f482600Sdownsj shots++;
13317f482600Sdownsj }
13327f482600Sdownsj return(shots);
13337f482600Sdownsj }
13347f482600Sdownsj
1335cd84dbdaSmestre int
main(int argc,char * argv[])1336cd84dbdaSmestre main(int argc, char *argv[])
13377f482600Sdownsj {
13387f482600Sdownsj do_options(argc, argv);
13397f482600Sdownsj
13407f482600Sdownsj intro();
1341b9f12921Smestre
1342b9f12921Smestre if (pledge("stdio tty", NULL) == -1)
1343b9f12921Smestre err(1, "pledge");
1344b9f12921Smestre
13457f482600Sdownsj do {
13467f482600Sdownsj initgame();
13477f482600Sdownsj while(awinna() == -1)
13487f482600Sdownsj {
13497f482600Sdownsj if (!blitz)
13507f482600Sdownsj {
13517f482600Sdownsj if (!salvo)
13527f482600Sdownsj {
13537f482600Sdownsj if(turn)
13547f482600Sdownsj (void) cputurn();
13557f482600Sdownsj else
13567f482600Sdownsj (void) plyturn();
13577f482600Sdownsj }
1358efc3f44dSpjanzen else /* salvo */
13597f482600Sdownsj {
136097419aa0Spjanzen int i;
13617f482600Sdownsj
13627f482600Sdownsj i = scount(turn);
13637f482600Sdownsj while (i--)
13647f482600Sdownsj {
13657f482600Sdownsj if (turn)
13667f482600Sdownsj {
13677f482600Sdownsj if (cputurn() && awinna() != -1)
13687f482600Sdownsj i = 0;
13697f482600Sdownsj }
13707f482600Sdownsj else
13717f482600Sdownsj {
13727f482600Sdownsj if (plyturn() && awinna() != -1)
13737f482600Sdownsj i = 0;
13747f482600Sdownsj }
13757f482600Sdownsj }
13767f482600Sdownsj }
13777f482600Sdownsj }
1378efc3f44dSpjanzen else /* blitz */
13797f482600Sdownsj while(turn ? cputurn() : plyturn())
1380efc3f44dSpjanzen {
1381efc3f44dSpjanzen if (turn) /* Pause between successive computer shots */
1382efc3f44dSpjanzen {
1383efc3f44dSpjanzen (void)refresh();
1384efc3f44dSpjanzen (void)sleep(1);
1385efc3f44dSpjanzen }
1386efc3f44dSpjanzen if (awinna() != -1)
1387efc3f44dSpjanzen break;
1388efc3f44dSpjanzen }
13897f482600Sdownsj turn = OTHER;
13907f482600Sdownsj }
13917f482600Sdownsj } while
13927f482600Sdownsj (playagain());
1393efc3f44dSpjanzen uninitgame(0);
139417641e31Stb return 0;
13957f482600Sdownsj }
1396