Hunt the Wumpus: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add python implementation of wumpus game)
m (Add complete cave, add example run)
Line 242: Line 242:
=={{header|Python}}==
=={{header|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. If you have python installed, you can copy this script into your favorite text editor and save it as wumpus.py. To run the script open a command prompt and enter "python path/to/wumpus.py".
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>
<lang python>
Line 252: Line 252:
def __init__(self, edges=[]):
def __init__(self, edges=[]):
# Given a list of edges, the cave is calculated via:
# 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:
if edges:
cave = {}
cave = {}
N = len(edges)
N = max([edges[i][0] for i in range(len(edges))])
for i in range(20):
for i in range(N):
exits = [edges[k][1] for k in range(20) if edges[k][0] == i]
exits = [edge[1] for edge in edges if edge[0] == i]
cave[i] = exits
cave[i] = exits


# Else, play in the standard cave.
# Else, play in the standard cave: a dodecahedron
else:
self.cave = {1: [2,3,4], 2: [1,5,6], 3: [1,7,8], 4: [1,9,10], 5:[2,9,11],
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],
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],
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
15: [8,13,19], 16: [8,13,19], 17: [8,13,19], 18: [8,13,19],
19: [8,13,19], 20: [8,13,19]}


self.threats = {}
self.threats = {}
Line 360: Line 363:
# If he shoots into another room, the Wumpus has a 75% of chance of waking up and moving into an adjacent room.
# 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:
if random.random() < 0.75:
print("DEBUG: Wumpus moved.")
#print("DEBUG: Wumpus moved.")
for room_number, threat in self.threats.items():
for room_number, threat in self.threats.items():
if threat == 'wumpus':
if threat == 'wumpus':
Line 416: Line 419:
WG.gameloop()
WG.gameloop()
</lang>
</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>



=={{header|Ruby}}==
=={{header|Ruby}}==

Revision as of 17:10, 24 January 2019

Task
Hunt the Wumpus
You are encouraged to solve this task according to the task description, using any language you may know.
This task has been flagged for clarification. Code on this page in its current state may be flagged incorrect once this task has been clarified. See this page's Talk page for discussion.

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#

See Hunt_The_Wumpus/CSharp.

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

See Hunt_The_Wumpus/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.