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