184689157Sbostic /*
2*1897046eSbostic * Copyright (c) 1989, 1993
3*1897046eSbostic * The Regents of the University of California. All rights reserved.
484689157Sbostic * All rights reserved.
584689157Sbostic *
684689157Sbostic * This code is derived from software contributed to Berkeley by
784689157Sbostic * Dave Taylor, of Intuitive Systems.
884689157Sbostic *
9593194efSbostic * %sccs.include.redist.c%
1084689157Sbostic */
11957a0273Smckusick
1284689157Sbostic #ifndef lint
13*1897046eSbostic static char copyright[] =
14*1897046eSbostic "@(#) Copyright (c) 1989, 1993\n\
15*1897046eSbostic The Regents of the University of California. All rights reserved.\n";
1684689157Sbostic #endif /* not lint */
17957a0273Smckusick
1884689157Sbostic #ifndef lint
19*1897046eSbostic static char sccsid[] = "@(#)wump.c 8.1 (Berkeley) 05/31/93";
2084689157Sbostic #endif /* not lint */
2184689157Sbostic
2284689157Sbostic /*
2384689157Sbostic * A very new version of the age old favorite Hunt-The-Wumpus game that has
2484689157Sbostic * been a part of the BSD distribution of Unix for longer than us old folk
2584689157Sbostic * would care to remember.
2684689157Sbostic */
2784689157Sbostic
2884689157Sbostic #include <sys/types.h>
2984689157Sbostic #include <sys/file.h>
30957a0273Smckusick #include <stdio.h>
3184689157Sbostic #include "pathnames.h"
3284689157Sbostic
3384689157Sbostic /* some defines to spec out what our wumpus cave should look like */
3484689157Sbostic
3584689157Sbostic #define MAX_ARROW_SHOT_DISTANCE 6 /* +1 for '0' stopper */
3684689157Sbostic #define MAX_LINKS_IN_ROOM 25 /* a complex cave */
3784689157Sbostic
3884689157Sbostic #define MAX_ROOMS_IN_CAVE 250
3984689157Sbostic #define ROOMS_IN_CAVE 20
4084689157Sbostic #define MIN_ROOMS_IN_CAVE 10
4184689157Sbostic
4284689157Sbostic #define LINKS_IN_ROOM 3
4384689157Sbostic #define NUMBER_OF_ARROWS 5
4484689157Sbostic #define PIT_COUNT 3
4584689157Sbostic #define BAT_COUNT 3
4684689157Sbostic
4784689157Sbostic #define EASY 1 /* levels of play */
4884689157Sbostic #define HARD 2
4984689157Sbostic
5084689157Sbostic /* some macro definitions for cleaner output */
5184689157Sbostic
5284689157Sbostic #define plural(n) (n == 1 ? "" : "s")
5384689157Sbostic
5484689157Sbostic /* simple cave data structure; +1 so we can index from '1' not '0' */
5584689157Sbostic struct room_record {
5684689157Sbostic int tunnel[MAX_LINKS_IN_ROOM];
5784689157Sbostic int has_a_pit, has_a_bat;
5884689157Sbostic } cave[MAX_ROOMS_IN_CAVE+1];
59957a0273Smckusick
60957a0273Smckusick /*
6184689157Sbostic * global variables so we can keep track of where the player is, how
6284689157Sbostic * many arrows they still have, where el wumpo is, and so on...
63957a0273Smckusick */
6484689157Sbostic int player_loc = -1; /* player location */
6584689157Sbostic int wumpus_loc = -1; /* The Bad Guy location */
6684689157Sbostic int level = EASY; /* level of play */
6784689157Sbostic int arrows_left; /* arrows unshot */
68957a0273Smckusick
6984689157Sbostic #ifdef DEBUG
7084689157Sbostic int debug = 0;
7184689157Sbostic #endif
72957a0273Smckusick
7384689157Sbostic int pit_num = PIT_COUNT; /* # pits in cave */
7484689157Sbostic int bat_num = BAT_COUNT; /* # bats */
7584689157Sbostic int room_num = ROOMS_IN_CAVE; /* # rooms in cave */
7684689157Sbostic int link_num = LINKS_IN_ROOM; /* links per room */
7784689157Sbostic int arrow_num = NUMBER_OF_ARROWS; /* arrow inventory */
7884689157Sbostic
7984689157Sbostic char answer[20]; /* user input */
8084689157Sbostic
main(argc,argv)8184689157Sbostic main(argc, argv)
8284689157Sbostic int argc;
8384689157Sbostic char **argv;
84957a0273Smckusick {
8584689157Sbostic extern char *optarg;
86957a0273Smckusick int c;
87957a0273Smckusick
8884689157Sbostic #ifdef DEBUG
8984689157Sbostic while ((c = getopt(argc, argv, "a:b:hp:r:t:d")) != EOF)
9084689157Sbostic #else
9184689157Sbostic while ((c = getopt(argc, argv, "a:b:hp:r:t:")) != EOF)
9284689157Sbostic #endif
9384689157Sbostic switch (c) {
9484689157Sbostic case 'a':
9584689157Sbostic arrow_num = atoi(optarg);
9684689157Sbostic break;
9784689157Sbostic case 'b':
9884689157Sbostic bat_num = atoi(optarg);
9984689157Sbostic break;
10084689157Sbostic #ifdef DEBUG
10184689157Sbostic case 'd':
10284689157Sbostic debug = 1;
10384689157Sbostic break;
10484689157Sbostic #endif
10584689157Sbostic case 'h':
10684689157Sbostic level = HARD;
10784689157Sbostic break;
10884689157Sbostic case 'p':
10984689157Sbostic pit_num = atoi(optarg);
11084689157Sbostic break;
11184689157Sbostic case 'r':
11284689157Sbostic room_num = atoi(optarg);
11384689157Sbostic if (room_num < MIN_ROOMS_IN_CAVE) {
11484689157Sbostic (void)fprintf(stderr,
11584689157Sbostic "No self-respecting wumpus would live in such a small cave!\n");
11684689157Sbostic exit(1);
117957a0273Smckusick }
11884689157Sbostic if (room_num > MAX_ROOMS_IN_CAVE) {
11984689157Sbostic (void)fprintf(stderr,
12084689157Sbostic "Even wumpii can't furnish caves that large!\n");
12184689157Sbostic exit(1);
12284689157Sbostic }
12384689157Sbostic break;
12484689157Sbostic case 't':
12584689157Sbostic link_num = atoi(optarg);
12684689157Sbostic if (link_num < 2) {
12784689157Sbostic (void)fprintf(stderr,
12884689157Sbostic "Wumpii like extra doors in their caves!\n");
12984689157Sbostic exit(1);
13084689157Sbostic }
13184689157Sbostic break;
13284689157Sbostic case '?':
13384689157Sbostic default:
13484689157Sbostic usage();
135957a0273Smckusick }
136957a0273Smckusick
13784689157Sbostic if (link_num > MAX_LINKS_IN_ROOM ||
13884689157Sbostic link_num > room_num - (room_num / 4)) {
13984689157Sbostic (void)fprintf(stderr,
14084689157Sbostic "Too many tunnels! The cave collapsed!\n(Fortunately, the wumpus escaped!)\n");
14184689157Sbostic exit(1);
14284689157Sbostic }
14384689157Sbostic
14484689157Sbostic if (level == HARD) {
14584689157Sbostic bat_num += ((random() % (room_num / 2)) + 1);
14684689157Sbostic pit_num += ((random() % (room_num / 2)) + 1);
14784689157Sbostic }
14884689157Sbostic
14984689157Sbostic if (bat_num > room_num / 2) {
15084689157Sbostic (void)fprintf(stderr,
15184689157Sbostic "The wumpus refused to enter the cave, claiming it was too crowded!\n");
15284689157Sbostic exit(1);
15384689157Sbostic }
15484689157Sbostic
15584689157Sbostic if (pit_num > room_num / 2) {
15684689157Sbostic (void)fprintf(stderr,
15784689157Sbostic "The wumpus refused to enter the cave, claiming it was too dangerous!\n");
15884689157Sbostic exit(1);
15984689157Sbostic }
16084689157Sbostic
16184689157Sbostic instructions();
16284689157Sbostic cave_init();
16384689157Sbostic
16484689157Sbostic /* and we're OFF! da dum, da dum, da dum, da dum... */
16584689157Sbostic (void)printf(
16684689157Sbostic "\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
16784689157Sbostic There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
16884689157Sbostic quiver holds %d custom super anti-evil Wumpus arrows. Good luck.\n",
16984689157Sbostic room_num, link_num, bat_num, plural(bat_num), pit_num,
17084689157Sbostic plural(pit_num), arrow_num);
17184689157Sbostic
17284689157Sbostic for (;;) {
17384689157Sbostic initialize_things_in_cave();
17484689157Sbostic arrows_left = arrow_num;
17584689157Sbostic do {
17684689157Sbostic display_room_stats();
17784689157Sbostic (void)printf("Move or shoot? (m-s) ");
17884689157Sbostic (void)fflush(stdout);
17984689157Sbostic if (!fgets(answer, sizeof(answer), stdin))
18084689157Sbostic break;
18184689157Sbostic } while (!take_action());
18284689157Sbostic
18384689157Sbostic if (!getans("\nCare to play another game? (y-n) "))
18484689157Sbostic exit(0);
18584689157Sbostic if (getans("In the same cave? (y-n) "))
18684689157Sbostic clear_things_in_cave();
18784689157Sbostic else
18884689157Sbostic cave_init();
18984689157Sbostic }
19084689157Sbostic /* NOTREACHED */
19184689157Sbostic }
19284689157Sbostic
display_room_stats()19384689157Sbostic display_room_stats()
194957a0273Smckusick {
19584689157Sbostic register int i;
196957a0273Smckusick
19784689157Sbostic /*
19884689157Sbostic * Routine will explain what's going on with the current room, as well
19984689157Sbostic * as describe whether there are pits, bats, & wumpii nearby. It's
20084689157Sbostic * all pretty mindless, really.
20184689157Sbostic */
20284689157Sbostic (void)printf(
20384689157Sbostic "\nYou are in room %d of the cave, and have %d arrow%s left.\n",
20484689157Sbostic player_loc, arrows_left, plural(arrows_left));
20584689157Sbostic
20684689157Sbostic if (bats_nearby())
20784689157Sbostic (void)printf("*rustle* *rustle* (must be bats nearby)\n");
20884689157Sbostic if (pit_nearby())
20984689157Sbostic (void)printf("*whoosh* (I feel a draft from some pits).\n");
21084689157Sbostic if (wump_nearby())
21184689157Sbostic (void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
21284689157Sbostic
21384689157Sbostic (void)printf("There are tunnels to rooms %d, ",
21484689157Sbostic cave[player_loc].tunnel[0]);
21584689157Sbostic
21684689157Sbostic for (i = 1; i < link_num - 1; i++)
21784689157Sbostic if (cave[player_loc].tunnel[i] <= room_num)
21884689157Sbostic (void)printf("%d, ", cave[player_loc].tunnel[i]);
21984689157Sbostic (void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
220957a0273Smckusick }
221957a0273Smckusick
take_action()22284689157Sbostic take_action()
223957a0273Smckusick {
22484689157Sbostic /*
22584689157Sbostic * Do the action specified by the player, either 'm'ove, 's'hoot
22684689157Sbostic * or something exceptionally bizarre and strange! Returns 1
22784689157Sbostic * iff the player died during this turn, otherwise returns 0.
22884689157Sbostic */
22984689157Sbostic switch (*answer) {
23084689157Sbostic case 'M':
23184689157Sbostic case 'm': /* move */
23284689157Sbostic return(move_to(answer + 1));
23384689157Sbostic case 'S':
23484689157Sbostic case 's': /* shoot */
23584689157Sbostic return(shoot(answer + 1));
23684689157Sbostic case 'Q':
23784689157Sbostic case 'q':
23884689157Sbostic case 'x':
23984689157Sbostic exit(0);
24084689157Sbostic case '\n':
24184689157Sbostic return(0);
242957a0273Smckusick }
24384689157Sbostic if (random() % 15 == 1)
24484689157Sbostic (void)printf("Que pasa?\n");
24584689157Sbostic else
24684689157Sbostic (void)printf("I don't understand!\n");
24784689157Sbostic return(0);
248957a0273Smckusick }
249957a0273Smckusick
move_to(room_number)25084689157Sbostic move_to(room_number)
25184689157Sbostic char *room_number;
252957a0273Smckusick {
25384689157Sbostic int i, just_moved_by_bats, next_room, tunnel_available;
254957a0273Smckusick
25584689157Sbostic /*
25684689157Sbostic * This is responsible for moving the player into another room in the
25784689157Sbostic * cave as per their directions. If room_number is a null string,
25884689157Sbostic * then we'll prompt the user for the next room to go into. Once
25984689157Sbostic * we've moved into the room, we'll check for things like bats, pits,
26084689157Sbostic * and so on. This routine returns 1 if something occurs that kills
26184689157Sbostic * the player and 0 otherwise...
26284689157Sbostic */
26384689157Sbostic tunnel_available = just_moved_by_bats = 0;
26484689157Sbostic next_room = atoi(room_number);
26584689157Sbostic
26684689157Sbostic /* crap for magic tunnels */
26784689157Sbostic if (next_room == room_num + 1 &&
26884689157Sbostic cave[player_loc].tunnel[link_num-1] != next_room)
26984689157Sbostic ++next_room;
27084689157Sbostic
27184689157Sbostic while (next_room < 1 || next_room > room_num + 1) {
27284689157Sbostic if (next_room < 0 && next_room != -1)
27384689157Sbostic (void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
27484689157Sbostic if (next_room > room_num + 1)
27584689157Sbostic (void)printf("What? The cave surely isn't quite that big!\n");
27684689157Sbostic if (next_room == room_num + 1 &&
27784689157Sbostic cave[player_loc].tunnel[link_num-1] != next_room) {
27884689157Sbostic (void)printf("What? The cave isn't that big!\n");
27984689157Sbostic ++next_room;
28084689157Sbostic }
28184689157Sbostic (void)printf("To which room do you wish to move? ");
28284689157Sbostic (void)fflush(stdout);
28384689157Sbostic if (!fgets(answer, sizeof(answer), stdin))
28484689157Sbostic return(1);
28584689157Sbostic next_room = atoi(answer);
28684689157Sbostic }
28784689157Sbostic
28884689157Sbostic /* now let's see if we can move to that room or not */
28984689157Sbostic tunnel_available = 0;
29084689157Sbostic for (i = 0; i < link_num; i++)
29184689157Sbostic if (cave[player_loc].tunnel[i] == next_room)
29284689157Sbostic tunnel_available = 1;
29384689157Sbostic
29484689157Sbostic if (!tunnel_available) {
29584689157Sbostic (void)printf("*Oof!* (You hit the wall)\n");
29684689157Sbostic if (random() % 6 == 1) {
29784689157Sbostic (void)printf("Your colorful comments awaken the wumpus!\n");
29884689157Sbostic move_wump();
29984689157Sbostic if (wumpus_loc == player_loc) {
30084689157Sbostic wump_kill();
30184689157Sbostic return(1);
30284689157Sbostic }
303957a0273Smckusick }
304957a0273Smckusick return(0);
305957a0273Smckusick }
30684689157Sbostic
30784689157Sbostic /* now let's move into that room and check it out for dangers */
30884689157Sbostic if (next_room == room_num + 1)
30984689157Sbostic jump(next_room = (random() % room_num) + 1);
31084689157Sbostic
31184689157Sbostic player_loc = next_room;
31284689157Sbostic for (;;) {
31384689157Sbostic if (next_room == wumpus_loc) { /* uh oh... */
31484689157Sbostic wump_kill();
31584689157Sbostic return(1);
316957a0273Smckusick }
31784689157Sbostic if (cave[next_room].has_a_pit)
31884689157Sbostic if (random() % 12 < 2) {
31984689157Sbostic pit_survive();
32084689157Sbostic return(0);
32184689157Sbostic } else {
32284689157Sbostic pit_kill();
32384689157Sbostic return(1);
324957a0273Smckusick }
325957a0273Smckusick
32684689157Sbostic if (cave[next_room].has_a_bat) {
32784689157Sbostic (void)printf(
32884689157Sbostic "*flap* *flap* *flap* (humongous bats pick you up and move you%s!)\n",
32984689157Sbostic just_moved_by_bats ? " again": "");
33084689157Sbostic next_room = player_loc = (random() % room_num) + 1;
33184689157Sbostic just_moved_by_bats = 1;
33284689157Sbostic }
33384689157Sbostic
33484689157Sbostic else
33584689157Sbostic break;
33684689157Sbostic }
33784689157Sbostic return(0);
33884689157Sbostic }
33984689157Sbostic
shoot(room_list)34084689157Sbostic shoot(room_list)
34184689157Sbostic char *room_list;
342957a0273Smckusick {
34384689157Sbostic int chance, next, roomcnt;
34484689157Sbostic int j, arrow_location, link, ok;
34584689157Sbostic char *p, *strtok();
346957a0273Smckusick
34784689157Sbostic /*
34884689157Sbostic * Implement shooting arrows. Arrows are shot by the player indicating
34984689157Sbostic * a space-separated list of rooms that the arrow should pass through;
35084689157Sbostic * if any of the rooms they specify are not accessible via tunnel from
35184689157Sbostic * the room the arrow is in, it will instead fly randomly into another
35284689157Sbostic * room. If the player hits the wumpus, this routine will indicate
35384689157Sbostic * such. If it misses, this routine will *move* the wumpus one room.
35484689157Sbostic * If it's the last arrow, the player then dies... Returns 1 if the
35584689157Sbostic * player has won or died, 0 if nothing has happened.
35684689157Sbostic */
35784689157Sbostic arrow_location = player_loc;
35884689157Sbostic for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
35984689157Sbostic if (!(p = strtok(room_list, " \t\n")))
36084689157Sbostic if (roomcnt == 1) {
36184689157Sbostic (void)printf(
36284689157Sbostic "The arrow falls to the ground at your feet!\n");
36384689157Sbostic return(0);
36484689157Sbostic } else
36584689157Sbostic break;
36684689157Sbostic if (roomcnt > 5) {
36784689157Sbostic (void)printf(
36884689157Sbostic "The arrow wavers in its flight and and can go no further!\n");
36984689157Sbostic break;
37084689157Sbostic }
37184689157Sbostic next = atoi(p);
37284689157Sbostic for (j = 0, ok = 0; j < link_num; j++)
37384689157Sbostic if (cave[arrow_location].tunnel[j] == next)
37484689157Sbostic ok = 1;
37584689157Sbostic
37684689157Sbostic if (ok) {
37784689157Sbostic if (next > room_num) {
37884689157Sbostic (void)printf(
37984689157Sbostic "A faint gleam tells you the arrow has gone through a magic tunnel!\n");
38084689157Sbostic arrow_location = (random() % room_num) + 1;
38184689157Sbostic } else
38284689157Sbostic arrow_location = next;
38384689157Sbostic } else {
38484689157Sbostic link = (random() % link_num);
38584689157Sbostic if (link == player_loc)
38684689157Sbostic (void)printf(
38784689157Sbostic "*thunk* The arrow can't find a way from %d to %d and flys back into\n\
38884689157Sbostic your room!\n",
38984689157Sbostic arrow_location, next);
39084689157Sbostic else if (cave[arrow_location].tunnel[link] > room_num)
39184689157Sbostic (void)printf(
39284689157Sbostic "*thunk* The arrow flys randomly into a magic tunnel, thence into\n\
39384689157Sbostic room %d!\n",
39484689157Sbostic cave[arrow_location].tunnel[link]);
39584689157Sbostic else
39684689157Sbostic (void)printf(
39784689157Sbostic "*thunk* The arrow can't find a way from %d to %d and flys randomly\n\
39884689157Sbostic into room %d!\n",
39984689157Sbostic arrow_location, next,
40084689157Sbostic cave[arrow_location].tunnel[link]);
40184689157Sbostic arrow_location = cave[arrow_location].tunnel[link];
40284689157Sbostic break;
40384689157Sbostic }
40484689157Sbostic chance = random() % 10;
40584689157Sbostic if (roomcnt == 3 && chance < 2) {
40684689157Sbostic (void)printf(
40784689157Sbostic "Your bowstring breaks! *twaaaaaang*\n\
40884689157Sbostic The arrow is weakly shot and can go no further!\n");
40984689157Sbostic break;
41084689157Sbostic } else if (roomcnt == 4 && chance < 6) {
41184689157Sbostic (void)printf(
41284689157Sbostic "The arrow wavers in its flight and and can go no further!\n");
41384689157Sbostic break;
41484689157Sbostic }
41584689157Sbostic }
41684689157Sbostic
41784689157Sbostic /*
41884689157Sbostic * now we've gotten into the new room let us see if El Wumpo is
41984689157Sbostic * in the same room ... if so we've a HIT and the player WON!
42084689157Sbostic */
42184689157Sbostic if (arrow_location == wumpus_loc) {
42284689157Sbostic kill_wump();
42384689157Sbostic return(1);
42484689157Sbostic }
42584689157Sbostic
42684689157Sbostic if (arrow_location == player_loc) {
42784689157Sbostic shoot_self();
42884689157Sbostic return(1);
42984689157Sbostic }
43084689157Sbostic
43184689157Sbostic if (!--arrows_left) {
43284689157Sbostic no_arrows();
43384689157Sbostic return(1);
43484689157Sbostic }
43584689157Sbostic
43684689157Sbostic {
43784689157Sbostic /* each time you shoot, it's more likely the wumpus moves */
43884689157Sbostic static int lastchance = 2;
43984689157Sbostic
44084689157Sbostic if (random() % level == EASY ? 12 : 9 < (lastchance += 2)) {
44184689157Sbostic move_wump();
44284689157Sbostic if (wumpus_loc == player_loc)
44384689157Sbostic wump_kill();
44484689157Sbostic lastchance = random() % 3;
44584689157Sbostic
44684689157Sbostic }
44784689157Sbostic }
44884689157Sbostic return(0);
44984689157Sbostic }
45084689157Sbostic
cave_init()45184689157Sbostic cave_init()
45284689157Sbostic {
45384689157Sbostic register int i, j, k, link;
45484689157Sbostic int delta, int_compare();
45584689157Sbostic time_t time();
45684689157Sbostic
45784689157Sbostic /*
45884689157Sbostic * This does most of the interesting work in this program actually!
45984689157Sbostic * In this routine we'll initialize the Wumpus cave to have all rooms
46084689157Sbostic * linking to all others by stepping through our data structure once,
46184689157Sbostic * recording all forward links and backwards links too. The parallel
46284689157Sbostic * "linkcount" data structure ensures that no room ends up with more
46384689157Sbostic * than three links, regardless of the quality of the random number
46484689157Sbostic * generator that we're using.
46584689157Sbostic */
46684689157Sbostic srandom((int)time((time_t *)0));
46784689157Sbostic
46884689157Sbostic /* initialize the cave first off. */
46984689157Sbostic for (i = 1; i <= room_num; ++i)
47084689157Sbostic for (j = 0; j < link_num ; ++j)
47184689157Sbostic cave[i].tunnel[j] = -1;
47284689157Sbostic
47384689157Sbostic /* choose a random 'hop' delta for our guaranteed link */
47484689157Sbostic while (!(delta = random() % room_num));
47584689157Sbostic
47684689157Sbostic for (i = 1; i <= room_num; ++i) {
47784689157Sbostic link = ((i + delta) % room_num) + 1; /* connection */
47884689157Sbostic cave[i].tunnel[0] = link; /* forw link */
47984689157Sbostic cave[link].tunnel[1] = i; /* back link */
48084689157Sbostic }
48184689157Sbostic /* now fill in the rest of the cave with random connections */
48284689157Sbostic for (i = 1; i <= room_num; i++)
48384689157Sbostic for (j = 2; j < link_num ; j++) {
48484689157Sbostic if (cave[i].tunnel[j] != -1)
48584689157Sbostic continue;
48684689157Sbostic try_again: link = (random() % room_num) + 1;
48784689157Sbostic /* skip duplicates */
48884689157Sbostic for (k = 0; k < j; k++)
48984689157Sbostic if (cave[i].tunnel[k] == link)
49084689157Sbostic goto try_again;
49184689157Sbostic cave[i].tunnel[j] = link;
49284689157Sbostic if (random() % 2 == 1)
49384689157Sbostic continue;
49484689157Sbostic for (k = 0; k < link_num; ++k) {
49584689157Sbostic /* if duplicate, skip it */
49684689157Sbostic if (cave[link].tunnel[k] == i)
49784689157Sbostic k = link_num;
49884689157Sbostic
49984689157Sbostic /* if open link, use it, force exit */
50084689157Sbostic if (cave[link].tunnel[k] == -1) {
50184689157Sbostic cave[link].tunnel[k] = i;
50284689157Sbostic k = link_num;
50384689157Sbostic }
50484689157Sbostic }
50584689157Sbostic }
50684689157Sbostic /*
50784689157Sbostic * now that we're done, sort the tunnels in each of the rooms to
50884689157Sbostic * make it easier on the intrepid adventurer.
50984689157Sbostic */
51084689157Sbostic for (i = 1; i <= room_num; ++i)
51184689157Sbostic qsort(cave[i].tunnel, (u_int)link_num,
51284689157Sbostic sizeof(cave[i].tunnel[0]), int_compare);
51384689157Sbostic
51484689157Sbostic #ifdef DEBUG
51584689157Sbostic if (debug)
51684689157Sbostic for (i = 1; i <= room_num; ++i) {
51784689157Sbostic (void)printf("<room %d has tunnels to ", i);
51884689157Sbostic for (j = 0; j < link_num; ++j)
51984689157Sbostic (void)printf("%d ", cave[i].tunnel[j]);
52084689157Sbostic (void)printf(">\n");
52184689157Sbostic }
52284689157Sbostic #endif
52384689157Sbostic }
52484689157Sbostic
clear_things_in_cave()52584689157Sbostic clear_things_in_cave()
52684689157Sbostic {
52784689157Sbostic register int i;
52884689157Sbostic
52984689157Sbostic /*
53084689157Sbostic * remove bats and pits from the current cave in preparation for us
53184689157Sbostic * adding new ones via the initialize_things_in_cave() routines.
53284689157Sbostic */
53384689157Sbostic for (i = 1; i <= room_num; ++i)
53484689157Sbostic cave[i].has_a_bat = cave[i].has_a_pit = 0;
53584689157Sbostic }
53684689157Sbostic
initialize_things_in_cave()53784689157Sbostic initialize_things_in_cave()
53884689157Sbostic {
53984689157Sbostic register int i, loc;
54084689157Sbostic
54184689157Sbostic /* place some bats, pits, the wumpus, and the player. */
54284689157Sbostic for (i = 0; i < bat_num; ++i) {
54384689157Sbostic do {
54484689157Sbostic loc = (random() % room_num) + 1;
54584689157Sbostic } while (cave[loc].has_a_bat);
54684689157Sbostic cave[loc].has_a_bat = 1;
54784689157Sbostic #ifdef DEBUG
54884689157Sbostic if (debug)
54984689157Sbostic (void)printf("<bat in room %d>\n", loc);
55084689157Sbostic #endif
55184689157Sbostic }
55284689157Sbostic
55384689157Sbostic for (i = 0; i < pit_num; ++i) {
55484689157Sbostic do {
55584689157Sbostic loc = (random() % room_num) + 1;
55684689157Sbostic } while (cave[loc].has_a_pit && cave[loc].has_a_bat);
55784689157Sbostic cave[loc].has_a_pit = 1;
55884689157Sbostic #ifdef DEBUG
55984689157Sbostic if (debug)
56084689157Sbostic (void)printf("<pit in room %d>\n", loc);
56184689157Sbostic #endif
56284689157Sbostic }
56384689157Sbostic
56484689157Sbostic wumpus_loc = (random() % room_num) + 1;
56584689157Sbostic #ifdef DEBUG
56684689157Sbostic if (debug)
56784689157Sbostic (void)printf("<wumpus in room %d>\n", loc);
56884689157Sbostic #endif
56984689157Sbostic
57084689157Sbostic do {
57184689157Sbostic player_loc = (random() % room_num) + 1;
57284689157Sbostic } while (player_loc == wumpus_loc || (level == HARD ?
57384689157Sbostic (link_num / room_num < 0.4 ? wump_nearby() : 0) : 0));
57484689157Sbostic }
57584689157Sbostic
getans(prompt)57684689157Sbostic getans(prompt)
57784689157Sbostic char *prompt;
57884689157Sbostic {
57984689157Sbostic char buf[20];
58084689157Sbostic
58184689157Sbostic /*
58284689157Sbostic * simple routine to ask the yes/no question specified until the user
58384689157Sbostic * answers yes or no, then return 1 if they said 'yes' and 0 if they
58484689157Sbostic * answered 'no'.
58584689157Sbostic */
58684689157Sbostic for (;;) {
58784689157Sbostic (void)printf("%s", prompt);
58884689157Sbostic (void)fflush(stdout);
58984689157Sbostic if (!fgets(buf, sizeof(buf), stdin))
59084689157Sbostic return(0);
59184689157Sbostic if (*buf == 'N' || *buf == 'n')
59284689157Sbostic return(0);
59384689157Sbostic if (*buf == 'Y' || *buf == 'y')
59484689157Sbostic return(1);
59584689157Sbostic (void)printf(
59684689157Sbostic "I don't understand your answer; please enter 'y' or 'n'!\n");
59784689157Sbostic }
59884689157Sbostic /* NOTREACHED */
59984689157Sbostic }
60084689157Sbostic
bats_nearby()60184689157Sbostic bats_nearby()
60284689157Sbostic {
60384689157Sbostic register int i;
60484689157Sbostic
60584689157Sbostic /* check for bats in the immediate vicinity */
60684689157Sbostic for (i = 0; i < link_num; ++i)
60784689157Sbostic if (cave[cave[player_loc].tunnel[i]].has_a_bat)
608957a0273Smckusick return(1);
609957a0273Smckusick return(0);
610957a0273Smckusick }
611957a0273Smckusick
pit_nearby()61284689157Sbostic pit_nearby()
613957a0273Smckusick {
61484689157Sbostic register int i;
615957a0273Smckusick
61684689157Sbostic /* check for pits in the immediate vicinity */
61784689157Sbostic for (i = 0; i < link_num; ++i)
61884689157Sbostic if (cave[cave[player_loc].tunnel[i]].has_a_pit)
61984689157Sbostic return(1);
62084689157Sbostic return(0);
621957a0273Smckusick }
622957a0273Smckusick
wump_nearby()62384689157Sbostic wump_nearby()
62484689157Sbostic {
62584689157Sbostic register int i, j;
62684689157Sbostic
62784689157Sbostic /* check for a wumpus within TWO caves of where we are */
62884689157Sbostic for (i = 0; i < link_num; ++i) {
62984689157Sbostic if (cave[player_loc].tunnel[i] == wumpus_loc)
63084689157Sbostic return(1);
63184689157Sbostic for (j = 0; j < link_num; ++j)
63284689157Sbostic if (cave[cave[player_loc].tunnel[i]].tunnel[j] ==
63384689157Sbostic wumpus_loc)
63484689157Sbostic return(1);
63584689157Sbostic }
63684689157Sbostic return(0);
63784689157Sbostic }
63884689157Sbostic
move_wump()63984689157Sbostic move_wump()
64084689157Sbostic {
64184689157Sbostic wumpus_loc = cave[wumpus_loc].tunnel[random() % link_num];
64284689157Sbostic }
64384689157Sbostic
int_compare(a,b)64484689157Sbostic int_compare(a, b)
64584689157Sbostic int *a, *b;
64684689157Sbostic {
64784689157Sbostic return(*a < *b ? -1 : 1);
64884689157Sbostic }
64984689157Sbostic
instructions()65084689157Sbostic instructions()
65184689157Sbostic {
65284689157Sbostic char buf[120], *p, *getenv();
65384689157Sbostic
65484689157Sbostic /*
65584689157Sbostic * read the instructions file, if needed, and show the user how to
65684689157Sbostic * play this game!
65784689157Sbostic */
65884689157Sbostic if (!getans("Instructions? (y-n) "))
65984689157Sbostic return;
66084689157Sbostic
66184689157Sbostic if (access(_PATH_WUMPINFO, R_OK)) {
66284689157Sbostic (void)printf(
66384689157Sbostic "Sorry, but the instruction file seems to have disappeared in a\n\
66484689157Sbostic puff of greasy black smoke! (poof)\n");
66584689157Sbostic return;
66684689157Sbostic }
66784689157Sbostic
66884689157Sbostic if (!(p = getenv("PAGER")) ||
66984689157Sbostic strlen(p) > sizeof(buf) + strlen(_PATH_WUMPINFO) + 5)
67084689157Sbostic p = _PATH_PAGER;
67184689157Sbostic
67284689157Sbostic (void)sprintf(buf, "%s %s", p, _PATH_WUMPINFO);
67384689157Sbostic (void)system(buf);
67484689157Sbostic }
67584689157Sbostic
usage()67684689157Sbostic usage()
67784689157Sbostic {
67884689157Sbostic (void)fprintf(stderr,
67984689157Sbostic "usage: wump [-h] [-a arrows] [-b bats] [-p pits] [-r rooms] [-t tunnels]\n");
68084689157Sbostic exit(1);
68184689157Sbostic }
68284689157Sbostic
68384689157Sbostic /* messages */
68484689157Sbostic
wump_kill()68584689157Sbostic wump_kill()
68684689157Sbostic {
68784689157Sbostic (void)printf(
68884689157Sbostic "*ROAR* *chomp* *snurfle* *chomp*!\n\
68984689157Sbostic Much to the delight of the Wumpus, you walked right into his mouth,\n\
69084689157Sbostic making you one of the easiest dinners he's ever had! For you, however,\n\
69184689157Sbostic it's a rather unpleasant death. The only good thing is that it's been\n\
69284689157Sbostic so long since the evil Wumpus cleaned his teeth that you immediately\n\
69384689157Sbostic passed out from the stench!\n");
69484689157Sbostic }
69584689157Sbostic
kill_wump()69684689157Sbostic kill_wump()
69784689157Sbostic {
69884689157Sbostic (void)printf(
69984689157Sbostic "*thwock!* *groan* *crash*\n\n\
70084689157Sbostic A horrible roar fills the cave, and you realize, with a smile, that you\n\
70184689157Sbostic have slain the evil Wumpus and won the game! You don't want to tarry for\n\
70284689157Sbostic long, however, because not only is the Wumpus famous, but the stench of\n\
70384689157Sbostic dead Wumpus is also quite well known, a stench plenty enough to slay the\n\
70484689157Sbostic mightiest adventurer at a single whiff!!\n");
70584689157Sbostic }
70684689157Sbostic
no_arrows()70784689157Sbostic no_arrows()
70884689157Sbostic {
70984689157Sbostic (void)printf(
71084689157Sbostic "\nYou turn and look at your quiver, and realize with a sinking feeling\n\
71184689157Sbostic that you've just shot your last arrow (figuratively, too). Sensing this\n\
71284689157Sbostic with its psychic powers, the evil Wumpus rampagees through the cave, finds\n\
71384689157Sbostic you, and with a mighty *ROAR* eats you alive!\n");
71484689157Sbostic }
71584689157Sbostic
shoot_self()71684689157Sbostic shoot_self()
71784689157Sbostic {
71884689157Sbostic (void)printf(
71984689157Sbostic "\n*Thwack!* A sudden piercing feeling informs you that the ricochet\n\
72084689157Sbostic of your wild arrow has resulted in it wedging in your side, causing\n\
72184689157Sbostic extreme agony. The evil Wumpus, with its psychic powers, realizes this\n\
72284689157Sbostic and immediately rushes to your side, not to help, alas, but to EAT YOU!\n\
72384689157Sbostic (*CHOMP*)\n");
72484689157Sbostic }
72584689157Sbostic
jump(where)72684689157Sbostic jump(where)
72784689157Sbostic int where;
72884689157Sbostic {
72984689157Sbostic (void)printf(
73084689157Sbostic "\nWith a jaunty step you enter the magic tunnel. As you do, you\n\
73184689157Sbostic notice that the walls are shimmering and glowing. Suddenly you feel\n\
73284689157Sbostic a very curious, warm sensation and find yourself in room %d!!\n", where);
73384689157Sbostic }
73484689157Sbostic
pit_kill()73584689157Sbostic pit_kill()
73684689157Sbostic {
73784689157Sbostic (void)printf(
73884689157Sbostic "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
73984689157Sbostic The whistling sound and updraft as you walked into this room of the\n\
74084689157Sbostic cave apparently wasn't enough to clue you in to the presence of the\n\
74184689157Sbostic bottomless pit. You have a lot of time to reflect on this error as\n\
74284689157Sbostic you fall many miles to the core of the earth. Look on the bright side;\n\
74384689157Sbostic you can at least find out if Jules Verne was right...\n");
74484689157Sbostic }
74584689157Sbostic
pit_survive()74684689157Sbostic pit_survive()
74784689157Sbostic {
74884689157Sbostic (void)printf(
74984689157Sbostic "Without conscious thought you grab for the side of the cave and manage\n\
75084689157Sbostic to grasp onto a rocky outcrop. Beneath your feet stretches the limitless\n\
75184689157Sbostic depths of a bottomless pit! Rock crumbles beneath your feet!\n");
752957a0273Smckusick }
753