2 * bs.c - original author: Bruce Holloway
3 * salvo option by: Chuck A DeGaul
4 * with improved user interface, autoconfiguration and code cleanup
5 * by Eric S. Raymond <esr@snark.thyrsus.com>
6 * v1.2 with color support and minor portability fixes, November 1990
7 * v2.0 featuring strict ANSI/POSIX conformance, November 1993.
8 * v2.1 with ncurses mouse support, September 1995
10 * $Id: bs.c,v 1.39 2003/12/06 18:10:13 tom Exp $
15 #include <test.priv.h>
18 #define SIGIOT SIGABRT
21 static int getcoord(int);
24 * Constants for tuning the random-fire algorithm. It prefers moves that
25 * diagonal-stripe the board with a stripe separation of srchstep. If
26 * no such preferred moves are found, srchstep is decremented.
28 #define BEGINSTEP 3 /* initial value of srchstep */
30 /* miscellaneous constants */
32 #define OTHER (1-turn)
37 #define CTRLC '\003' /* used as terminate command */
38 #define FF '\014' /* used as redraw command */
40 /* coordinate handling */
46 #define SHOWSPLASH ' '
47 #define IS_SHIP(c) (isupper(UChar(c)) ? TRUE : FALSE)
49 /* how to position us on player board */
52 #define PY(y) (PYBASE + (y))
53 #define PX(x) (PXBASE + (x)*3)
54 #define pgoto(y, x) (void)move(PY(y), PX(x))
56 /* how to position us on cpu board */
59 #define CY(y) (CYBASE + (y))
60 #define CX(x) (CXBASE + (x)*3)
61 #define CYINV(y) ((y) - CYBASE)
62 #define CXINV(x) (((x) - CXBASE) / 3)
63 #define cgoto(y, x) (void)move(CY(y), CX(x))
65 #define ONBOARD(x, y) (x >= 0 && x < BWIDTH && y >= 0 && y < BDEPTH)
67 /* other board locations */
69 #define PROMPTLINE 21 /* prompt line */
70 #define SYBASE CYBASE + BDEPTH + 3 /* move key diagram */
72 #define MYBASE SYBASE - 1 /* diagram caption */
74 #define HYBASE SYBASE - 1 /* help area */
77 /* this will need to be changed if BWIDTH changes */
78 static char numbers
[] = " 0 1 2 3 4 5 6 7 8 9";
80 static char carrier
[] = "Aircraft Carrier";
81 static char battle
[] = "Battleship";
82 static char sub
[] = "Submarine";
83 static char destroy
[] = "Destroyer";
84 static char ptboat
[] = "PT Boat";
87 static char dftname
[] = "stranger";
89 /* direction constants */
99 {1, 1, 0, -1, -1, -1, 0, 1};
100 static int yincr
[8] =
101 {0, 1, 1, 1, 0, -1, -1, -1};
103 /* current ship position and direction */
104 static int curx
= (BWIDTH
/ 2);
105 static int cury
= (BDEPTH
/ 2);
108 char *name
; /* name of the ship type */
109 int hits
; /* how many times has this ship been hit? */
110 char symbol
; /* symbol for game purposes */
111 int length
; /* length of ship */
112 int x
, y
; /* coordinates of ship start point */
113 int dir
; /* direction of `bow' */
114 bool placed
; /* has it been placed on the board? */
117 static bool checkplace(int b
, ship_t
* ss
, int vis
);
119 #define SHIPIT(name, symbol, length) { name, 0, symbol, length, 0,0, 0, FALSE }
121 static ship_t plyship
[SHIPTYPES
] =
123 SHIPIT(carrier
, 'A', 5),
124 SHIPIT(battle
, 'B', 4),
125 SHIPIT(destroy
, 'D', 3),
127 SHIPIT(ptboat
, 'P', 2),
130 static ship_t cpuship
[SHIPTYPES
] =
132 SHIPIT(carrier
, 'A', 5),
133 SHIPIT(battle
, 'B', 4),
134 SHIPIT(destroy
, 'D', 3),
136 SHIPIT(ptboat
, 'P', 2),
139 /* "Hits" board, and main board. */
140 static char hits
[2][BWIDTH
][BDEPTH
];
141 static char board
[2][BWIDTH
][BDEPTH
];
143 static int turn
; /* 0=player, 1=computer */
144 static int plywon
= 0, cpuwon
= 0; /* How many games has each won? */
146 static int salvo
, blitz
, closepack
;
148 #define PR (void)addstr
150 static RETSIGTYPE
uninitgame(int sig
) GCC_NORETURN
;
152 static RETSIGTYPE
uninitgame(int sig GCC_UNUSED
)
153 /* end the game, either normally or due to signal */
157 (void) reset_shell_mode();
160 ExitProgram(sig
? EXIT_FAILURE
: EXIT_SUCCESS
);
165 /* announce which game options are enabled */
167 if (salvo
|| blitz
|| closepack
) {
168 (void) printw("Playing optional game (");
170 (void) printw("salvo, ");
172 (void) printw("nosalvo, ");
174 (void) printw("blitz ");
176 (void) printw("noblitz, ");
178 (void) printw("closepack)");
180 (void) printw("noclosepack)");
183 "Playing standard game (noblitz, nosalvo, noclosepack)");
191 srand((unsigned) (time(0L) + getpid())); /* Kick the random number generator */
193 (void) signal(SIGINT
, uninitgame
);
194 (void) signal(SIGINT
, uninitgame
);
195 (void) signal(SIGIOT
, uninitgame
); /* for assert(3) */
196 if (signal(SIGQUIT
, SIG_IGN
) != SIG_IGN
)
197 (void) signal(SIGQUIT
, uninitgame
);
199 if ((tmpname
= getlogin()) != 0) {
200 (void) strcpy(name
, tmpname
);
201 name
[0] = toupper(name
[0]);
203 (void) strcpy(name
, dftname
);
206 keypad(stdscr
, TRUE
);
207 (void) def_prog_mode();
214 (void) mvaddstr(4, 29, "Welcome to Battleship!");
218 PR(" \\ \\ \\ \\ \\_____________\n");
219 PR(" \\ \\ \\_____________ \\ \\/ |\n");
220 PR(" \\ \\/ \\ \\/ |\n");
221 PR(" \\/ \\_____/ |__\n");
222 PR(" ________________/ |\n");
223 PR(" \\ S.S. Penguin |\n");
225 PR(" \\___________________________________________________/\n");
227 (void) mvaddstr(22, 27, "Hit any key to continue...");
235 init_pair(COLOR_BLACK
, COLOR_BLACK
, COLOR_BLACK
);
236 init_pair(COLOR_GREEN
, COLOR_GREEN
, COLOR_BLACK
);
237 init_pair(COLOR_RED
, COLOR_RED
, COLOR_BLACK
);
238 init_pair(COLOR_CYAN
, COLOR_CYAN
, COLOR_BLACK
);
239 init_pair(COLOR_WHITE
, COLOR_WHITE
, COLOR_BLACK
);
240 init_pair(COLOR_MAGENTA
, COLOR_MAGENTA
, COLOR_BLACK
);
241 init_pair(COLOR_BLUE
, COLOR_BLUE
, COLOR_BLACK
);
242 init_pair(COLOR_YELLOW
, COLOR_YELLOW
, COLOR_BLACK
);
245 #ifdef NCURSES_MOUSE_VERSION
246 (void) mousemask(BUTTON1_CLICKED
, (mmask_t
*) NULL
);
247 #endif /* NCURSES_MOUSE_VERSION */
252 prompt(int n
, const char *f
, const char *s
)
253 /* print a message at the prompt line */
255 (void) move(PROMPTLINE
+ n
, 0);
262 error(NCURSES_CONST
char *s
)
264 (void) move(PROMPTLINE
+ 2, 0);
273 placeship(int b
, ship_t
* ss
, int vis
)
277 for (l
= 0; l
< ss
->length
; ++l
) {
278 int newx
= ss
->x
+ l
* xincr
[ss
->dir
];
279 int newy
= ss
->y
+ l
* yincr
[ss
->dir
];
281 board
[b
][newx
][newy
] = ss
->symbol
;
284 (void) addch((chtype
) ss
->symbol
);
293 return (((rand() & 0x7FFF) % n
));
297 randomplace(int b
, ship_t
* ss
)
298 /* generate a valid random ship placement into px,py */
302 ss
->dir
= rnd(2) ? E
: S
;
303 ss
->x
= rnd(BWIDTH
- (ss
->dir
== E
? ss
->length
: 0));
304 ss
->y
= rnd(BDEPTH
- (ss
->dir
== S
? ss
->length
: 0));
306 (!checkplace(b
, ss
, FALSE
));
316 (void) mvaddstr(0, 35, "BATTLESHIPS");
317 (void) move(PROMPTLINE
+ 2, 0);
320 memset(board
, 0, sizeof(char) * BWIDTH
* BDEPTH
* 2);
321 memset(hits
, 0, sizeof(char) * BWIDTH
* BDEPTH
* 2);
322 for (i
= 0; i
< SHIPTYPES
; i
++) {
340 /* draw empty boards */
341 (void) mvaddstr(PYBASE
- 2, PXBASE
+ 5, "Main Board");
342 (void) mvaddstr(PYBASE
- 1, PXBASE
- 3, numbers
);
343 for (i
= 0; i
< BDEPTH
; ++i
) {
344 (void) mvaddch(PYBASE
+ i
, PXBASE
- 3, (chtype
) (i
+ 'A'));
347 attron(COLOR_PAIR(COLOR_BLUE
));
350 for (j
= 0; j
< BWIDTH
; j
++)
351 (void) addstr(" . ");
356 (void) addch((chtype
) (i
+ 'A'));
358 (void) mvaddstr(PYBASE
+ BDEPTH
, PXBASE
- 3, numbers
);
359 (void) mvaddstr(CYBASE
- 2, CXBASE
+ 7, "Hit/Miss Board");
360 (void) mvaddstr(CYBASE
- 1, CXBASE
- 3, numbers
);
361 for (i
= 0; i
< BDEPTH
; ++i
) {
362 (void) mvaddch(CYBASE
+ i
, CXBASE
- 3, (chtype
) (i
+ 'A'));
365 attron(COLOR_PAIR(COLOR_BLUE
));
368 for (j
= 0; j
< BWIDTH
; j
++)
369 (void) addstr(" . ");
374 (void) addch((chtype
) (i
+ 'A'));
377 (void) mvaddstr(CYBASE
+ BDEPTH
, CXBASE
- 3, numbers
);
379 (void) mvprintw(HYBASE
, HXBASE
,
380 "To position your ships: move the cursor to a spot, then");
381 (void) mvprintw(HYBASE
+ 1, HXBASE
,
382 "type the first letter of a ship type to select it, then");
383 (void) mvprintw(HYBASE
+ 2, HXBASE
,
384 "type a direction ([hjkl] or [4862]), indicating how the");
385 (void) mvprintw(HYBASE
+ 3, HXBASE
,
386 "ship should be pointed. You may also type a ship letter");
387 (void) mvprintw(HYBASE
+ 4, HXBASE
,
388 "followed by `r' to position it randomly, or type `R' to");
389 (void) mvprintw(HYBASE
+ 5, HXBASE
,
390 "place all remaining ships randomly.");
392 (void) mvaddstr(MYBASE
, MXBASE
, "Aiming keys:");
393 (void) mvaddstr(SYBASE
, SXBASE
, "y k u 7 8 9");
394 (void) mvaddstr(SYBASE
+ 1, SXBASE
, " \\|/ \\|/ ");
395 (void) mvaddstr(SYBASE
+ 2, SXBASE
, "h-+-l 4-+-6");
396 (void) mvaddstr(SYBASE
+ 3, SXBASE
, " /|\\ /|\\ ");
397 (void) mvaddstr(SYBASE
+ 4, SXBASE
, "b j n 1 2 3");
399 /* have the computer place ships */
400 for (ss
= cpuship
; ss
< cpuship
+ SHIPTYPES
; ss
++) {
401 randomplace(COMPUTER
, ss
);
402 placeship(COMPUTER
, ss
, FALSE
);
405 ss
= (ship_t
*) NULL
;
407 char c
, docked
[SHIPTYPES
+ 2], *cp
= docked
;
409 /* figure which ships still wait to be placed */
411 for (i
= 0; i
< SHIPTYPES
; i
++)
412 if (!plyship
[i
].placed
)
413 *cp
++ = plyship
[i
].symbol
;
416 /* get a command letter */
417 prompt(1, "Type one of [%s] to pick a ship.", docked
+ 1);
419 c
= getcoord(PLAYER
);
421 (!strchr(docked
, c
));
426 /* map that into the corresponding symbol */
427 for (ss
= plyship
; ss
< plyship
+ SHIPTYPES
; ss
++)
431 prompt(1, "Type one of [hjklrR] to place your %s.", ss
->name
);
438 (!strchr("hjklrR", c
) || c
== FF
);
441 (void) clearok(stdscr
, TRUE
);
443 } else if (c
== 'r') {
444 prompt(1, "Random-placing your %s", ss
->name
);
445 randomplace(PLAYER
, ss
);
446 placeship(PLAYER
, ss
, TRUE
);
447 error((char *) NULL
);
449 } else if (c
== 'R') {
450 prompt(1, "Placing the rest of your fleet at random...", "");
451 for (ss
= plyship
; ss
< plyship
+ SHIPTYPES
; ss
++)
453 randomplace(PLAYER
, ss
);
454 placeship(PLAYER
, ss
, TRUE
);
457 error((char *) NULL
);
458 } else if (strchr("hjkl8462", c
)) {
481 if (checkplace(PLAYER
, ss
, TRUE
)) {
482 placeship(PLAYER
, ss
, TRUE
);
483 error((char *) NULL
);
488 for (unplaced
= i
= 0; i
< SHIPTYPES
; i
++)
489 unplaced
+= !plyship
[i
].placed
;
495 (void) mvprintw(HYBASE
, HXBASE
,
496 "To fire, move the cursor to your chosen aiming point ");
497 (void) mvprintw(HYBASE
+ 1, HXBASE
,
498 "and strike any key other than a motion key. ");
499 (void) mvprintw(HYBASE
+ 2, HXBASE
,
501 (void) mvprintw(HYBASE
+ 3, HXBASE
,
503 (void) mvprintw(HYBASE
+ 4, HXBASE
,
505 (void) mvprintw(HYBASE
+ 5, HXBASE
,
508 (void) prompt(0, "Press any key to start...", "");
524 (void) mvprintw(CYBASE
+ BDEPTH
+ 1, CXBASE
+ 11, "(%d, %c)",
528 (void) mvprintw(PYBASE
+ BDEPTH
+ 1, PXBASE
+ 11, "(%d, %c)",
533 switch (c
= getch()) {
537 ny
= cury
+ BDEPTH
- 1;
550 nx
= curx
+ BWIDTH
- 1;
561 ny
= cury
+ BDEPTH
- 1;
562 nx
= curx
+ BWIDTH
- 1;
568 nx
= curx
+ BWIDTH
- 1;
573 ny
= cury
+ BDEPTH
- 1;
585 (void) clearok(stdscr
, TRUE
);
588 #ifdef NCURSES_MOUSE_VERSION
595 && myevent
.y
>= CY(0) && myevent
.y
<= CY(BDEPTH
)
596 && myevent
.x
>= CX(0) && myevent
.x
<= CX(BDEPTH
)) {
597 curx
= CXINV(myevent
.x
);
598 cury
= CYINV(myevent
.y
);
605 /* no fall through */
606 #endif /* NCURSES_MOUSE_VERSION */
610 (void) mvaddstr(CYBASE
+ BDEPTH
+ 1, CXBASE
+ 11, " ");
612 (void) mvaddstr(PYBASE
+ BDEPTH
+ 1, PXBASE
+ 11, " ");
622 collidecheck(int b
, int y
, int x
)
623 /* is this location on the selected zboard adjacent to a ship? */
627 /* anything on the square */
628 if ((collide
= IS_SHIP(board
[b
][x
][y
])) != FALSE
)
631 /* anything on the neighbors */
635 for (i
= 0; i
< 8; i
++) {
640 if (ONBOARD(xend
, yend
)
641 && IS_SHIP(board
[b
][xend
][yend
])) {
651 checkplace(int b
, ship_t
* ss
, int vis
)
655 /* first, check for board edges */
656 xend
= ss
->x
+ (ss
->length
- 1) * xincr
[ss
->dir
];
657 yend
= ss
->y
+ (ss
->length
- 1) * yincr
[ss
->dir
];
658 if (!ONBOARD(xend
, yend
)) {
662 error("Ship is hanging from the edge of the world");
665 error("Try fitting it on the board");
668 error("Figure I won't find it if you put it there?");
674 for (l
= 0; l
< ss
->length
; ++l
) {
675 if (collidecheck(b
, ss
->y
+ l
* yincr
[ss
->dir
], ss
->x
+ l
* xincr
[ss
->dir
])) {
679 error("There's already a ship there");
682 error("Collision alert! Aaaaaagh!");
685 error("Er, Admiral, what about the other ship?");
700 for (i
= 0; i
< 2; ++i
) {
701 ss
= (i
) ? cpuship
: plyship
;
702 for (j
= 0; j
< SHIPTYPES
; ++j
, ++ss
)
703 if (ss
->length
> ss
->hits
)
712 hitship(int x
, int y
)
713 /* register a hit on the targeted ship */
719 getyx(stdscr
, oldy
, oldx
);
720 sb
= (turn
) ? plyship
: cpuship
;
721 if ((sym
= board
[OTHER
][x
][y
]) == 0)
722 return ((ship_t
*) NULL
);
723 for (ss
= sb
; ss
< sb
+ SHIPTYPES
; ++ss
)
724 if (ss
->symbol
== sym
) {
725 if (++ss
->hits
< ss
->length
) /* still afloat? */
726 return ((ship_t
*) NULL
);
731 for (j
= -1; j
<= 1; j
++) {
732 int bx
= ss
->x
+ j
* xincr
[(ss
->dir
+ 2) % 8];
733 int by
= ss
->y
+ j
* yincr
[(ss
->dir
+ 2) % 8];
735 for (i
= -1; i
<= ss
->length
; ++i
) {
738 x1
= bx
+ i
* xincr
[ss
->dir
];
739 y1
= by
+ i
* yincr
[ss
->dir
];
740 if (ONBOARD(x1
, y1
)) {
741 hits
[turn
][x1
][y1
] = MARK_MISS
;
742 if (turn
% 2 == PLAYER
) {
746 attron(COLOR_PAIR(COLOR_GREEN
));
748 (void) addch(MARK_MISS
);
754 (void) addch(SHOWSPLASH
);
760 for (i
= 0; i
< ss
->length
; ++i
) {
761 int x1
= ss
->x
+ i
* xincr
[ss
->dir
];
762 int y1
= ss
->y
+ i
* yincr
[ss
->dir
];
764 hits
[turn
][x1
][y1
] = ss
->symbol
;
765 if (turn
% 2 == PLAYER
) {
767 (void) addch((chtype
) (ss
->symbol
));
772 attron(COLOR_PAIR(COLOR_RED
));
774 (void) addch(SHOWHIT
);
781 (void) move(oldy
, oldx
);
785 (void) move(oldy
, oldx
);
786 return ((ship_t
*) NULL
);
794 NCURSES_CONST
char *m
= NULL
;
796 prompt(1, "Where do you want to shoot? ", "");
798 (void) getcoord(COMPUTER
);
799 if (hits
[PLAYER
][curx
][cury
]) {
800 prompt(1, "You shelled this spot already! Try again.", "");
805 hit
= IS_SHIP(board
[COMPUTER
][curx
][cury
]);
806 hits
[PLAYER
][curx
][cury
] = (hit
? MARK_HIT
: MARK_MISS
);
811 attron(COLOR_PAIR(COLOR_RED
));
813 attron(COLOR_PAIR(COLOR_GREEN
));
816 (void) addch((chtype
) hits
[PLAYER
][curx
][cury
]);
821 prompt(1, "You %s.", hit
? "scored a hit" : "missed");
822 if (hit
&& (ss
= hitship(curx
, cury
))) {
825 m
= " You sank my %s!";
828 m
= " I have this sinking feeling about my %s....";
831 m
= " My %s has gone to Davy Jones's locker!";
834 m
= " Glub, glub -- my %s is headed for the bottom!";
837 m
= " You'll pick up survivors from my %s, I hope...!";
840 (void) printw(m
, ss
->name
);
842 return (awinna() == -1);
860 for (s1
= s
; *s1
&& ch
!= *s1
; ++s1
)
863 (void) addch((chtype
) ch
);
871 randomfire(int *px
, int *py
)
872 /* random-fire routine -- implements simple diagonal-striping strategy */
874 static int turncount
= 0;
875 static int srchstep
= BEGINSTEP
;
876 static int huntoffs
; /* Offset on search strategy */
877 int ypossible
[BWIDTH
* BDEPTH
], xpossible
[BWIDTH
* BDEPTH
], nposs
;
878 int ypreferred
[BWIDTH
* BDEPTH
], xpreferred
[BWIDTH
* BDEPTH
], npref
;
881 if (turncount
++ == 0)
882 huntoffs
= rnd(srchstep
);
884 /* first, list all possible moves */
886 for (x
= 0; x
< BWIDTH
; x
++)
887 for (y
= 0; y
< BDEPTH
; y
++)
888 if (!hits
[COMPUTER
][x
][y
]) {
889 xpossible
[nposs
] = x
;
890 ypossible
[nposs
] = y
;
892 if (((x
+ huntoffs
) % srchstep
) != (y
% srchstep
)) {
893 xpreferred
[npref
] = x
;
894 ypreferred
[npref
] = y
;
913 error("No moves possible?? Help!");
914 ExitProgram(EXIT_FAILURE
);
924 cpufire(int x
, int y
)
925 /* fire away at given location */
930 hits
[COMPUTER
][x
][y
] = (hit
= (board
[PLAYER
][x
][y
])) ? MARK_HIT
: MARK_MISS
;
931 (void) mvprintw(PROMPTLINE
, 0,
932 "I shoot at %c%d. I %s!", y
+ 'A', x
, hit
? "hit" :
934 if ((sunk
= (hit
&& (ss
= hitship(x
, y
)))) != 0)
935 (void) printw(" I've sunk your %s", ss
->name
);
942 attron(COLOR_PAIR(COLOR_RED
));
944 attron(COLOR_PAIR(COLOR_GREEN
));
947 (void) addch((chtype
) (hit
? SHOWHIT
: SHOWSPLASH
));
952 return ((hit
? (sunk
? S_SUNK
: S_HIT
) : S_MISS
) ? TRUE
: FALSE
);
956 * This code implements a fairly irregular FSM, so please forgive the rampant
957 * unstructuredness below. The five labels are states which need to be held
958 * between computer turns.
963 #define POSSIBLE(x, y) (ONBOARD(x, y) && !hits[COMPUTER][x][y])
964 #define RANDOM_FIRE 0
966 #define HUNT_DIRECT 2
968 #define REVERSE_JUMP 4
969 #define SECOND_PASS 5
970 static int next
= RANDOM_FIRE
;
973 int navail
, x
, y
, d
, n
;
977 case RANDOM_FIRE
: /* last shot was random and missed */
980 if (!(hit
= cpufire(x
, y
)))
986 next
= (hit
== S_SUNK
) ? RANDOM_FIRE
: RANDOM_HIT
;
990 case RANDOM_HIT
: /* last shot was random and hit */
991 used
[E
/ 2] = used
[S
/ 2] = used
[W
/ 2] = used
[N
/ 2] = FALSE
;
994 case HUNT_DIRECT
: /* last shot hit, we're looking for ship's long axis */
995 for (d
= navail
= 0; d
< 4; d
++) {
996 x
= ts
.x
+ xincr
[d
* 2];
997 y
= ts
.y
+ yincr
[d
* 2];
998 if (!used
[d
] && POSSIBLE(x
, y
))
1003 if (navail
== 0) /* no valid places for shots adjacent... */
1004 goto refire
; /* ...so we must random-fire */
1006 for (d
= 0, n
= rnd(navail
) + 1; n
; n
--)
1013 x
= ts
.x
+ xincr
[d
* 2];
1014 y
= ts
.y
+ yincr
[d
* 2];
1016 assert(POSSIBLE(x
, y
));
1018 if (!(hit
= cpufire(x
, y
)))
1025 next
= (hit
== S_SUNK
) ? RANDOM_FIRE
: FIRST_PASS
;
1030 case FIRST_PASS
: /* we have a start and a direction now */
1031 x
= ts
.x
+ xincr
[ts
.dir
];
1032 y
= ts
.y
+ yincr
[ts
.dir
];
1033 if (POSSIBLE(x
, y
) && (hit
= cpufire(x
, y
))) {
1037 next
= (hit
== S_SUNK
) ? RANDOM_FIRE
: FIRST_PASS
;
1039 next
= REVERSE_JUMP
;
1042 case REVERSE_JUMP
: /* nail down the ship's other end */
1044 x
= ts
.x
+ ts
.hits
* xincr
[d
];
1045 y
= ts
.y
+ ts
.hits
* yincr
[d
];
1046 if (POSSIBLE(x
, y
) && (hit
= cpufire(x
, y
))) {
1051 next
= (hit
== S_SUNK
) ? RANDOM_FIRE
: SECOND_PASS
;
1056 case SECOND_PASS
: /* kill squares not caught on first pass */
1057 x
= ts
.x
+ xincr
[ts
.dir
];
1058 y
= ts
.y
+ yincr
[ts
.dir
];
1059 if (POSSIBLE(x
, y
) && (hit
= cpufire(x
, y
))) {
1063 next
= (hit
== S_SUNK
) ? RANDOM_FIRE
: SECOND_PASS
;
1070 /* check for continuation and/or winner */
1079 (void) mvprintw(PROMPTLINE
+ 2, 0,
1080 "New state %d, x=%d, y=%d, d=%d",
1083 return ((hit
) ? TRUE
: FALSE
);
1092 for (ss
= cpuship
; ss
< cpuship
+ SHIPTYPES
; ss
++)
1093 for (j
= 0; j
< ss
->length
; j
++) {
1094 cgoto(ss
->y
+ j
* yincr
[ss
->dir
], ss
->x
+ j
* xincr
[ss
->dir
]);
1095 (void) addch((chtype
) ss
->symbol
);
1102 j
= 18 + strlen(name
);
1107 (void) mvprintw(1, (COLWIDTH
- j
) / 2,
1108 "%s: %d Computer: %d", name
, plywon
, cpuwon
);
1110 prompt(2, (awinna())? "Want to be humiliated again, %s [yn]? "
1111 : "Going to give me a chance for revenge, %s [yn]? ", name
);
1112 return (sgetc("YN") == 'Y');
1116 do_options(int c
, char *op
[])
1121 for (i
= 1; i
< c
; i
++) {
1125 (void) fprintf(stderr
, "Usage: battle [-s | -b] [-c]\n");
1126 (void) fprintf(stderr
, "\tWhere the options are:\n");
1127 (void) fprintf(stderr
, "\t-s : play a salvo game\n");
1128 (void) fprintf(stderr
, "\t-b : play a blitz game\n");
1129 (void) fprintf(stderr
, "\t-c : ships may be adjacent\n");
1130 ExitProgram(EXIT_FAILURE
);
1137 (void) fprintf(stderr
,
1138 "Bad Arg: -b and -s are mutually exclusive\n");
1139 ExitProgram(EXIT_FAILURE
);
1145 (void) fprintf(stderr
,
1146 "Bad Arg: -s and -b are mutually exclusive\n");
1147 ExitProgram(EXIT_FAILURE
);
1154 (void) fprintf(stderr
,
1155 "Bad arg: type \"%s ?\" for usage message\n",
1157 ExitProgram(EXIT_FAILURE
);
1167 register int i
, shots
;
1168 register ship_t
*sp
;
1171 sp
= cpuship
; /* count cpu shots */
1173 sp
= plyship
; /* count player shots */
1175 for (i
= 0, shots
= 0; i
< SHIPTYPES
; i
++, sp
++) {
1176 if (sp
->hits
>= sp
->length
)
1177 continue; /* dead ship */
1185 main(int argc
, char *argv
[])
1187 setlocale(LC_ALL
, "");
1189 do_options(argc
, argv
);
1194 while (awinna() == -1) {
1207 if (cputurn() && awinna() != -1)
1210 if (plyturn() && awinna() != -1)
1216 while (turn
? cputurn() : plyturn())
1226 /* bs.c ends here */