xref: /openbsd/games/wump/wump.c (revision 91f110e0)
1 /*	$OpenBSD: wump.c,v 1.26 2013/08/29 20:22:22 naddy Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Dave Taylor, of Intuitive Systems.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * A no longer new version of the age-old favorite Hunt-The-Wumpus game that
38  * has been a part of the BSD distribution for longer than us old folk
39  * would care to remember.
40  */
41 
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <paths.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include "pathnames.h"
53 
54 /* some defines to spec out what our wumpus cave should look like */
55 
56 /* #define	MAX_ARROW_SHOT_DISTANCE	6	*/	/* +1 for '0' stopper */
57 #define	MAX_LINKS_IN_ROOM	25		/* a complex cave */
58 
59 #define	MAX_ROOMS_IN_CAVE	250
60 #define	ROOMS_IN_CAVE		20
61 #define	MIN_ROOMS_IN_CAVE	10
62 
63 #define	LINKS_IN_ROOM		3
64 #define	NUMBER_OF_ARROWS	5
65 #define	PIT_COUNT		3
66 #define	BAT_COUNT		3
67 
68 #define	EASY			1		/* levels of play */
69 #define	HARD			2
70 
71 /* some macro definitions for cleaner output */
72 
73 #define	plural(n)	(n == 1 ? "" : "s")
74 
75 /* simple cave data structure; +1 so we can index from '1' not '0' */
76 struct room_record {
77 	int tunnel[MAX_LINKS_IN_ROOM];
78 	int has_a_pit, has_a_bat;
79 } cave[MAX_ROOMS_IN_CAVE+1];
80 
81 /*
82  * global variables so we can keep track of where the player is, how
83  * many arrows they still have, where el wumpo is, and so on...
84  */
85 int player_loc = -1;			/* player location */
86 int wumpus_loc = -1;			/* The Bad Guy location */
87 int level = EASY;			/* level of play */
88 int arrows_left;			/* arrows unshot */
89 int oldstyle = 0;			/* dodecahedral cave? */
90 
91 #ifdef DEBUG
92 int debug = 0;
93 #endif
94 
95 int pit_num = -1;		/* # pits in cave */
96 int bat_num = -1;		/* # bats */
97 int room_num = ROOMS_IN_CAVE;		/* # rooms in cave */
98 int link_num = LINKS_IN_ROOM;		/* links per room  */
99 int arrow_num = NUMBER_OF_ARROWS;	/* arrow inventory */
100 
101 char answer[20];			/* user input */
102 
103 int	bats_nearby(void);
104 void	cave_init(void);
105 void	clear_things_in_cave(void);
106 void	display_room_stats(void);
107 void	dodecahedral_cave_init(void);
108 int	gcd(int, int);
109 int	getans(const char *);
110 void	initialize_things_in_cave(void);
111 void	instructions(void);
112 int	int_compare(const void *, const void *);
113 /* void	jump(int); */
114 void	kill_wump(void);
115 int	main(int, char **);
116 int	move_to(const char *);
117 void	move_wump(void);
118 void	no_arrows(void);
119 void	pit_kill(void);
120 void	pit_kill_bat(void);
121 int	pit_nearby(void);
122 void	pit_survive(void);
123 int	shoot(char *);
124 void	shoot_self(void);
125 int	take_action(void);
126 void	usage(void);
127 void	wump_kill(void);
128 void	wump_bat_kill(void);
129 void	wump_walk_kill(void);
130 int	wump_nearby(void);
131 
132 
133 int
134 main(int argc, char *argv[])
135 {
136 	int c;
137 
138 #ifdef DEBUG
139 	while ((c = getopt(argc, argv, "a:b:hop:r:t:d")) != -1)
140 #else
141 	while ((c = getopt(argc, argv, "a:b:hop:r:t:")) != -1)
142 #endif
143 		switch (c) {
144 		case 'a':
145 			arrow_num = atoi(optarg);
146 			break;
147 		case 'b':
148 			bat_num = atoi(optarg);
149 			break;
150 #ifdef DEBUG
151 		case 'd':
152 			debug = 1;
153 			break;
154 #endif
155 		case 'h':
156 			level = HARD;
157 			break;
158 		case 'o':
159 			oldstyle = 1;
160 			break;
161 		case 'p':
162 			pit_num = atoi(optarg);
163 			break;
164 		case 'r':
165 			room_num = atoi(optarg);
166 			if (room_num < MIN_ROOMS_IN_CAVE)
167 				errx(1,
168 	"no self-respecting wumpus would live in such a small cave!");
169 			if (room_num > MAX_ROOMS_IN_CAVE)
170 				errx(1,
171 	"even wumpii can't furnish caves that large!");
172 			break;
173 		case 't':
174 			link_num = atoi(optarg);
175 			if (link_num < 2)
176 				errx(1,
177 	"wumpii like extra doors in their caves!");
178 			break;
179 		case '?':
180 		default:
181 			usage();
182 	}
183 
184 	if (oldstyle) {
185 		room_num = 20;
186 		link_num = 3;
187 		/* Original game had exactly 2 bats and 2 pits */
188 		if (bat_num < 0)
189 			bat_num = 2;
190 		if (pit_num < 0)
191 			pit_num = 2;
192 	} else {
193 		if (bat_num < 0)
194 			bat_num = BAT_COUNT;
195 		if (pit_num < 0)
196 			pit_num = PIT_COUNT;
197 	}
198 
199 	if (link_num > MAX_LINKS_IN_ROOM ||
200 	    link_num > room_num - (room_num / 4))
201 		errx(1,
202 "too many tunnels!  The cave collapsed!\n(Fortunately, the wumpus escaped!)");
203 
204 	if (level == HARD) {
205 		if (room_num / 2 - bat_num)
206 			bat_num += arc4random_uniform(room_num / 2 - bat_num);
207 		if (room_num / 2 - pit_num)
208 			pit_num += arc4random_uniform(room_num / 2 - pit_num);
209 	}
210 
211 	/* Leave at least two rooms free--one for the player to start in, and
212 	 * potentially one for the wumpus.
213 	 */
214 	if (bat_num > room_num / 2 - 1)
215 		errx(1,
216 "the wumpus refused to enter the cave, claiming it was too crowded!");
217 
218 	if (pit_num > room_num / 2 - 1)
219 		errx(1,
220 "the wumpus refused to enter the cave, claiming it was too dangerous!");
221 
222 	instructions();
223 	if (oldstyle)
224 		dodecahedral_cave_init();
225 	else
226 		cave_init();
227 
228 	/* and we're OFF!  da dum, da dum, da dum, da dum... */
229 	(void)printf(
230 "\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
231 There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
232 quiver holds %d custom super anti-evil Wumpus arrows.  Good luck.\n",
233 	    room_num, link_num, bat_num, plural(bat_num), pit_num,
234 	    plural(pit_num), arrow_num);
235 
236 	for (;;) {
237 		initialize_things_in_cave();
238 		arrows_left = arrow_num;
239 		do {
240 			display_room_stats();
241 			(void)printf("Move or shoot? (m-s) ");
242 			(void)fflush(stdout);
243 			(void)fpurge(stdin);
244 			if (!fgets(answer, sizeof(answer), stdin))
245 				break;
246 		} while (!take_action());
247 		(void)fpurge(stdin);
248 
249 		if (!getans("\nCare to play another game? (y-n) ")) {
250 			(void)printf("\n");
251 			exit(0);
252 		}
253 		clear_things_in_cave();
254 		if (!getans("In the same cave? (y-n) ")) {
255 			if (oldstyle)
256 				dodecahedral_cave_init();
257 			else
258 				cave_init();
259 		}
260 	}
261 	/* NOTREACHED */
262 }
263 
264 void
265 display_room_stats(void)
266 {
267 	int i;
268 
269 	/*
270 	 * Routine will explain what's going on with the current room, as well
271 	 * as describe whether there are pits, bats, & wumpii nearby.  It's
272 	 * all pretty mindless, really.
273 	 */
274 	(void)printf(
275 "\nYou are in room %d of the cave, and have %d arrow%s left.\n",
276 	    player_loc, arrows_left, plural(arrows_left));
277 
278 	if (bats_nearby())
279 		(void)printf("*rustle* *rustle* (must be bats nearby)\n");
280 	if (pit_nearby())
281 		(void)printf("*whoosh* (I feel a draft from some pits).\n");
282 	if (wump_nearby())
283 		(void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
284 
285 	(void)printf("There are tunnels to rooms %d, ",
286 	   cave[player_loc].tunnel[0]);
287 
288 	for (i = 1; i < link_num - 1; i++)
289 /*		if (cave[player_loc].tunnel[i] <= room_num) */
290 			(void)printf("%d, ", cave[player_loc].tunnel[i]);
291 	(void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
292 }
293 
294 int
295 take_action(void)
296 {
297 	/*
298 	 * Do the action specified by the player, either 'm'ove, 's'hoot
299 	 * or something exceptionally bizarre and strange!  Returns 1
300 	 * iff the player died during this turn, otherwise returns 0.
301 	 */
302 	switch (*answer) {
303 		case 'M':
304 		case 'm':			/* move */
305 			return(move_to(answer + 1));
306 		case 'S':
307 		case 's':			/* shoot */
308 			return(shoot(answer + 1));
309 		case 'Q':
310 		case 'q':
311 		case 'x':
312 			exit(0);
313 		case '\n':
314 			return(0);
315 		}
316 	if (arc4random_uniform(15) == 1)
317 		(void)printf("Que pasa?\n");
318 	else
319 		(void)printf("I don't understand!\n");
320 	return(0);
321 }
322 
323 int
324 move_to(const char *room_number)
325 {
326 	int i, just_moved_by_bats, next_room, tunnel_available;
327 
328 	/*
329 	 * This is responsible for moving the player into another room in the
330 	 * cave as per their directions.  If room_number is a null string,
331 	 * then we'll prompt the user for the next room to go into.   Once
332 	 * we've moved into the room, we'll check for things like bats, pits,
333 	 * and so on.  This routine returns 1 if something occurs that kills
334 	 * the player and 0 otherwise...
335 	 */
336 	tunnel_available = just_moved_by_bats = 0;
337 	next_room = atoi(room_number);
338 
339 	/* crap for magic tunnels */
340 /*	if (next_room == room_num + 1 &&
341  *	    cave[player_loc].tunnel[link_num-1] != next_room)
342  *		++next_room;
343  */
344 	while (next_room < 1 || next_room > room_num /* + 1 */) {
345 		if (next_room < 0 && next_room != -1)
346 (void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
347 		if (next_room > room_num /* + 1 */)
348 (void)printf("What?  The cave surely isn't quite that big!\n");
349 /*		if (next_room == room_num + 1 &&
350  *		    cave[player_loc].tunnel[link_num-1] != next_room) {
351  *			(void)printf("What?  The cave isn't that big!\n");
352  *			++next_room;
353  *		}
354  */		(void)printf("To which room do you wish to move? ");
355 		(void)fflush(stdout);
356 		if (!fgets(answer, sizeof(answer), stdin))
357 			return(1);
358 		next_room = atoi(answer);
359 	}
360 
361 	/* now let's see if we can move to that room or not */
362 	tunnel_available = 0;
363 	for (i = 0; i < link_num; i++)
364 		if (cave[player_loc].tunnel[i] == next_room)
365 			tunnel_available = 1;
366 
367 	if (!tunnel_available) {
368 		(void)printf("*Oof!*  (You hit the wall)\n");
369 		if (arc4random_uniform(6) == 1) {
370 (void)printf("Your colorful comments awaken the wumpus!\n");
371 			move_wump();
372 			if (wumpus_loc == player_loc) {
373 				wump_walk_kill();
374 				return(1);
375 			}
376 		}
377 		return(0);
378 	}
379 
380 	/* now let's move into that room and check it out for dangers */
381 /*	if (next_room == room_num + 1)
382  *		jump(next_room = arc4random_uniform(room_num) + 1);
383  */
384 	player_loc = next_room;
385 	for (;;) {
386 		if (next_room == wumpus_loc) {		/* uh oh... */
387 			if (just_moved_by_bats)
388 				wump_bat_kill();
389 			else
390 				wump_kill();
391 			return(1);
392 		}
393 		if (cave[next_room].has_a_pit) {
394 			if (arc4random_uniform(12) < 2) {
395 				pit_survive();
396 				return(0);
397 			} else {
398 				if (just_moved_by_bats)
399 					pit_kill_bat();
400 				else
401 					pit_kill();
402 				return(1);
403 			}
404 		}
405 
406 		if (cave[next_room].has_a_bat) {
407 			(void)printf(
408 "*flap*  *flap*  *flap*  (humongous bats pick you up and move you%s!)\n",
409 			    just_moved_by_bats ? " again": "");
410 			next_room = player_loc =
411 			    arc4random_uniform(room_num) + 1;
412 			just_moved_by_bats = 1;
413 		}
414 
415 		else
416 			break;
417 	}
418 	return(0);
419 }
420 
421 int
422 shoot(char *room_list)
423 {
424 	int chance, next, roomcnt;
425 	int j, arrow_location, link, ok;
426 	char *p;
427 
428 	/*
429 	 * Implement shooting arrows.  Arrows are shot by the player indicating
430 	 * a space-separated list of rooms that the arrow should pass through;
431 	 * if any of the rooms they specify are not accessible via tunnel from
432 	 * the room the arrow is in, it will instead fly randomly into another
433 	 * room.  If the player hits the wumpus, this routine will indicate
434 	 * such.  If it misses, this routine may *move* the wumpus one room.
435 	 * If it's the last arrow, then the player dies...  Returns 1 if the
436 	 * player has won or died, 0 if nothing has happened.
437 	 */
438 	arrow_location = player_loc;
439 	for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
440 		if (!(p = strtok(room_list, " \t\n"))) {
441 			if (roomcnt == 1) {
442 				(void)printf("Enter a list of rooms to shoot into:\n");
443 				(void)fflush(stdout);
444 				if (!(p = strtok(fgets(answer, sizeof(answer), stdin),
445 							" \t\n"))) {
446 					(void)printf(
447 				"The arrow falls to the ground at your feet.\n");
448 					return(0);
449 					}
450 			} else
451 				break;
452 		}
453 		if (roomcnt > 5) {
454 			(void)printf(
455 "The arrow wavers in its flight and can go no further than room %d!\n",
456 					arrow_location);
457 			break;
458 		}
459 
460 		next = atoi(p);
461 		if (next == 0)
462 			break;	/* Old wumpus used room 0 as the terminator */
463 
464 		chance = arc4random_uniform(10);
465 		if (roomcnt == 4 && chance < 2) {
466 			(void)printf(
467 "Your finger slips on the bowstring!  *twaaaaaang*\n\
468 The arrow is weakly shot and can go no further than room %d!\n",arrow_location);
469 			break;
470 		} else if (roomcnt == 5 && chance < 6) {
471 			(void)printf(
472 "The arrow wavers in its flight and can go no further than room %d!\n",
473 					arrow_location);
474 			break;
475 		}
476 
477 		for (j = 0, ok = 0; j < link_num; j++)
478 			if (cave[arrow_location].tunnel[j] == next)
479 				ok = 1;
480 
481 		if (ok) {
482 /*			if (next > room_num) {
483  *				(void)printf(
484  * "A faint gleam tells you the arrow has gone through a magic tunnel!\n");
485  *				arrow_location =
486  *				    arc4random_uniform(room_num) + 1;
487  *			} else
488  */				arrow_location = next;
489 		} else {
490 			link = (arc4random_uniform(link_num));
491 			if (cave[arrow_location].tunnel[link] == player_loc)
492 				(void)printf(
493 "*thunk*  The arrow can't find a way from %d to %d and flies back into\n\
494 your room!\n",
495 				    arrow_location, next);
496 /*			else if (cave[arrow_location].tunnel[link] > room_num)
497  *				(void)printf(
498  *"*thunk*  The arrow flies randomly into a magic tunnel, thence into\n\
499  *room %d!\n",
500  *				    cave[arrow_location].tunnel[link]);
501  */			else
502 				(void)printf(
503 "*thunk*  The arrow can't find a way from %d to %d and flies randomly\n\
504 into room %d!\n", arrow_location, next, cave[arrow_location].tunnel[link]);
505 
506 			arrow_location = cave[arrow_location].tunnel[link];
507 		}
508 
509 		/*
510 		 * now we've gotten into the new room let us see if El Wumpo is
511 		 * in the same room ... if so we've a HIT and the player WON!
512 		 */
513 		if (arrow_location == wumpus_loc) {
514 			kill_wump();
515 			return(1);
516 		}
517 
518 		if (arrow_location == player_loc) {
519 			shoot_self();
520 			return(1);
521 		}
522 	}
523 
524 	if (!--arrows_left) {
525 		no_arrows();
526 		return(1);
527 	}
528 
529 	{
530 		/* each time you shoot, it's more likely the wumpus moves */
531 		static int lastchance = 2;
532 
533 		if (arc4random_uniform(level) == EASY ?
534 		    12 : 9 < (lastchance += 2)) {
535 			move_wump();
536 			if (wumpus_loc == player_loc) {
537 				wump_walk_kill();
538 				/* Reset for next game */
539 				lastchance = arc4random_uniform(3);
540 				return(1);
541 			}
542 
543 		}
544 	}
545 	(void)printf("The arrow hit nothing.\n");
546 	return(0);
547 }
548 
549 int
550 gcd(int a, int b)
551 {
552 	int r;
553 
554 	if (!(r = (a % b)))
555 		return(b);
556 	return(gcd(b, r));
557 }
558 
559 void
560 cave_init(void)
561 {
562 	int i, j, k, link;
563 	int delta;
564 
565 	/*
566 	 * This does most of the interesting work in this program actually!
567 	 * In this routine we'll initialize the Wumpus cave to have all rooms
568 	 * linking to all others by stepping through our data structure once,
569 	 * recording all forward links and backwards links too.  The parallel
570 	 * "linkcount" data structure ensures that no room ends up with more
571 	 * than three links, regardless of the quality of the random number
572 	 * generator that we're using.
573 	 */
574 
575 	/* Note that throughout the source there are commented-out vestigial
576 	 * remains of the 'magic tunnel', which was a tunnel to room
577 	 * room_num +1.  It was necessary if all paths were two-way and
578 	 * there was an odd number of rooms, each with an odd number of
579 	 * exits.  It's being kept in case cave_init ever gets reworked into
580 	 * something more traditional.
581 	 */
582 
583 	/* initialize the cave first off. */
584 	for (i = 1; i <= room_num; ++i)
585 		for (j = 0; j < link_num ; ++j)
586 			cave[i].tunnel[j] = -1;
587 
588 	/* choose a random 'hop' delta for our guaranteed link.
589 	 * To keep the cave connected, require greatest common
590 	 * divisor of (delta + 1) and room_num to be 1
591 	 */
592 	do {
593 		delta = arc4random_uniform(room_num - 1) + 1;
594 	} while (gcd(room_num, delta + 1) != 1);
595 
596 	for (i = 1; i <= room_num; ++i) {
597 		link = ((i + delta) % room_num) + 1;	/* connection */
598 		cave[i].tunnel[0] = link;		/* forw link */
599 		cave[link].tunnel[1] = i;		/* back link */
600 	}
601 	/* now fill in the rest of the cave with random connections.
602 	 * This is a departure from historical versions of wumpus.
603 	 */
604 	for (i = 1; i <= room_num; i++)
605 		for (j = 2; j < link_num ; j++) {
606 			if (cave[i].tunnel[j] != -1)
607 				continue;
608 try_again:		link = arc4random_uniform(room_num) + 1;
609 			/* skip duplicates */
610 			for (k = 0; k < j; k++)
611 				if (cave[i].tunnel[k] == link)
612 					goto try_again;
613 			/* don't let a room connect to itself */
614 			if (link == i)
615 				goto try_again;
616 			cave[i].tunnel[j] = link;
617 			if (arc4random() % 2 == 1)
618 				continue;
619 			for (k = 0; k < link_num; ++k) {
620 				/* if duplicate, skip it */
621 				if (cave[link].tunnel[k] == i)
622 					k = link_num;
623 				else {
624 					/* if open link, use it, force exit */
625 					if (cave[link].tunnel[k] == -1) {
626 						cave[link].tunnel[k] = i;
627 						k = link_num;
628 					}
629 				}
630 			}
631 		}
632 	/*
633 	 * now that we're done, sort the tunnels in each of the rooms to
634 	 * make it easier on the intrepid adventurer.
635 	 */
636 	for (i = 1; i <= room_num; ++i)
637 		qsort(cave[i].tunnel, (u_int)link_num,
638 		    sizeof(cave[i].tunnel[0]), int_compare);
639 
640 #ifdef DEBUG
641 	if (debug)
642 		for (i = 1; i <= room_num; ++i) {
643 			(void)printf("<room %d  has tunnels to ", i);
644 			for (j = 0; j < link_num; ++j)
645 				(void)printf("%d ", cave[i].tunnel[j]);
646 			(void)printf(">\n");
647 		}
648 #endif
649 }
650 
651 void
652 dodecahedral_cave_init(void)
653 {
654 	int vert[20][3] = {
655 		{1, 4, 7},
656 		{0, 2, 9},
657 		{1, 3, 11},
658 		{2, 4, 13},
659 		{0, 3, 5},
660 		{4, 6, 14},
661 		{5, 7, 16},
662 		{0, 6, 8},
663 		{7, 9, 17},
664 		{1, 8, 10},
665 		{9, 11, 18},
666 		{2, 10, 12},
667 		{11, 13, 19},
668 		{3, 12, 14},
669 		{5, 13, 15},
670 		{14, 16, 19},
671 		{6, 15, 17},
672 		{8, 16, 18},
673 		{10, 17, 19},
674 		{12, 15, 18},
675 	};
676 	int loc[20];
677 	int i, j, temp;
678 
679 	if (room_num != 20 || link_num != 3)
680 		errx(1, "wrong parameters for dodecahedron");
681 	for (i = 0; i < 20; i++)
682 		loc[i] = i;
683 	for (i = 0; i < 20; i++) {
684 		j = arc4random_uniform(20 - i);
685 		if (j) {
686 			temp = loc[i];
687 			loc[i] = loc[i + j];
688 			loc[i + j] = temp;
689 		}
690 	}
691 	/* cave is offset by 1 */
692 	for (i = 0; i < 20; i++) {
693 		for (j = 0; j < 3; j++)
694 			cave[loc[i] + 1].tunnel[j] = loc[vert[i][j]] + 1;
695 	}
696 
697 	/*
698 	 * now that we're done, sort the tunnels in each of the rooms to
699 	 * make it easier on the intrepid adventurer.
700 	 */
701 	for (i = 1; i <= room_num; ++i)
702 		qsort(cave[i].tunnel, (u_int)link_num,
703 		    sizeof(cave[i].tunnel[0]), int_compare);
704 
705 #ifdef DEBUG
706 	if (debug)
707 		for (i = 1; i <= room_num; ++i) {
708 			(void)printf("<room %d  has tunnels to ", i);
709 			for (j = 0; j < link_num; ++j)
710 				(void)printf("%d ", cave[i].tunnel[j]);
711 			(void)printf(">\n");
712 		}
713 #endif
714 }
715 
716 void
717 clear_things_in_cave(void)
718 {
719 	int i;
720 
721 	/*
722 	 * remove bats and pits from the current cave in preparation for us
723 	 * adding new ones via the initialize_things_in_cave() routines.
724 	 */
725 	for (i = 1; i <= room_num; ++i)
726 		cave[i].has_a_bat = cave[i].has_a_pit = 0;
727 }
728 
729 void
730 initialize_things_in_cave(void)
731 {
732 	int i, loc;
733 
734 	/* place some bats, pits, the wumpus, and the player. */
735 	for (i = 0; i < bat_num; ++i) {
736 		do {
737 			loc = arc4random_uniform(room_num) + 1;
738 		} while (cave[loc].has_a_bat);
739 		cave[loc].has_a_bat = 1;
740 #ifdef DEBUG
741 		if (debug)
742 			(void)printf("<bat in room %d>\n", loc);
743 #endif
744 	}
745 
746 	for (i = 0; i < pit_num; ++i) {
747 		do {
748 			loc = arc4random_uniform(room_num) + 1;
749 		} while (cave[loc].has_a_pit || cave[loc].has_a_bat);
750 		/* Above used to be &&;  || makes sense but so does just
751 		 * checking cave[loc].has_a_pit  */
752 		cave[loc].has_a_pit = 1;
753 #ifdef DEBUG
754 		if (debug)
755 			(void)printf("<pit in room %d>\n", loc);
756 #endif
757 	}
758 
759 	wumpus_loc = arc4random_uniform(room_num) + 1;
760 #ifdef DEBUG
761 	if (debug)
762 		(void)printf("<wumpus in room %d>\n", wumpus_loc);
763 #endif
764 
765 	do {
766 		player_loc = arc4random_uniform(room_num) + 1;
767 	} while (player_loc == wumpus_loc || cave[player_loc].has_a_pit ||
768 			cave[player_loc].has_a_bat);
769 	/* Replaced (level == HARD ?
770 	 *  (link_num / room_num < 0.4 ? wump_nearby() : 0) : 0)
771 	 * with bat/pit checks in initial room.  If this is kept there is
772 	 * a slight chance that no room satisfies all four conditions.
773 	 */
774 }
775 
776 int
777 getans(const char *prompt)
778 {
779 	char buf[20];
780 
781 	/*
782 	 * simple routine to ask the yes/no question specified until the user
783 	 * answers yes or no, then return 1 if they said 'yes' and 0 if they
784 	 * answered 'no'.
785 	 */
786 	for (;;) {
787 		(void)printf("%s", prompt);
788 		(void)fflush(stdout);
789 		if (!fgets(buf, sizeof(buf), stdin))
790 			return(0);
791 		if (*buf == 'N' || *buf == 'n')
792 			return(0);
793 		if (*buf == 'Y' || *buf == 'y')
794 			return(1);
795 		(void)printf(
796 "I don't understand your answer; please enter 'y' or 'n'!\n");
797 	}
798 	/* NOTREACHED */
799 }
800 
801 int
802 bats_nearby(void)
803 {
804 	int i;
805 
806 	/* check for bats in the immediate vicinity */
807 	for (i = 0; i < link_num; ++i)
808 		if (cave[cave[player_loc].tunnel[i]].has_a_bat)
809 			return(1);
810 	return(0);
811 }
812 
813 int
814 pit_nearby(void)
815 {
816 	int i;
817 
818 	/* check for pits in the immediate vicinity */
819 	for (i = 0; i < link_num; ++i)
820 		if (cave[cave[player_loc].tunnel[i]].has_a_pit)
821 			return(1);
822 	return(0);
823 }
824 
825 int
826 wump_nearby(void)
827 {
828 	int i, j;
829 
830 	/* check for a wumpus within TWO caves of where we are */
831 	for (i = 0; i < link_num; ++i) {
832 		if (cave[player_loc].tunnel[i] == wumpus_loc)
833 			return(1);
834 		for (j = 0; j < link_num; ++j)
835 			if (cave[cave[player_loc].tunnel[i]].tunnel[j] ==
836 			    wumpus_loc)
837 				return(1);
838 	}
839 	return(0);
840 }
841 
842 void
843 move_wump(void)
844 {
845 	wumpus_loc = cave[wumpus_loc].tunnel[arc4random_uniform(link_num)];
846 #ifdef DEBUG
847 	if (debug)
848 		(void)printf("Wumpus moved to room %d\n",wumpus_loc);
849 #endif
850 }
851 
852 int
853 int_compare(const void *a, const void *b)
854 {
855 	return(*(const int *)a < *(const int *)b ? -1 : 1);
856 }
857 
858 void
859 instructions(void)
860 {
861 	const char *pager;
862 	pid_t pid;
863 	int status;
864 	int fd;
865 
866 	/*
867 	 * read the instructions file, if needed, and show the user how to
868 	 * play this game!
869 	 */
870 	if (!getans("Instructions? (y-n) "))
871 		return;
872 
873 	if ((fd = open(_PATH_WUMPINFO, O_RDONLY)) == -1) {
874 		(void)printf(
875 "Sorry, but the instruction file seems to have disappeared in a\n\
876 puff of greasy black smoke! (poof)\n");
877 		return;
878 	}
879 
880 	if (!isatty(1))
881 		pager = "/bin/cat";
882 	else {
883 		if (!(pager = getenv("PAGER")) || (*pager == 0))
884 			pager = _PATH_PAGER;
885 	}
886 	switch (pid = fork()) {
887 	case 0: /* child */
888 		if (dup2(fd, 0) == -1)
889 			err(1, "dup2");
890 		(void)execl(_PATH_BSHELL, "sh", "-c", pager, (char *)NULL);
891 		err(1, "exec sh -c %s", pager);
892 		/* NOT REACHED */
893 	case -1:
894 		err(1, "fork");
895 		/* NOT REACHED */
896 	default:
897 		(void)waitpid(pid, &status, 0);
898 		close(fd);
899 		break;
900 	}
901 }
902 
903 void
904 usage(void)
905 {
906 	(void)fprintf(stderr,
907 	    "usage: wump [-ho] [-a arrows] [-b bats] [-p pits] "
908 	    "[-r rooms] [-t tunnels]\n");
909 	exit(1);
910 }
911 
912 /* messages */
913 void
914 wump_kill(void)
915 {
916 	(void)printf(
917 "*ROAR* *chomp* *snurfle* *chomp*!\n\
918 Much to the delight of the Wumpus, you walk right into his mouth,\n\
919 making you one of the easiest dinners he's ever had!  For you, however,\n\
920 it's a rather unpleasant death.  The only good thing is that it's been\n\
921 so long since the evil Wumpus cleaned his teeth that you immediately\n\
922 pass out from the stench!\n");
923 }
924 
925 void
926 wump_walk_kill(void)
927 {
928 	(void)printf(
929 "Oh dear.  All the commotion has managed to awaken the evil Wumpus, who\n\
930 has chosen to walk into this very room!  Your eyes open wide as they behold\n\
931 the great sucker-footed bulk that is the Wumpus; the mouth of the Wumpus\n\
932 also opens wide as the evil beast beholds dinner.\n\
933 *ROAR* *chomp* *snurfle* *chomp*!\n");
934 }
935 
936 void
937 wump_bat_kill(void)
938 {
939 	(void)printf(
940 "Flap, flap.  The bats fly you right into the room with the evil Wumpus!\n\
941 The Wumpus, seeing a fine dinner flying overhead, takes a swipe at you,\n\
942 and the bats, not wanting to serve as hors d'oeuvres, drop their\n\
943 soon-to-be-dead weight and take off in the way that only bats flying out\n\
944 of a very bad place can.  As you fall towards the large, sharp, and very\n\
945 foul-smelling teeth of the Wumpus, you think, \"Man, this is going to hurt.\"\n\
946 It does.\n");
947 }
948 
949 void
950 kill_wump(void)
951 {
952 	(void)printf(
953 "*thwock!* *groan* *crash*\n\n\
954 A horrible roar fills the cave, and you realize, with a smile, that you\n\
955 have slain the evil Wumpus and won the game!  You don't want to tarry for\n\
956 long, however, because not only is the Wumpus famous, but the stench of\n\
957 dead Wumpus is also quite well known--a stench powerful enough to slay the\n\
958 mightiest adventurer at a single whiff!!\n");
959 }
960 
961 void
962 no_arrows(void)
963 {
964 	(void)printf(
965 "\nYou turn and look at your quiver, and realize with a sinking feeling\n\
966 that you've just shot your last arrow (figuratively, too).  Sensing this\n\
967 with its psychic powers, the evil Wumpus rampages through the cave, finds\n\
968 you, and with a mighty *ROAR* eats you alive!\n");
969 }
970 
971 void
972 shoot_self(void)
973 {
974 	(void)printf(
975 "\n*Thwack!*  A sudden piercing feeling informs you that your wild arrow\n\
976 has ricocheted back and wedged in your side, causing extreme agony.  The\n\
977 evil Wumpus, with its psychic powers, realizes this and immediately rushes\n\
978 to your side, not to help, alas, but to EAT YOU!\n\
979 (*CHOMP*)\n");
980 }
981 
982 /*
983  * void
984  * jump(int where)
985  * {
986  * 	(void)printf(
987  * "\nWith a jaunty step you enter the magic tunnel.  As you do, you\n\
988  * notice that the walls are shimmering and glowing.  Suddenly you feel\n\
989  * a very curious, warm sensation and find yourself in room %d!!\n", where);
990  * }
991  */
992 
993 void
994 pit_kill(void)
995 {
996 	(void)printf(
997 "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
998 The whistling sound and updraft as you walked into this room of the\n\
999 cave apparently weren't enough to clue you in to the presence of the\n\
1000 bottomless pit.  You have a lot of time to reflect on this error as\n\
1001 you fall many miles to the core of the earth.  Look on the bright side;\n\
1002 you can at least find out if Jules Verne was right...\n");
1003 }
1004 
1005 void
1006 pit_kill_bat(void)
1007 {
1008 	(void)printf(
1009 "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
1010 It appears the bats have decided to drop you into a bottomless pit.  At\n\
1011 least, that's what the whistling sound and updraft would suggest.  Look on\n\
1012 the bright side; you can at least find out if Jules Verne was right...\n");
1013 }
1014 
1015 void
1016 pit_survive(void)
1017 {
1018 	(void)printf(
1019 "Without conscious thought you grab for the side of the cave and manage\n\
1020 to grasp onto a rocky outcrop.  Beneath your feet stretches the limitless\n\
1021 depths of a bottomless pit!  Rock crumbles beneath your feet!\n");
1022 }
1023