xref: /openbsd-src/games/wump/wump.c (revision 6106ce73d60968add179949ec4fdf000d95bed55)
1*6106ce73Sschwarze /*	$OpenBSD: wump.c,v 1.34 2018/12/20 09:55:44 schwarze Exp $	*/
2df930be7Sderaadt 
3df930be7Sderaadt /*
4df930be7Sderaadt  * Copyright (c) 1989, 1993
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  * All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Dave Taylor, of Intuitive Systems.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
197a09557bSmillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36df930be7Sderaadt /*
3725154944Spjanzen  * A no longer new version of the age-old favorite Hunt-The-Wumpus game that
3825154944Spjanzen  * has been a part of the BSD distribution for longer than us old folk
39df930be7Sderaadt  * would care to remember.
40df930be7Sderaadt  */
41df930be7Sderaadt 
4296b46b10Spjanzen #include <sys/wait.h>
439ea8ec70Smestre 
4496b46b10Spjanzen #include <err.h>
4501a83688Smillert #include <fcntl.h>
4696b46b10Spjanzen #include <paths.h>
47df930be7Sderaadt #include <stdio.h>
4840c957bfSderaadt #include <stdlib.h>
49df930be7Sderaadt #include <string.h>
5040c957bfSderaadt #include <unistd.h>
519ea8ec70Smestre 
52df930be7Sderaadt #include "pathnames.h"
53df930be7Sderaadt 
54df930be7Sderaadt /* some defines to spec out what our wumpus cave should look like */
55df930be7Sderaadt 
5640c957bfSderaadt /* #define	MAX_ARROW_SHOT_DISTANCE	6	*/	/* +1 for '0' stopper */
57df930be7Sderaadt #define	MAX_LINKS_IN_ROOM	25		/* a complex cave */
58df930be7Sderaadt 
59df930be7Sderaadt #define	MAX_ROOMS_IN_CAVE	250
60df930be7Sderaadt #define	ROOMS_IN_CAVE		20
61df930be7Sderaadt #define	MIN_ROOMS_IN_CAVE	10
62df930be7Sderaadt 
63df930be7Sderaadt #define	LINKS_IN_ROOM		3
64df930be7Sderaadt #define	NUMBER_OF_ARROWS	5
65df930be7Sderaadt #define	PIT_COUNT		3
66df930be7Sderaadt #define	BAT_COUNT		3
67df930be7Sderaadt 
68df930be7Sderaadt #define	EASY			1		/* levels of play */
69df930be7Sderaadt #define	HARD			2
70df930be7Sderaadt 
71df930be7Sderaadt /* some macro definitions for cleaner output */
72df930be7Sderaadt 
73df930be7Sderaadt #define	plural(n)	(n == 1 ? "" : "s")
74df930be7Sderaadt 
75df930be7Sderaadt /* simple cave data structure; +1 so we can index from '1' not '0' */
76df930be7Sderaadt struct room_record {
77df930be7Sderaadt 	int tunnel[MAX_LINKS_IN_ROOM];
78df930be7Sderaadt 	int has_a_pit, has_a_bat;
79df930be7Sderaadt } cave[MAX_ROOMS_IN_CAVE+1];
80df930be7Sderaadt 
81df930be7Sderaadt /*
82df930be7Sderaadt  * global variables so we can keep track of where the player is, how
83df930be7Sderaadt  * many arrows they still have, where el wumpo is, and so on...
84df930be7Sderaadt  */
85df930be7Sderaadt int player_loc = -1;			/* player location */
86df930be7Sderaadt int wumpus_loc = -1;			/* The Bad Guy location */
87df930be7Sderaadt int level = EASY;			/* level of play */
88df930be7Sderaadt int arrows_left;			/* arrows unshot */
89077eda3bSpjanzen int oldstyle = 0;			/* dodecahedral cave? */
90df930be7Sderaadt 
91df930be7Sderaadt #ifdef DEBUG
92df930be7Sderaadt int debug = 0;
93df930be7Sderaadt #endif
94df930be7Sderaadt 
95077eda3bSpjanzen int pit_num = -1;		/* # pits in cave */
96077eda3bSpjanzen int bat_num = -1;		/* # bats */
97df930be7Sderaadt int room_num = ROOMS_IN_CAVE;		/* # rooms in cave */
98df930be7Sderaadt int link_num = LINKS_IN_ROOM;		/* links per room  */
99df930be7Sderaadt int arrow_num = NUMBER_OF_ARROWS;	/* arrow inventory */
100df930be7Sderaadt 
101df930be7Sderaadt char answer[20];			/* user input */
102df930be7Sderaadt 
103c72b5b24Smillert int	bats_nearby(void);
104c72b5b24Smillert void	cave_init(void);
105c72b5b24Smillert void	clear_things_in_cave(void);
106c72b5b24Smillert void	display_room_stats(void);
107c72b5b24Smillert void	dodecahedral_cave_init(void);
108c72b5b24Smillert int	gcd(int, int);
109c72b5b24Smillert int	getans(const char *);
110c72b5b24Smillert void	initialize_things_in_cave(void);
111c72b5b24Smillert void	instructions(void);
112c72b5b24Smillert int	int_compare(const void *, const void *);
113c72b5b24Smillert /* void	jump(int); */
114c72b5b24Smillert void	kill_wump(void);
115c72b5b24Smillert int	main(int, char **);
116c72b5b24Smillert int	move_to(const char *);
117c72b5b24Smillert void	move_wump(void);
118c72b5b24Smillert void	no_arrows(void);
119c72b5b24Smillert void	pit_kill(void);
120c72b5b24Smillert void	pit_kill_bat(void);
121c72b5b24Smillert int	pit_nearby(void);
122c72b5b24Smillert void	pit_survive(void);
123c72b5b24Smillert int	shoot(char *);
124c72b5b24Smillert void	shoot_self(void);
125c72b5b24Smillert int	take_action(void);
126f0628b46Smestre __dead void	usage(void);
127c72b5b24Smillert void	wump_kill(void);
128c72b5b24Smillert void	wump_bat_kill(void);
129c72b5b24Smillert void	wump_walk_kill(void);
130c72b5b24Smillert int	wump_nearby(void);
13140c957bfSderaadt 
13240c957bfSderaadt 
13340c957bfSderaadt int
main(int argc,char * argv[])134ff8320a7Sderaadt main(int argc, char *argv[])
135df930be7Sderaadt {
136df930be7Sderaadt 	int c;
137df930be7Sderaadt 
13856e43436Stb 	if (pledge("stdio rpath proc exec", NULL) == -1)
13956e43436Stb 		err(1, "pledge");
14056e43436Stb 
141df930be7Sderaadt #ifdef DEBUG
142077eda3bSpjanzen 	while ((c = getopt(argc, argv, "a:b:hop:r:t:d")) != -1)
143df930be7Sderaadt #else
144077eda3bSpjanzen 	while ((c = getopt(argc, argv, "a:b:hop:r:t:")) != -1)
145df930be7Sderaadt #endif
146df930be7Sderaadt 		switch (c) {
147df930be7Sderaadt 		case 'a':
148df930be7Sderaadt 			arrow_num = atoi(optarg);
149df930be7Sderaadt 			break;
150df930be7Sderaadt 		case 'b':
151df930be7Sderaadt 			bat_num = atoi(optarg);
152df930be7Sderaadt 			break;
153df930be7Sderaadt #ifdef DEBUG
154df930be7Sderaadt 		case 'd':
155df930be7Sderaadt 			debug = 1;
156df930be7Sderaadt 			break;
157df930be7Sderaadt #endif
158df930be7Sderaadt 		case 'h':
159df930be7Sderaadt 			level = HARD;
160df930be7Sderaadt 			break;
161077eda3bSpjanzen 		case 'o':
162077eda3bSpjanzen 			oldstyle = 1;
163077eda3bSpjanzen 			break;
164df930be7Sderaadt 		case 'p':
165df930be7Sderaadt 			pit_num = atoi(optarg);
166df930be7Sderaadt 			break;
167df930be7Sderaadt 		case 'r':
168df930be7Sderaadt 			room_num = atoi(optarg);
169077eda3bSpjanzen 			if (room_num < MIN_ROOMS_IN_CAVE)
170077eda3bSpjanzen 				errx(1,
171077eda3bSpjanzen 	"no self-respecting wumpus would live in such a small cave!");
172077eda3bSpjanzen 			if (room_num > MAX_ROOMS_IN_CAVE)
173077eda3bSpjanzen 				errx(1,
174077eda3bSpjanzen 	"even wumpii can't furnish caves that large!");
175df930be7Sderaadt 			break;
176df930be7Sderaadt 		case 't':
177df930be7Sderaadt 			link_num = atoi(optarg);
178077eda3bSpjanzen 			if (link_num < 2)
179077eda3bSpjanzen 				errx(1,
180077eda3bSpjanzen 	"wumpii like extra doors in their caves!");
181df930be7Sderaadt 			break;
182df930be7Sderaadt 		default:
183df930be7Sderaadt 			usage();
184df930be7Sderaadt 	}
185df930be7Sderaadt 
186077eda3bSpjanzen 	if (oldstyle) {
187077eda3bSpjanzen 		room_num = 20;
188077eda3bSpjanzen 		link_num = 3;
189077eda3bSpjanzen 		/* Original game had exactly 2 bats and 2 pits */
190077eda3bSpjanzen 		if (bat_num < 0)
191077eda3bSpjanzen 			bat_num = 2;
192077eda3bSpjanzen 		if (pit_num < 0)
193077eda3bSpjanzen 			pit_num = 2;
194077eda3bSpjanzen 	} else {
195077eda3bSpjanzen 		if (bat_num < 0)
196077eda3bSpjanzen 			bat_num = BAT_COUNT;
197077eda3bSpjanzen 		if (pit_num < 0)
198077eda3bSpjanzen 			pit_num = PIT_COUNT;
199df930be7Sderaadt 	}
200df930be7Sderaadt 
201077eda3bSpjanzen 	if (link_num > MAX_LINKS_IN_ROOM ||
202077eda3bSpjanzen 	    link_num > room_num - (room_num / 4))
203077eda3bSpjanzen 		errx(1,
204077eda3bSpjanzen "too many tunnels!  The cave collapsed!\n(Fortunately, the wumpus escaped!)");
205077eda3bSpjanzen 
206df930be7Sderaadt 	if (level == HARD) {
20740c957bfSderaadt 		if (room_num / 2 - bat_num)
20866e49541Snaddy 			bat_num += arc4random_uniform(room_num / 2 - bat_num);
20940c957bfSderaadt 		if (room_num / 2 - pit_num)
21066e49541Snaddy 			pit_num += arc4random_uniform(room_num / 2 - pit_num);
211df930be7Sderaadt 	}
212df930be7Sderaadt 
21340c957bfSderaadt 	/* Leave at least two rooms free--one for the player to start in, and
21440c957bfSderaadt 	 * potentially one for the wumpus.
21540c957bfSderaadt 	 */
216077eda3bSpjanzen 	if (bat_num > room_num / 2 - 1)
217077eda3bSpjanzen 		errx(1,
218077eda3bSpjanzen "the wumpus refused to enter the cave, claiming it was too crowded!");
219df930be7Sderaadt 
220077eda3bSpjanzen 	if (pit_num > room_num / 2 - 1)
221077eda3bSpjanzen 		errx(1,
222077eda3bSpjanzen "the wumpus refused to enter the cave, claiming it was too dangerous!");
223df930be7Sderaadt 
224df930be7Sderaadt 	instructions();
22556e43436Stb 
22656e43436Stb 	if (pledge("stdio", NULL) == -1)
22756e43436Stb 		err(1, "pledge");
22856e43436Stb 
229077eda3bSpjanzen 	if (oldstyle)
230077eda3bSpjanzen 		dodecahedral_cave_init();
231077eda3bSpjanzen 	else
232df930be7Sderaadt 		cave_init();
233df930be7Sderaadt 
234df930be7Sderaadt 	/* and we're OFF!  da dum, da dum, da dum, da dum... */
235df930be7Sderaadt 	(void)printf(
236df930be7Sderaadt "\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
237df930be7Sderaadt There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
238df930be7Sderaadt quiver holds %d custom super anti-evil Wumpus arrows.  Good luck.\n",
239df930be7Sderaadt 	    room_num, link_num, bat_num, plural(bat_num), pit_num,
240df930be7Sderaadt 	    plural(pit_num), arrow_num);
241df930be7Sderaadt 
242df930be7Sderaadt 	for (;;) {
243df930be7Sderaadt 		initialize_things_in_cave();
244df930be7Sderaadt 		arrows_left = arrow_num;
245df930be7Sderaadt 		do {
246df930be7Sderaadt 			display_room_stats();
247df930be7Sderaadt 			(void)printf("Move or shoot? (m-s) ");
248df930be7Sderaadt 			(void)fflush(stdout);
24940c957bfSderaadt 			(void)fpurge(stdin);
250df930be7Sderaadt 			if (!fgets(answer, sizeof(answer), stdin))
251df930be7Sderaadt 				break;
252df930be7Sderaadt 		} while (!take_action());
25340c957bfSderaadt 		(void)fpurge(stdin);
254df930be7Sderaadt 
25596b46b10Spjanzen 		if (!getans("\nCare to play another game? (y-n) ")) {
25696b46b10Spjanzen 			(void)printf("\n");
25717641e31Stb 			return 0;
25896b46b10Spjanzen 		}
259df930be7Sderaadt 		clear_things_in_cave();
260077eda3bSpjanzen 		if (!getans("In the same cave? (y-n) ")) {
261077eda3bSpjanzen 			if (oldstyle)
262077eda3bSpjanzen 				dodecahedral_cave_init();
263077eda3bSpjanzen 			else
264df930be7Sderaadt 				cave_init();
265df930be7Sderaadt 		}
266077eda3bSpjanzen 	}
267df930be7Sderaadt }
268df930be7Sderaadt 
26940c957bfSderaadt void
display_room_stats(void)270ff8320a7Sderaadt display_room_stats(void)
271df930be7Sderaadt {
2727faebae9Spjanzen 	int i;
273df930be7Sderaadt 
274df930be7Sderaadt 	/*
275df930be7Sderaadt 	 * Routine will explain what's going on with the current room, as well
276df930be7Sderaadt 	 * as describe whether there are pits, bats, & wumpii nearby.  It's
277df930be7Sderaadt 	 * all pretty mindless, really.
278df930be7Sderaadt 	 */
279df930be7Sderaadt 	(void)printf(
280df930be7Sderaadt "\nYou are in room %d of the cave, and have %d arrow%s left.\n",
281df930be7Sderaadt 	    player_loc, arrows_left, plural(arrows_left));
282df930be7Sderaadt 
283df930be7Sderaadt 	if (bats_nearby())
284df930be7Sderaadt 		(void)printf("*rustle* *rustle* (must be bats nearby)\n");
285df930be7Sderaadt 	if (pit_nearby())
286df930be7Sderaadt 		(void)printf("*whoosh* (I feel a draft from some pits).\n");
287df930be7Sderaadt 	if (wump_nearby())
288df930be7Sderaadt 		(void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
289df930be7Sderaadt 
290df930be7Sderaadt 	(void)printf("There are tunnels to rooms %d, ",
291df930be7Sderaadt 	   cave[player_loc].tunnel[0]);
292df930be7Sderaadt 
293df930be7Sderaadt 	for (i = 1; i < link_num - 1; i++)
29440c957bfSderaadt /*		if (cave[player_loc].tunnel[i] <= room_num) */
295df930be7Sderaadt 			(void)printf("%d, ", cave[player_loc].tunnel[i]);
296df930be7Sderaadt 	(void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
297df930be7Sderaadt }
298df930be7Sderaadt 
29940c957bfSderaadt int
take_action(void)300ff8320a7Sderaadt take_action(void)
301df930be7Sderaadt {
302df930be7Sderaadt 	/*
303df930be7Sderaadt 	 * Do the action specified by the player, either 'm'ove, 's'hoot
304df930be7Sderaadt 	 * or something exceptionally bizarre and strange!  Returns 1
305df930be7Sderaadt 	 * iff the player died during this turn, otherwise returns 0.
306df930be7Sderaadt 	 */
307df930be7Sderaadt 	switch (*answer) {
308df930be7Sderaadt 		case 'M':
309df930be7Sderaadt 		case 'm':			/* move */
310df930be7Sderaadt 			return(move_to(answer + 1));
311df930be7Sderaadt 		case 'S':
312df930be7Sderaadt 		case 's':			/* shoot */
313df930be7Sderaadt 			return(shoot(answer + 1));
314df930be7Sderaadt 		case 'Q':
315df930be7Sderaadt 		case 'q':
316df930be7Sderaadt 		case 'x':
317df930be7Sderaadt 			exit(0);
318df930be7Sderaadt 		case '\n':
319df930be7Sderaadt 			return(0);
320df930be7Sderaadt 		}
32166e49541Snaddy 	if (arc4random_uniform(15) == 1)
322df930be7Sderaadt 		(void)printf("Que pasa?\n");
323df930be7Sderaadt 	else
324df930be7Sderaadt 		(void)printf("I don't understand!\n");
325df930be7Sderaadt 	return(0);
326df930be7Sderaadt }
327df930be7Sderaadt 
32840c957bfSderaadt int
move_to(const char * room_number)329ff8320a7Sderaadt move_to(const char *room_number)
330df930be7Sderaadt {
331df930be7Sderaadt 	int i, just_moved_by_bats, next_room, tunnel_available;
332df930be7Sderaadt 
333df930be7Sderaadt 	/*
334df930be7Sderaadt 	 * This is responsible for moving the player into another room in the
335df930be7Sderaadt 	 * cave as per their directions.  If room_number is a null string,
336df930be7Sderaadt 	 * then we'll prompt the user for the next room to go into.   Once
337df930be7Sderaadt 	 * we've moved into the room, we'll check for things like bats, pits,
338df930be7Sderaadt 	 * and so on.  This routine returns 1 if something occurs that kills
339df930be7Sderaadt 	 * the player and 0 otherwise...
340df930be7Sderaadt 	 */
341df930be7Sderaadt 	tunnel_available = just_moved_by_bats = 0;
342df930be7Sderaadt 	next_room = atoi(room_number);
343df930be7Sderaadt 
344df930be7Sderaadt 	/* crap for magic tunnels */
34540c957bfSderaadt /*	if (next_room == room_num + 1 &&
34640c957bfSderaadt  *	    cave[player_loc].tunnel[link_num-1] != next_room)
34740c957bfSderaadt  *		++next_room;
34840c957bfSderaadt  */
34940c957bfSderaadt 	while (next_room < 1 || next_room > room_num /* + 1 */) {
350df930be7Sderaadt 		if (next_room < 0 && next_room != -1)
351df930be7Sderaadt (void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
35240c957bfSderaadt 		if (next_room > room_num /* + 1 */)
353df930be7Sderaadt (void)printf("What?  The cave surely isn't quite that big!\n");
35440c957bfSderaadt /*		if (next_room == room_num + 1 &&
35540c957bfSderaadt  *		    cave[player_loc].tunnel[link_num-1] != next_room) {
35640c957bfSderaadt  *			(void)printf("What?  The cave isn't that big!\n");
35740c957bfSderaadt  *			++next_room;
35840c957bfSderaadt  *		}
35940c957bfSderaadt  */		(void)printf("To which room do you wish to move? ");
360df930be7Sderaadt 		(void)fflush(stdout);
361df930be7Sderaadt 		if (!fgets(answer, sizeof(answer), stdin))
362df930be7Sderaadt 			return(1);
363df930be7Sderaadt 		next_room = atoi(answer);
364df930be7Sderaadt 	}
365df930be7Sderaadt 
366df930be7Sderaadt 	/* now let's see if we can move to that room or not */
367df930be7Sderaadt 	tunnel_available = 0;
368df930be7Sderaadt 	for (i = 0; i < link_num; i++)
369df930be7Sderaadt 		if (cave[player_loc].tunnel[i] == next_room)
370df930be7Sderaadt 			tunnel_available = 1;
371df930be7Sderaadt 
372df930be7Sderaadt 	if (!tunnel_available) {
373df930be7Sderaadt 		(void)printf("*Oof!*  (You hit the wall)\n");
37466e49541Snaddy 		if (arc4random_uniform(6) == 1) {
375df930be7Sderaadt (void)printf("Your colorful comments awaken the wumpus!\n");
376df930be7Sderaadt 			move_wump();
377df930be7Sderaadt 			if (wumpus_loc == player_loc) {
37840c957bfSderaadt 				wump_walk_kill();
379df930be7Sderaadt 				return(1);
380df930be7Sderaadt 			}
381df930be7Sderaadt 		}
382df930be7Sderaadt 		return(0);
383df930be7Sderaadt 	}
384df930be7Sderaadt 
385df930be7Sderaadt 	/* now let's move into that room and check it out for dangers */
38640c957bfSderaadt /*	if (next_room == room_num + 1)
38766e49541Snaddy  *		jump(next_room = arc4random_uniform(room_num) + 1);
38840c957bfSderaadt  */
389df930be7Sderaadt 	player_loc = next_room;
390df930be7Sderaadt 	for (;;) {
391df930be7Sderaadt 		if (next_room == wumpus_loc) {		/* uh oh... */
39240c957bfSderaadt 			if (just_moved_by_bats)
39340c957bfSderaadt 				wump_bat_kill();
39440c957bfSderaadt 			else
395df930be7Sderaadt 				wump_kill();
396df930be7Sderaadt 			return(1);
397df930be7Sderaadt 		}
3981ed0e75dSpjanzen 		if (cave[next_room].has_a_pit) {
39966e49541Snaddy 			if (arc4random_uniform(12) < 2) {
400df930be7Sderaadt 				pit_survive();
401df930be7Sderaadt 				return(0);
402df930be7Sderaadt 			} else {
40340c957bfSderaadt 				if (just_moved_by_bats)
40440c957bfSderaadt 					pit_kill_bat();
40540c957bfSderaadt 				else
406df930be7Sderaadt 					pit_kill();
407df930be7Sderaadt 				return(1);
408df930be7Sderaadt 			}
4091ed0e75dSpjanzen 		}
410df930be7Sderaadt 
411df930be7Sderaadt 		if (cave[next_room].has_a_bat) {
412df930be7Sderaadt 			(void)printf(
413df930be7Sderaadt "*flap*  *flap*  *flap*  (humongous bats pick you up and move you%s!)\n",
414df930be7Sderaadt 			    just_moved_by_bats ? " again": "");
41566e49541Snaddy 			next_room = player_loc =
41666e49541Snaddy 			    arc4random_uniform(room_num) + 1;
417df930be7Sderaadt 			just_moved_by_bats = 1;
418df930be7Sderaadt 		}
419df930be7Sderaadt 
420df930be7Sderaadt 		else
421df930be7Sderaadt 			break;
422df930be7Sderaadt 	}
423df930be7Sderaadt 	return(0);
424df930be7Sderaadt }
425df930be7Sderaadt 
42640c957bfSderaadt int
shoot(char * room_list)42725154944Spjanzen shoot(char *room_list)
428df930be7Sderaadt {
429df930be7Sderaadt 	int chance, next, roomcnt;
430df930be7Sderaadt 	int j, arrow_location, link, ok;
43140c957bfSderaadt 	char *p;
432df930be7Sderaadt 
433df930be7Sderaadt 	/*
434df930be7Sderaadt 	 * Implement shooting arrows.  Arrows are shot by the player indicating
435df930be7Sderaadt 	 * a space-separated list of rooms that the arrow should pass through;
436df930be7Sderaadt 	 * if any of the rooms they specify are not accessible via tunnel from
437df930be7Sderaadt 	 * the room the arrow is in, it will instead fly randomly into another
438df930be7Sderaadt 	 * room.  If the player hits the wumpus, this routine will indicate
43940c957bfSderaadt 	 * such.  If it misses, this routine may *move* the wumpus one room.
44040c957bfSderaadt 	 * If it's the last arrow, then the player dies...  Returns 1 if the
441df930be7Sderaadt 	 * player has won or died, 0 if nothing has happened.
442df930be7Sderaadt 	 */
443df930be7Sderaadt 	arrow_location = player_loc;
444df930be7Sderaadt 	for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
4451ed0e75dSpjanzen 		if (!(p = strtok(room_list, " \t\n"))) {
446df930be7Sderaadt 			if (roomcnt == 1) {
44740c957bfSderaadt 				(void)printf("Enter a list of rooms to shoot into:\n");
44840c957bfSderaadt 				(void)fflush(stdout);
44940c957bfSderaadt 				if (!(p = strtok(fgets(answer, sizeof(answer), stdin),
45040c957bfSderaadt 							" \t\n"))) {
451df930be7Sderaadt 					(void)printf(
45240c957bfSderaadt 				"The arrow falls to the ground at your feet.\n");
453df930be7Sderaadt 					return(0);
45440c957bfSderaadt 					}
455df930be7Sderaadt 			} else
456df930be7Sderaadt 				break;
4571ed0e75dSpjanzen 		}
458df930be7Sderaadt 		if (roomcnt > 5) {
459df930be7Sderaadt 			(void)printf(
4607a333710Sdavid "The arrow wavers in its flight and can go no further than room %d!\n",
46140c957bfSderaadt 					arrow_location);
462df930be7Sderaadt 			break;
463df930be7Sderaadt 		}
46440c957bfSderaadt 
465df930be7Sderaadt 		next = atoi(p);
46640c957bfSderaadt 		if (next == 0)
46740c957bfSderaadt 			break;	/* Old wumpus used room 0 as the terminator */
46840c957bfSderaadt 
46966e49541Snaddy 		chance = arc4random_uniform(10);
47040c957bfSderaadt 		if (roomcnt == 4 && chance < 2) {
47140c957bfSderaadt 			(void)printf(
47240c957bfSderaadt "Your finger slips on the bowstring!  *twaaaaaang*\n\
47340c957bfSderaadt The arrow is weakly shot and can go no further than room %d!\n",arrow_location);
47440c957bfSderaadt 			break;
47540c957bfSderaadt 		} else if (roomcnt == 5 && chance < 6) {
47640c957bfSderaadt 			(void)printf(
4777a333710Sdavid "The arrow wavers in its flight and can go no further than room %d!\n",
47840c957bfSderaadt 					arrow_location);
47940c957bfSderaadt 			break;
48040c957bfSderaadt 		}
48140c957bfSderaadt 
482df930be7Sderaadt 		for (j = 0, ok = 0; j < link_num; j++)
483df930be7Sderaadt 			if (cave[arrow_location].tunnel[j] == next)
484df930be7Sderaadt 				ok = 1;
485df930be7Sderaadt 
486df930be7Sderaadt 		if (ok) {
48740c957bfSderaadt /*			if (next > room_num) {
48840c957bfSderaadt  *				(void)printf(
48940c957bfSderaadt  * "A faint gleam tells you the arrow has gone through a magic tunnel!\n");
49066e49541Snaddy  *				arrow_location =
49166e49541Snaddy  *				    arc4random_uniform(room_num) + 1;
49240c957bfSderaadt  *			} else
49340c957bfSderaadt  */				arrow_location = next;
494df930be7Sderaadt 		} else {
49566e49541Snaddy 			link = (arc4random_uniform(link_num));
49640c957bfSderaadt 			if (cave[arrow_location].tunnel[link] == player_loc)
497df930be7Sderaadt 				(void)printf(
49840c957bfSderaadt "*thunk*  The arrow can't find a way from %d to %d and flies back into\n\
499df930be7Sderaadt your room!\n",
500df930be7Sderaadt 				    arrow_location, next);
50140c957bfSderaadt /*			else if (cave[arrow_location].tunnel[link] > room_num)
50240c957bfSderaadt  *				(void)printf(
50340c957bfSderaadt  *"*thunk*  The arrow flies randomly into a magic tunnel, thence into\n\
50440c957bfSderaadt  *room %d!\n",
50540c957bfSderaadt  *				    cave[arrow_location].tunnel[link]);
50640c957bfSderaadt  */			else
507df930be7Sderaadt 				(void)printf(
50840c957bfSderaadt "*thunk*  The arrow can't find a way from %d to %d and flies randomly\n\
50940c957bfSderaadt into room %d!\n", arrow_location, next, cave[arrow_location].tunnel[link]);
51040c957bfSderaadt 
511df930be7Sderaadt 			arrow_location = cave[arrow_location].tunnel[link];
512df930be7Sderaadt 		}
513df930be7Sderaadt 
514df930be7Sderaadt 		/*
515df930be7Sderaadt 		 * now we've gotten into the new room let us see if El Wumpo is
516df930be7Sderaadt 		 * in the same room ... if so we've a HIT and the player WON!
517df930be7Sderaadt 		 */
518df930be7Sderaadt 		if (arrow_location == wumpus_loc) {
519df930be7Sderaadt 			kill_wump();
520df930be7Sderaadt 			return(1);
521df930be7Sderaadt 		}
522df930be7Sderaadt 
523df930be7Sderaadt 		if (arrow_location == player_loc) {
524df930be7Sderaadt 			shoot_self();
525df930be7Sderaadt 			return(1);
526df930be7Sderaadt 		}
52740c957bfSderaadt 	}
528df930be7Sderaadt 
529df930be7Sderaadt 	if (!--arrows_left) {
530df930be7Sderaadt 		no_arrows();
531df930be7Sderaadt 		return(1);
532df930be7Sderaadt 	}
533df930be7Sderaadt 
534df930be7Sderaadt 	{
535df930be7Sderaadt 		/* each time you shoot, it's more likely the wumpus moves */
536df930be7Sderaadt 		static int lastchance = 2;
537df930be7Sderaadt 
538*6106ce73Sschwarze 		lastchance += 2;
539*6106ce73Sschwarze 		if (arc4random_uniform(level == EASY ? 12 : 9) < lastchance) {
540df930be7Sderaadt 			move_wump();
54140c957bfSderaadt 			if (wumpus_loc == player_loc) {
54240c957bfSderaadt 				wump_walk_kill();
54366e49541Snaddy 				/* Reset for next game */
54466e49541Snaddy 				lastchance = arc4random_uniform(3);
54540c957bfSderaadt 				return(1);
54640c957bfSderaadt 			}
547df930be7Sderaadt 
548df930be7Sderaadt 		}
549df930be7Sderaadt 	}
55040c957bfSderaadt 	(void)printf("The arrow hit nothing.\n");
551df930be7Sderaadt 	return(0);
552df930be7Sderaadt }
553df930be7Sderaadt 
55441102c1dSpjanzen int
gcd(int a,int b)55525154944Spjanzen gcd(int a, int b)
55641102c1dSpjanzen {
55741102c1dSpjanzen 	int r;
55841102c1dSpjanzen 
55941102c1dSpjanzen 	if (!(r = (a % b)))
56041102c1dSpjanzen 		return(b);
56141102c1dSpjanzen 	return(gcd(b, r));
56241102c1dSpjanzen }
56341102c1dSpjanzen 
56440c957bfSderaadt void
cave_init(void)565ff8320a7Sderaadt cave_init(void)
566df930be7Sderaadt {
5677faebae9Spjanzen 	int i, j, k, link;
5687faebae9Spjanzen 	int delta;
569df930be7Sderaadt 
570df930be7Sderaadt 	/*
571df930be7Sderaadt 	 * This does most of the interesting work in this program actually!
572df930be7Sderaadt 	 * In this routine we'll initialize the Wumpus cave to have all rooms
573df930be7Sderaadt 	 * linking to all others by stepping through our data structure once,
574df930be7Sderaadt 	 * recording all forward links and backwards links too.  The parallel
575df930be7Sderaadt 	 * "linkcount" data structure ensures that no room ends up with more
576df930be7Sderaadt 	 * than three links, regardless of the quality of the random number
577df930be7Sderaadt 	 * generator that we're using.
578df930be7Sderaadt 	 */
57940c957bfSderaadt 
58040c957bfSderaadt 	/* Note that throughout the source there are commented-out vestigial
58140c957bfSderaadt 	 * remains of the 'magic tunnel', which was a tunnel to room
58240c957bfSderaadt 	 * room_num +1.  It was necessary if all paths were two-way and
58340c957bfSderaadt 	 * there was an odd number of rooms, each with an odd number of
58440c957bfSderaadt 	 * exits.  It's being kept in case cave_init ever gets reworked into
58540c957bfSderaadt 	 * something more traditional.
58640c957bfSderaadt 	 */
587df930be7Sderaadt 
588df930be7Sderaadt 	/* initialize the cave first off. */
589df930be7Sderaadt 	for (i = 1; i <= room_num; ++i)
590df930be7Sderaadt 		for (j = 0; j < link_num ; ++j)
591df930be7Sderaadt 			cave[i].tunnel[j] = -1;
592df930be7Sderaadt 
59341102c1dSpjanzen 	/* choose a random 'hop' delta for our guaranteed link.
59441102c1dSpjanzen 	 * To keep the cave connected, require greatest common
59541102c1dSpjanzen 	 * divisor of (delta + 1) and room_num to be 1
59641102c1dSpjanzen 	 */
59741102c1dSpjanzen 	do {
59866e49541Snaddy 		delta = arc4random_uniform(room_num - 1) + 1;
59941102c1dSpjanzen 	} while (gcd(room_num, delta + 1) != 1);
600df930be7Sderaadt 
601df930be7Sderaadt 	for (i = 1; i <= room_num; ++i) {
602df930be7Sderaadt 		link = ((i + delta) % room_num) + 1;	/* connection */
603df930be7Sderaadt 		cave[i].tunnel[0] = link;		/* forw link */
604df930be7Sderaadt 		cave[link].tunnel[1] = i;		/* back link */
605df930be7Sderaadt 	}
60640c957bfSderaadt 	/* now fill in the rest of the cave with random connections.
60740c957bfSderaadt 	 * This is a departure from historical versions of wumpus.
60840c957bfSderaadt 	 */
609df930be7Sderaadt 	for (i = 1; i <= room_num; i++)
610df930be7Sderaadt 		for (j = 2; j < link_num ; j++) {
611df930be7Sderaadt 			if (cave[i].tunnel[j] != -1)
612df930be7Sderaadt 				continue;
61366e49541Snaddy try_again:		link = arc4random_uniform(room_num) + 1;
614df930be7Sderaadt 			/* skip duplicates */
615df930be7Sderaadt 			for (k = 0; k < j; k++)
616df930be7Sderaadt 				if (cave[i].tunnel[k] == link)
617df930be7Sderaadt 					goto try_again;
61840c957bfSderaadt 			/* don't let a room connect to itself */
61940c957bfSderaadt 			if (link == i)
62040c957bfSderaadt 				goto try_again;
621df930be7Sderaadt 			cave[i].tunnel[j] = link;
62266e49541Snaddy 			if (arc4random() % 2 == 1)
623df930be7Sderaadt 				continue;
624df930be7Sderaadt 			for (k = 0; k < link_num; ++k) {
625df930be7Sderaadt 				/* if duplicate, skip it */
626df930be7Sderaadt 				if (cave[link].tunnel[k] == i)
627df930be7Sderaadt 					k = link_num;
62840c957bfSderaadt 				else {
629df930be7Sderaadt 					/* if open link, use it, force exit */
630df930be7Sderaadt 					if (cave[link].tunnel[k] == -1) {
631df930be7Sderaadt 						cave[link].tunnel[k] = i;
632df930be7Sderaadt 						k = link_num;
633df930be7Sderaadt 					}
634df930be7Sderaadt 				}
635df930be7Sderaadt 			}
63640c957bfSderaadt 		}
637df930be7Sderaadt 	/*
638df930be7Sderaadt 	 * now that we're done, sort the tunnels in each of the rooms to
639df930be7Sderaadt 	 * make it easier on the intrepid adventurer.
640df930be7Sderaadt 	 */
641df930be7Sderaadt 	for (i = 1; i <= room_num; ++i)
642df930be7Sderaadt 		qsort(cave[i].tunnel, (u_int)link_num,
643df930be7Sderaadt 		    sizeof(cave[i].tunnel[0]), int_compare);
644df930be7Sderaadt 
645df930be7Sderaadt #ifdef DEBUG
646df930be7Sderaadt 	if (debug)
647df930be7Sderaadt 		for (i = 1; i <= room_num; ++i) {
648df930be7Sderaadt 			(void)printf("<room %d  has tunnels to ", i);
649df930be7Sderaadt 			for (j = 0; j < link_num; ++j)
650df930be7Sderaadt 				(void)printf("%d ", cave[i].tunnel[j]);
651df930be7Sderaadt 			(void)printf(">\n");
652df930be7Sderaadt 		}
653df930be7Sderaadt #endif
654df930be7Sderaadt }
655df930be7Sderaadt 
65640c957bfSderaadt void
dodecahedral_cave_init(void)657ff8320a7Sderaadt dodecahedral_cave_init(void)
658077eda3bSpjanzen {
659077eda3bSpjanzen 	int vert[20][3] = {
660077eda3bSpjanzen 		{1, 4, 7},
661077eda3bSpjanzen 		{0, 2, 9},
662077eda3bSpjanzen 		{1, 3, 11},
663077eda3bSpjanzen 		{2, 4, 13},
664077eda3bSpjanzen 		{0, 3, 5},
665077eda3bSpjanzen 		{4, 6, 14},
666077eda3bSpjanzen 		{5, 7, 16},
667077eda3bSpjanzen 		{0, 6, 8},
668077eda3bSpjanzen 		{7, 9, 17},
669077eda3bSpjanzen 		{1, 8, 10},
670077eda3bSpjanzen 		{9, 11, 18},
671077eda3bSpjanzen 		{2, 10, 12},
672077eda3bSpjanzen 		{11, 13, 19},
673077eda3bSpjanzen 		{3, 12, 14},
674077eda3bSpjanzen 		{5, 13, 15},
675077eda3bSpjanzen 		{14, 16, 19},
676077eda3bSpjanzen 		{6, 15, 17},
677077eda3bSpjanzen 		{8, 16, 18},
678077eda3bSpjanzen 		{10, 17, 19},
679077eda3bSpjanzen 		{12, 15, 18},
680077eda3bSpjanzen 	};
681077eda3bSpjanzen 	int loc[20];
682077eda3bSpjanzen 	int i, j, temp;
683077eda3bSpjanzen 
684077eda3bSpjanzen 	if (room_num != 20 || link_num != 3)
685077eda3bSpjanzen 		errx(1, "wrong parameters for dodecahedron");
686077eda3bSpjanzen 	for (i = 0; i < 20; i++)
687077eda3bSpjanzen 		loc[i] = i;
688077eda3bSpjanzen 	for (i = 0; i < 20; i++) {
68966e49541Snaddy 		j = arc4random_uniform(20 - i);
690077eda3bSpjanzen 		if (j) {
691077eda3bSpjanzen 			temp = loc[i];
692077eda3bSpjanzen 			loc[i] = loc[i + j];
693077eda3bSpjanzen 			loc[i + j] = temp;
694077eda3bSpjanzen 		}
695077eda3bSpjanzen 	}
696077eda3bSpjanzen 	/* cave is offset by 1 */
697077eda3bSpjanzen 	for (i = 0; i < 20; i++) {
698077eda3bSpjanzen 		for (j = 0; j < 3; j++)
699077eda3bSpjanzen 			cave[loc[i] + 1].tunnel[j] = loc[vert[i][j]] + 1;
700077eda3bSpjanzen 	}
701077eda3bSpjanzen 
702077eda3bSpjanzen 	/*
703077eda3bSpjanzen 	 * now that we're done, sort the tunnels in each of the rooms to
704077eda3bSpjanzen 	 * make it easier on the intrepid adventurer.
705077eda3bSpjanzen 	 */
706077eda3bSpjanzen 	for (i = 1; i <= room_num; ++i)
707077eda3bSpjanzen 		qsort(cave[i].tunnel, (u_int)link_num,
708077eda3bSpjanzen 		    sizeof(cave[i].tunnel[0]), int_compare);
709077eda3bSpjanzen 
710077eda3bSpjanzen #ifdef DEBUG
711077eda3bSpjanzen 	if (debug)
712077eda3bSpjanzen 		for (i = 1; i <= room_num; ++i) {
713077eda3bSpjanzen 			(void)printf("<room %d  has tunnels to ", i);
714077eda3bSpjanzen 			for (j = 0; j < link_num; ++j)
715077eda3bSpjanzen 				(void)printf("%d ", cave[i].tunnel[j]);
716077eda3bSpjanzen 			(void)printf(">\n");
717077eda3bSpjanzen 		}
718077eda3bSpjanzen #endif
719077eda3bSpjanzen }
720077eda3bSpjanzen 
721077eda3bSpjanzen void
clear_things_in_cave(void)722ff8320a7Sderaadt clear_things_in_cave(void)
723df930be7Sderaadt {
7247faebae9Spjanzen 	int i;
725df930be7Sderaadt 
726df930be7Sderaadt 	/*
727df930be7Sderaadt 	 * remove bats and pits from the current cave in preparation for us
728df930be7Sderaadt 	 * adding new ones via the initialize_things_in_cave() routines.
729df930be7Sderaadt 	 */
730df930be7Sderaadt 	for (i = 1; i <= room_num; ++i)
731df930be7Sderaadt 		cave[i].has_a_bat = cave[i].has_a_pit = 0;
732df930be7Sderaadt }
733df930be7Sderaadt 
73440c957bfSderaadt void
initialize_things_in_cave(void)735ff8320a7Sderaadt initialize_things_in_cave(void)
736df930be7Sderaadt {
7377faebae9Spjanzen 	int i, loc;
738df930be7Sderaadt 
739df930be7Sderaadt 	/* place some bats, pits, the wumpus, and the player. */
740df930be7Sderaadt 	for (i = 0; i < bat_num; ++i) {
741df930be7Sderaadt 		do {
74266e49541Snaddy 			loc = arc4random_uniform(room_num) + 1;
743df930be7Sderaadt 		} while (cave[loc].has_a_bat);
744df930be7Sderaadt 		cave[loc].has_a_bat = 1;
745df930be7Sderaadt #ifdef DEBUG
746df930be7Sderaadt 		if (debug)
747df930be7Sderaadt 			(void)printf("<bat in room %d>\n", loc);
748df930be7Sderaadt #endif
749df930be7Sderaadt 	}
750df930be7Sderaadt 
751df930be7Sderaadt 	for (i = 0; i < pit_num; ++i) {
752df930be7Sderaadt 		do {
75366e49541Snaddy 			loc = arc4random_uniform(room_num) + 1;
75440c957bfSderaadt 		} while (cave[loc].has_a_pit || cave[loc].has_a_bat);
75540c957bfSderaadt 		/* Above used to be &&;  || makes sense but so does just
75640c957bfSderaadt 		 * checking cave[loc].has_a_pit  */
757df930be7Sderaadt 		cave[loc].has_a_pit = 1;
758df930be7Sderaadt #ifdef DEBUG
759df930be7Sderaadt 		if (debug)
760df930be7Sderaadt 			(void)printf("<pit in room %d>\n", loc);
761df930be7Sderaadt #endif
762df930be7Sderaadt 	}
763df930be7Sderaadt 
76466e49541Snaddy 	wumpus_loc = arc4random_uniform(room_num) + 1;
765df930be7Sderaadt #ifdef DEBUG
766df930be7Sderaadt 	if (debug)
76740c957bfSderaadt 		(void)printf("<wumpus in room %d>\n", wumpus_loc);
768df930be7Sderaadt #endif
769df930be7Sderaadt 
770df930be7Sderaadt 	do {
77166e49541Snaddy 		player_loc = arc4random_uniform(room_num) + 1;
77240c957bfSderaadt 	} while (player_loc == wumpus_loc || cave[player_loc].has_a_pit ||
77340c957bfSderaadt 			cave[player_loc].has_a_bat);
77440c957bfSderaadt 	/* Replaced (level == HARD ?
77540c957bfSderaadt 	 *  (link_num / room_num < 0.4 ? wump_nearby() : 0) : 0)
77640c957bfSderaadt 	 * with bat/pit checks in initial room.  If this is kept there is
77740c957bfSderaadt 	 * a slight chance that no room satisfies all four conditions.
77840c957bfSderaadt 	 */
779df930be7Sderaadt }
780df930be7Sderaadt 
78140c957bfSderaadt int
getans(const char * prompt)78225154944Spjanzen getans(const char *prompt)
783df930be7Sderaadt {
784df930be7Sderaadt 	char buf[20];
785df930be7Sderaadt 
786df930be7Sderaadt 	/*
787df930be7Sderaadt 	 * simple routine to ask the yes/no question specified until the user
788df930be7Sderaadt 	 * answers yes or no, then return 1 if they said 'yes' and 0 if they
789df930be7Sderaadt 	 * answered 'no'.
790df930be7Sderaadt 	 */
791df930be7Sderaadt 	for (;;) {
792df930be7Sderaadt 		(void)printf("%s", prompt);
793df930be7Sderaadt 		(void)fflush(stdout);
794df930be7Sderaadt 		if (!fgets(buf, sizeof(buf), stdin))
795df930be7Sderaadt 			return(0);
796df930be7Sderaadt 		if (*buf == 'N' || *buf == 'n')
797df930be7Sderaadt 			return(0);
798df930be7Sderaadt 		if (*buf == 'Y' || *buf == 'y')
799df930be7Sderaadt 			return(1);
800df930be7Sderaadt 		(void)printf(
801df930be7Sderaadt "I don't understand your answer; please enter 'y' or 'n'!\n");
802df930be7Sderaadt 	}
803df930be7Sderaadt }
804df930be7Sderaadt 
80540c957bfSderaadt int
bats_nearby(void)806ff8320a7Sderaadt bats_nearby(void)
807df930be7Sderaadt {
8087faebae9Spjanzen 	int i;
809df930be7Sderaadt 
810df930be7Sderaadt 	/* check for bats in the immediate vicinity */
811df930be7Sderaadt 	for (i = 0; i < link_num; ++i)
812df930be7Sderaadt 		if (cave[cave[player_loc].tunnel[i]].has_a_bat)
813df930be7Sderaadt 			return(1);
814df930be7Sderaadt 	return(0);
815df930be7Sderaadt }
816df930be7Sderaadt 
81740c957bfSderaadt int
pit_nearby(void)818ff8320a7Sderaadt pit_nearby(void)
819df930be7Sderaadt {
8207faebae9Spjanzen 	int i;
821df930be7Sderaadt 
822df930be7Sderaadt 	/* check for pits in the immediate vicinity */
823df930be7Sderaadt 	for (i = 0; i < link_num; ++i)
824df930be7Sderaadt 		if (cave[cave[player_loc].tunnel[i]].has_a_pit)
825df930be7Sderaadt 			return(1);
826df930be7Sderaadt 	return(0);
827df930be7Sderaadt }
828df930be7Sderaadt 
82940c957bfSderaadt int
wump_nearby(void)830ff8320a7Sderaadt wump_nearby(void)
831df930be7Sderaadt {
8327faebae9Spjanzen 	int i, j;
833df930be7Sderaadt 
834df930be7Sderaadt 	/* check for a wumpus within TWO caves of where we are */
835df930be7Sderaadt 	for (i = 0; i < link_num; ++i) {
836df930be7Sderaadt 		if (cave[player_loc].tunnel[i] == wumpus_loc)
837df930be7Sderaadt 			return(1);
838df930be7Sderaadt 		for (j = 0; j < link_num; ++j)
839df930be7Sderaadt 			if (cave[cave[player_loc].tunnel[i]].tunnel[j] ==
840df930be7Sderaadt 			    wumpus_loc)
841df930be7Sderaadt 				return(1);
842df930be7Sderaadt 	}
843df930be7Sderaadt 	return(0);
844df930be7Sderaadt }
845df930be7Sderaadt 
84640c957bfSderaadt void
move_wump(void)847ff8320a7Sderaadt move_wump(void)
848df930be7Sderaadt {
84966e49541Snaddy 	wumpus_loc = cave[wumpus_loc].tunnel[arc4random_uniform(link_num)];
85040c957bfSderaadt #ifdef DEBUG
85140c957bfSderaadt 	if (debug)
85240c957bfSderaadt 		(void)printf("Wumpus moved to room %d\n",wumpus_loc);
85340c957bfSderaadt #endif
854df930be7Sderaadt }
855df930be7Sderaadt 
85640c957bfSderaadt int
int_compare(const void * a,const void * b)85725154944Spjanzen int_compare(const void *a, const void *b)
858df930be7Sderaadt {
859d049854fSpjanzen 	return(*(const int *)a < *(const int *)b ? -1 : 1);
860df930be7Sderaadt }
861df930be7Sderaadt 
86240c957bfSderaadt void
instructions(void)863ff8320a7Sderaadt instructions(void)
864df930be7Sderaadt {
86596b46b10Spjanzen 	const char *pager;
86696b46b10Spjanzen 	pid_t pid;
86796b46b10Spjanzen 	int status;
86896b46b10Spjanzen 	int fd;
869df930be7Sderaadt 
870df930be7Sderaadt 	/*
871df930be7Sderaadt 	 * read the instructions file, if needed, and show the user how to
872df930be7Sderaadt 	 * play this game!
873df930be7Sderaadt 	 */
874df930be7Sderaadt 	if (!getans("Instructions? (y-n) "))
875df930be7Sderaadt 		return;
876df930be7Sderaadt 
87796b46b10Spjanzen 	if ((fd = open(_PATH_WUMPINFO, O_RDONLY)) == -1) {
878df930be7Sderaadt 		(void)printf(
879df930be7Sderaadt "Sorry, but the instruction file seems to have disappeared in a\n\
880df930be7Sderaadt puff of greasy black smoke! (poof)\n");
881df930be7Sderaadt 		return;
882df930be7Sderaadt 	}
883df930be7Sderaadt 
88496b46b10Spjanzen 	if (!isatty(1))
88596b46b10Spjanzen 		pager = "/bin/cat";
88696b46b10Spjanzen 	else {
88796b46b10Spjanzen 		if (!(pager = getenv("PAGER")) || (*pager == 0))
88896b46b10Spjanzen 			pager = _PATH_PAGER;
88996b46b10Spjanzen 	}
89096b46b10Spjanzen 	switch (pid = fork()) {
89196b46b10Spjanzen 	case 0: /* child */
89296b46b10Spjanzen 		if (dup2(fd, 0) == -1)
89396b46b10Spjanzen 			err(1, "dup2");
894c96f6a27Sderaadt 		(void)execl(_PATH_BSHELL, "sh", "-c", pager, (char *)NULL);
89596b46b10Spjanzen 		err(1, "exec sh -c %s", pager);
89696b46b10Spjanzen 		/* NOT REACHED */
89796b46b10Spjanzen 	case -1:
89896b46b10Spjanzen 		err(1, "fork");
89996b46b10Spjanzen 		/* NOT REACHED */
90096b46b10Spjanzen 	default:
90196b46b10Spjanzen 		(void)waitpid(pid, &status, 0);
90296b46b10Spjanzen 		close(fd);
90396b46b10Spjanzen 		break;
90496b46b10Spjanzen 	}
905df930be7Sderaadt }
906df930be7Sderaadt 
90740c957bfSderaadt void
usage(void)908ff8320a7Sderaadt usage(void)
909df930be7Sderaadt {
910df930be7Sderaadt 	(void)fprintf(stderr,
9116fa5e1daSmestre 	    "usage: %s [-ho] [-a arrows] [-b bats] [-p pits] "
9126fa5e1daSmestre 	    "[-r rooms] [-t tunnels]\n", getprogname());
913df930be7Sderaadt 	exit(1);
914df930be7Sderaadt }
915df930be7Sderaadt 
916df930be7Sderaadt /* messages */
91740c957bfSderaadt void
wump_kill(void)918ff8320a7Sderaadt wump_kill(void)
919df930be7Sderaadt {
920df930be7Sderaadt 	(void)printf(
921df930be7Sderaadt "*ROAR* *chomp* *snurfle* *chomp*!\n\
92240c957bfSderaadt Much to the delight of the Wumpus, you walk right into his mouth,\n\
923df930be7Sderaadt making you one of the easiest dinners he's ever had!  For you, however,\n\
924df930be7Sderaadt it's a rather unpleasant death.  The only good thing is that it's been\n\
925df930be7Sderaadt so long since the evil Wumpus cleaned his teeth that you immediately\n\
92640c957bfSderaadt pass out from the stench!\n");
927df930be7Sderaadt }
928df930be7Sderaadt 
92940c957bfSderaadt void
wump_walk_kill(void)930ff8320a7Sderaadt wump_walk_kill(void)
93140c957bfSderaadt {
93240c957bfSderaadt 	(void)printf(
93340c957bfSderaadt "Oh dear.  All the commotion has managed to awaken the evil Wumpus, who\n\
93440c957bfSderaadt has chosen to walk into this very room!  Your eyes open wide as they behold\n\
93540c957bfSderaadt the great sucker-footed bulk that is the Wumpus; the mouth of the Wumpus\n\
93612afdeb8Spjanzen also opens wide as the evil beast beholds dinner.\n\
93740c957bfSderaadt *ROAR* *chomp* *snurfle* *chomp*!\n");
93840c957bfSderaadt }
93940c957bfSderaadt 
94040c957bfSderaadt void
wump_bat_kill(void)941ff8320a7Sderaadt wump_bat_kill(void)
94240c957bfSderaadt {
94340c957bfSderaadt 	(void)printf(
94440c957bfSderaadt "Flap, flap.  The bats fly you right into the room with the evil Wumpus!\n\
94540c957bfSderaadt The Wumpus, seeing a fine dinner flying overhead, takes a swipe at you,\n\
94640c957bfSderaadt and the bats, not wanting to serve as hors d'oeuvres, drop their\n\
94740c957bfSderaadt soon-to-be-dead weight and take off in the way that only bats flying out\n\
94840c957bfSderaadt of a very bad place can.  As you fall towards the large, sharp, and very\n\
94940c957bfSderaadt foul-smelling teeth of the Wumpus, you think, \"Man, this is going to hurt.\"\n\
95040c957bfSderaadt It does.\n");
95140c957bfSderaadt }
95240c957bfSderaadt 
95340c957bfSderaadt void
kill_wump(void)954ff8320a7Sderaadt kill_wump(void)
955df930be7Sderaadt {
956df930be7Sderaadt 	(void)printf(
957df930be7Sderaadt "*thwock!* *groan* *crash*\n\n\
958df930be7Sderaadt A horrible roar fills the cave, and you realize, with a smile, that you\n\
959df930be7Sderaadt have slain the evil Wumpus and won the game!  You don't want to tarry for\n\
960df930be7Sderaadt long, however, because not only is the Wumpus famous, but the stench of\n\
96140c957bfSderaadt dead Wumpus is also quite well known--a stench powerful enough to slay the\n\
962df930be7Sderaadt mightiest adventurer at a single whiff!!\n");
963df930be7Sderaadt }
964df930be7Sderaadt 
96540c957bfSderaadt void
no_arrows(void)966ff8320a7Sderaadt no_arrows(void)
967df930be7Sderaadt {
968df930be7Sderaadt 	(void)printf(
969df930be7Sderaadt "\nYou turn and look at your quiver, and realize with a sinking feeling\n\
970df930be7Sderaadt that you've just shot your last arrow (figuratively, too).  Sensing this\n\
97140c957bfSderaadt with its psychic powers, the evil Wumpus rampages through the cave, finds\n\
972df930be7Sderaadt you, and with a mighty *ROAR* eats you alive!\n");
973df930be7Sderaadt }
974df930be7Sderaadt 
97540c957bfSderaadt void
shoot_self(void)976ff8320a7Sderaadt shoot_self(void)
977df930be7Sderaadt {
978df930be7Sderaadt 	(void)printf(
97940c957bfSderaadt "\n*Thwack!*  A sudden piercing feeling informs you that your wild arrow\n\
98040c957bfSderaadt has ricocheted back and wedged in your side, causing extreme agony.  The\n\
98140c957bfSderaadt evil Wumpus, with its psychic powers, realizes this and immediately rushes\n\
98240c957bfSderaadt to your side, not to help, alas, but to EAT YOU!\n\
983df930be7Sderaadt (*CHOMP*)\n");
984df930be7Sderaadt }
985df930be7Sderaadt 
98640c957bfSderaadt /*
98740c957bfSderaadt  * void
98825154944Spjanzen  * jump(int where)
98940c957bfSderaadt  * {
99040c957bfSderaadt  * 	(void)printf(
99140c957bfSderaadt  * "\nWith a jaunty step you enter the magic tunnel.  As you do, you\n\
99240c957bfSderaadt  * notice that the walls are shimmering and glowing.  Suddenly you feel\n\
99340c957bfSderaadt  * a very curious, warm sensation and find yourself in room %d!!\n", where);
99440c957bfSderaadt  * }
99540c957bfSderaadt  */
996df930be7Sderaadt 
99740c957bfSderaadt void
pit_kill(void)998ff8320a7Sderaadt pit_kill(void)
999df930be7Sderaadt {
1000df930be7Sderaadt 	(void)printf(
1001df930be7Sderaadt "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
1002df930be7Sderaadt The whistling sound and updraft as you walked into this room of the\n\
100340c957bfSderaadt cave apparently weren't enough to clue you in to the presence of the\n\
1004df930be7Sderaadt bottomless pit.  You have a lot of time to reflect on this error as\n\
1005df930be7Sderaadt you fall many miles to the core of the earth.  Look on the bright side;\n\
1006df930be7Sderaadt you can at least find out if Jules Verne was right...\n");
1007df930be7Sderaadt }
1008df930be7Sderaadt 
100940c957bfSderaadt void
pit_kill_bat(void)1010ff8320a7Sderaadt pit_kill_bat(void)
101140c957bfSderaadt {
101240c957bfSderaadt 	(void)printf(
101340c957bfSderaadt "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
101440c957bfSderaadt It appears the bats have decided to drop you into a bottomless pit.  At\n\
101540c957bfSderaadt least, that's what the whistling sound and updraft would suggest.  Look on\n\
101640c957bfSderaadt the bright side; you can at least find out if Jules Verne was right...\n");
101740c957bfSderaadt }
101840c957bfSderaadt 
101940c957bfSderaadt void
pit_survive(void)1020ff8320a7Sderaadt pit_survive(void)
1021df930be7Sderaadt {
1022df930be7Sderaadt 	(void)printf(
1023df930be7Sderaadt "Without conscious thought you grab for the side of the cave and manage\n\
1024df930be7Sderaadt to grasp onto a rocky outcrop.  Beneath your feet stretches the limitless\n\
1025df930be7Sderaadt depths of a bottomless pit!  Rock crumbles beneath your feet!\n");
1026df930be7Sderaadt }
1027