Hunt the Wumpus
You are encouraged to solve this task according to the task description, using any language you may know.
Create a simple implementation of the classic textual game Hunt The Wumpus.
The rules are:
The game is set in a cave that consists of a 20 room labyrinth. Each room is connected to 3 other rooms (the cave is modeled after the vertices of a dodecahedron). The objective of the player is to find and kill the horrendous beast Wumpus that lurks in the cave.
The player has 5 arrows. If they run out of arrows before killing the Wumpus, the player loses the game.
In the cave there are:
- One Wumpus
- Two giant bats
- Two bottomless pits
If the player enters a room with the Wumpus, he is eaten by it and the game is lost.
If the player enters a room with a bottomless pit, he falls into it and the game is lost.
If the player enters a room with a giant bat, the bat takes him and transports him into a random empty room.
Each turn the player can either walk into an adjacent room or shoot into an adjacent room.
Whenever the player enters a room, he "senses" what happens in adjacent rooms. The messages are:
- Nearby Wumpus: "You smell something terrible nearby."
- Nearby bat: "You hear a rustling."
- Nearby pit: "You feel a cold wind blowing from a nearby cavern."
When the player shoots, he wins the game if he is shooting in the room with the Wumpus. If he shoots into another room, the Wumpus has a 75% of chance of waking up and moving into an adjacent room: if this is the room with the player, he eats him up and the game is lost.
AutoHotkey
See Hunt_The_Wumpus/AutoHotkey
C#
IS-BASIC
<lang IS-BASIC>100 PROGRAM "Wumpus.bas" 110 RANDOMIZE 120 NUMERIC RO(1 TO 20,1 TO 3),LO(1 TO 20),WPOS 130 LET ARROWS=5:LET L=1 140 CALL INIT 150 DO 160 PRINT :PRINT "You are in room";L 170 PRINT "Tunnels lead to ";RO(L,1);RO(L,2);RO(L,3) 180 IF MON(1) THEN PRINT "You smell something terrible nearby." 190 IF MON(2) OR MON(3) THEN PRINT "You hear a rustling." 200 IF MON(4) OR MON(5) THEN PRINT "You feel a cold wind blowing from a nearby cavern." 210 PRINT :PRINT "Shoot or move? (S-M)" 220 DO 230 LET K$=UCASE$(INKEY$) 240 LOOP UNTIL K$="S" OR K$="M" 250 IF K$="M" THEN ! Move 260 INPUT PROMPT "No. of rooms: ":I$ 270 LET I=VAL(I$) 280 IF CHK(I) THEN 290 LET L=I 300 ELSE 310 PRINT "Not possibile." 320 END IF 330 ELSE ! Shoot 340 INPUT PROMPT "Where? ":I$ 350 LET I=VAL(I$) 360 IF CHK(I) THEN 370 IF LO(I)=1 THEN 380 PRINT "You kill the Monster Wumpus.":PRINT "You win.":EXIT DO 390 ELSE 400 PRINT "Arrows aren't that crooked - Try another room." 410 IF RND(4)<3 THEN 420 PRINT "You woke the Wumpus and he moved." 430 LET LO(WPOS)=0:LET WPOS=RO(WPOS,RND(2)+1):LET LO(WPOS)=1 440 END IF 450 LET ARROWS=ARROWS-1 460 IF ARROWS=0 THEN PRINT "You ran out of arrows.":EXIT DO 470 END IF 480 ELSE 490 PRINT "Not possibile." 500 END IF 510 END IF 520 SELECT CASE LO(L) 530 CASE 1 540 PRINT "You eaten by Wumpus.":EXIT DO 550 CASE 2,3 560 PRINT "A giant bat takes you in another room.":LET I=L 570 DO 580 LET L=RND(19)+1 590 LOOP UNTIL I<>L 600 CASE 4,5 610 PRINT "You fall into a bottomless pit.":EXIT DO 620 CASE ELSE 630 END SELECT 640 LOOP 650 DEF MON(X)=X=LO(RO(L,1)) OR X=LO(RO(L,2)) OR X=LO(RO(L,3)) 660 DEF CHK(X)=X=RO(L,1) OR X=RO(L,2) OR X=RO(L,3) 670 DEF INIT 680 TEXT 40 690 PRINT "Hunt the Wumpus";CHR$(241) 700 FOR I=1 TO 20 ! Create the cave 710 LET LO(I)=0 720 FOR J=1 TO 3 730 READ RO(I,J) 740 NEXT 750 NEXT 760 LET WPOS=RND(19)+2:LET LO(WPOS)=1 770 FOR I=2 TO 5 780 DO 790 LET T=RND(19)+2 800 LOOP UNTIL LO(T)=0 810 LET LO(T)=I 820 NEXT 830 END DEF 840 DATA 2,6,5,3,8,1,4,10,2,5,2,3,1,14,4,15,1,7,17,6,8,7,2,9,18,8,10,9,3,11 850 DATA 19,10,12,11,4,13,20,12,14,5,11,13,6,16,14,20,15,17,16,7,18,17,9,19,18,11,20,19,13,16</lang>
Java
See Hunt_The_Wumpus/Java.
JavaScript
See Hunt_The_Wumpus/Javascript.
M2000 Interpreter
For Windows only (in Linux you hear nothing, using Wine 3.6): In Sense() you can change Print with Speech so you Hear your sense;
<lang M2000 Interpreter> Module WumpusGame {
Print "Game: Hunt The Wumpus" Arrows=5 Dim Room(1 to 20) Room(1)=(2,6,5),(3,8,1),(4,10,2),(5,2,3),(1,14,4) Room(6)=(15,1,7),(17,6,8),(7,2,9),(18,8,10),(9,3,11) Room(11)=(19,10,12),(11,4,13),(20,12,14),(5,11,13), (6,16,14) Room(16)=(20,15,17),(16,7,18),(17,9,19),(18,11,20),(19,13,16) Enum Things {EmptyRoom, Bat1, Bat2, Pit1, Pit2, Wumpus} Dim Content(1 to 20)=EmptyRoom i=each(Things,2) ' from 2 to End While i { r=random(1,20) if Content(r)<>EmptyRoom then restart Content(r)=Eval(i) } WumpusPos=r PlayerPos=-1 TranspotPlayer() Done=False \\ Help is statement but here used as variable Help=False While Arrows>0 And Not Done { Sense() Print "W- Walk, T - Throw Arrow, G - Give up or H for Help" a$=Ucase$(Key$) If a$="W" Then { Print "Choose Tunnel to Walk: 1, 2 or 3" r=Val("0"+Key$)-1 if r>=0 and r<=2 then { PlayerPos=Array(room(PlayerPos), r) Select Case Content(PlayerPos) Case Wumpus Eaten() Case Pit1, Pit2 { Arrows=0 Print "You fall to a bottomless pit;" } Case Bat1, Bat2 { Print "A giant bat takes you in another room;" TranspotPlayer() } End Select } } Else.if a$="T" Then { Arrows-- Print "Choose Tunnel to Throw Arrow: 1, 2 or 3" r=Val("0"+Key$)-1 if r>=0 and r<=2 then { i=room(PlayerPos) If Content(Array(i, r))=Wumpus then { Done=True } Else.if random(1,4)<4 then WakeWumpus() } } Else.if a$="G" Then { Arrows=0 } Else.if a$="H" Then Help~ } If Done then Print "You kill the Monster Wumpus; You Win.": Exit Print "You loose." Sub TranspotPlayer() local r=random(1,20) While Content(r)<>EmptyRoom {r=random(1,20)} PlayerPos=r End Sub Sub WakeWumpus() local j=array(room(WumpusPos),random(0,2)) If content(j)=EmptyRoom Then { swap content(j), content(WumpusPos) WumpusPos=j If WumpusPos=PlayerPos then Eaten() } End Sub Sub Eaten() Arrows=0 Print "You eaten by Wumpus;" End Sub Sub Sense() local k=Room(PlayerPos) local j=each(k), Wumpus_near, bat_near, pit_near If Help then Print "Player Room:";PlayerPos, "Wumpus Room:";WumpusPos While j { If Help Then Print "Tunnel:";j^+1, "Room:";Array(j), "Content:";eval$(content(array(j))) Select Case content(array(j)) Case Bat1, Bat2 bat_near=True Case Pit1, Pit2 pit_near=True Case Wumpus Wumpus_near=True End Select } If Wumpus_near Then Print "You smell something terrible nearby." If bat_near Then Print "You hear a rustling." if pit_near Then Print "You feel a cold wind blowing from a nearby cavern." End Sub
} WumpusGame
</lang>
Perl 6
Phix
See Hunt_The_Wumpus/Phix.
Python
This implementation of "Hunt the Wumpus" follows the set of rules at the top of this site. It uses python 3 syntax and the standard library random.
<lang python> import random
class WumpusGame(object):
def __init__(self, edges=[]):
# Create arbitrary caves from a list of edges. # E.g.: edges = [[1,2], [1,3], [1,4], [2,1], [2,5], [2,6], [3,1], ...] if edges: cave = {} N = max([edges[i][0] for i in range(len(edges))]) for i in range(N): exits = [edge[1] for edge in edges if edge[0] == i] cave[i] = exits
# Else, play in the standard cave: a dodecahedron else: cave = {1: [2,3,4], 2: [1,5,6], 3: [1,7,8], 4: [1,9,10], 5:[2,9,11], 6: [2,7,12], 7: [3,6,13], 8: [3,10,14], 9: [4,5,15], 10: [4,8,16], 11: [5,12,17], 12: [6,11,18], 13: [7,14,18], 14: [8,13,19], 15: [9,16,17], 16: [10,15,19], 17: [11,20,15], 18: [12,13,20], 19: [14,16,20], 20: [17,18,19]}
self.cave = cave
self.threats = {}
self.arrows = 5
self.player_pos = -1
def get_safe_rooms(self): return list(set(self.cave.keys()).difference(self.threats.keys()))
def print_warning(self, threat): """ Called when entering a new room. Shows threats in adjacent rooms. """ if threat == 'bat': print("You hear a rustling.") elif threat == 'pit': print("You feel a cold wind blowing from a nearby cavern.") elif threat == 'wumpus': print("You smell something terrible nearby.")
def populate_cave(self):
""" Drop player and threats into random rooms in the cave.
"""
for threat in ['bat', 'bat', 'pit', 'pit', 'wumpus']:
pos = random.choice(self.get_safe_rooms())
self.threats[pos] = threat
self.player_pos = random.choice(self.get_safe_rooms())
def get_players_input(self):
""" Queries input until valid input is given.
"""
while 1:
inpt = input("Your turn: ")
try:
choice = int(inpt)
assert -1 < choice < 10
return choice
except (ValueError, AssertionError):
print("Please enter an integer between 1 and 3 for exiting the room, or between 4 and 6 to shoot into adjacent rooms.")
def enter_room(self, room_number):
""" Controls the process of entering a new room.
"""
print("Entering room {}...".format(room_number))
# Maybe a threat waits in the new room.
if self.threats.get(room_number) == 'bat':
# The bat teleports the player to random empty room
print("You encounter a bat, it transports you to a random empty room.")
new_pos = random.choice(self.get_safe_rooms())
return self.enter_room(new_pos)
elif self.threats.get(room_number) == 'wumpus':
print("Wumpus eats you.")
return -1
elif self.threats.get(room_number) == 'pit':
print("You fall into a pit.")
return -1
# The room is safe; collect information about adjacent rooms. for i in self.cave[room_number]: self.print_warning(self.threats.get(i))
# Only if nothing else happens, the player enters the room of his choice. return room_number
def shoot_room(self, room_number):
""" Controls the process of shooting in a room.
"""
print("Shooting an arrow into room {}...".format(room_number))
# Fire an arrow and see if something is hit by it.
self.arrows -= 1
threat = self.threats.get(room_number)
if threat in ['bat', 'wumpus']:
del self.threats[room_number]
if threat == 'wumpus':
print("Hurra, you killed the wumpus!")
return -1
elif threat == 'bat':
print("You killed a bat.")
elif threat in ['pit', None]:
print("This arrow is lost.")
return self.player_pos
# If this was your last arrow and it did not hit the wumpus... if self.arrows < 1: print("Your quiver is empty.") return -1
# If he shoots into another room, the Wumpus has a 75% of chance of waking up and moving into an adjacent room. if random.random() < 0.75: #print("DEBUG: Wumpus moved.") for room_number, threat in self.threats.items(): if threat == 'wumpus': wumpus_pos = room_number new_pos = random.choice(self.cave[wumpus_pos]) del self.threats[room_number] self.threats[new_pos] = 'wumpus' # If wumpus enters players room, he eats him imediately. if new_pos == self.player_pos: print("Wumpus enters your room and eats you!") return -1
def gameloop(self):
print("Welcome to the wumpus game!") print("===========================") print() self.populate_cave() self.enter_room(self.player_pos)
while 1:
print("You are in room {}.".format(self.player_pos), end=" ") print("Adjacent rooms are {}.".format(self.cave[self.player_pos]))
# Player's turn to chose exit or shoot. inpt = self.get_players_input() print() if inpt in [1,2,3]: target = self.cave[self.player_pos][inpt-1] self.player_pos = self.enter_room(target) elif inpt in [4,5,6]: target = self.cave[self.player_pos][inpt%4] self.player_pos = self.shoot_room(target) elif inpt == 7: print("Your quiver holds {} arrows.".format(self.arrows)) elif inpt == 8: print("Rooms with no threats are: {}.".format(self.get_safe_rooms())) elif inpt == 9: print("Threats are located in the following rooms: {}".format(self.threats)) elif inpt == 0: print("You give up.".format(self.threats)) self.player_pos = -1 # If player encountered a deadly threat or his quiver is empty, then the players position will be -1. if self.player_pos == -1: break
print() print("Game over!")
if __name__ == '__main__':
WG = WumpusGame()
WG.gameloop()
</lang>
Example run (on a windows system):
<lang cmd> C:\Users\myusername>python D:\Workspace\rosettacode\wumpus.py Welcome to the wumpus game!
===============
Entering room 12...
You hear a rustling. You are in room 12. Adjacent rooms are [6, 11, 18]. Your turn: 2
Entering room 11...
You are in room 11. Adjacent rooms are [5, 12, 17]. Your turn: 3
Entering room 17...
You are in room 17. Adjacent rooms are [11, 20, 15]. Your turn: 2
Entering room 20...
You are in room 20. Adjacent rooms are [17, 18, 19]. Your turn: 3
Entering room 19...
You smell something terrible nearby. You are in room 19. Adjacent rooms are [14, 16, 20]. Your turn: 4
Shooting an arrow into room 14...
This arrow is lost. You are in room 19. Adjacent rooms are [14, 16, 20]. Your turn: 5
Shooting an arrow into room 16...
Hurra, you killed the wumpus!
Game over! C:\Users\myusername>exit
</lang>
Ruby
See Hunt_The_Wumpus/Ruby.