Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Hunt the Wumpus - 1972 by Gregory Yob
- # -------------------------------------
- # rerewritten half a century later by Nele Abels as a Python coding exercise
- import random
- # the game data is stored in this array
- game = [0,0,0,0,0,0,0]
- # the save array is used to restart a game with the same settings
- save = game[:]
- # the following variables are just use to make access to the game array more transparent
- player = 0 # in which room is the player?
- wumpus = 1 # in which room is the wumpus?
- bat1 = 2 # in first bat room
- bat2 = 3 # in second bat room
- pit1 = 4 # in first pit room
- pit2 = 5 # in second pit room
- arrows = 6 # in number of arrows left
- # The tunnels in the original Wumpus were hard coded. Yob's reasoning was that
- # this would encourage the player to draw maps and play strategically
- rooms = [
- [0,0,0], # dummy room; Yob's game map started with room 1
- [2,5,8], # room 1
- [1,3,10], # " 2
- [2,4,12], # " 3
- [3,5,14], # " 4
- [1,4,6], # " 5
- [5,7,15], # " 6
- [6,8,17], # " 7
- [1,7,9], # " 8
- [8,10,18], # " 9
- [2,9,11], # " 10
- [10,12,19], # " 11
- [3,11,13], # " 12
- [12,14,20], # " 13
- [4,13,15], # " 14
- [6,14,16], # " 15
- [15,17,20], # " 16
- [7,16,18], # " 17
- [9,17,19], # " 18
- [11,18,20], # " 19
- [13,16,19]] # " 20
- def instructions():
- print("\n\nThe Wumpus lives in a cave of 20 rooms. Each room has three tunnels")
- print("leading to other rooms. (Look at a dodecahedron to see how this works -")
- print("if you don't know what a dodecahedron is, ask someone.")
- print("[Or look at a twenty sided die, Nele]")
- print()
- print("Hazards:")
- print()
- print("Bottomless pits - two rooms have bottomless pits in them. If you go there,")
- print("you fall into the pit (and lose!)")
- print("Superbats - two other rooms have super bats. If you go there, a bat grabs")
- print("you and takes you to some other room at random. (Which might be troublesome.)")
- print("\nPress <Return>",end="")
- input()
- print("\nWumpus:")
- print()
- print("The Wumpus is not bothered by the Hazards (he has sucker feet and is too big")
- print("for a bat to lift.) Usually he is asleep. Two things wake him up: your entering")
- print("his room or your shooting an arrow.")
- print("If the Wumpus wakes, he move with a 75% chance to a next room or he stays still")
- print("(25% chance). After that, if he is where you are, he eats you up and you lose.")
- print()
- print("You:")
- print()
- print("Each turn you may move or shoot a crooked arrow.")
- print("Moving: you can go one room through one of the tunnels.")
- print("Arrows: you have five arrows. You lose when you run out.")
- print("Each arrow can go from one to five rooms. You aim by telling the computer the")
- print("rooms you want the arrow to go.")
- print("If the arrow can't go that (i.e. no tunnel) it moves at random to the next room.")
- print(" If the arrow hits the wumpus, you win.")
- print(" If the arrow hits you, you lose.")
- print("\nPress <Return>",end="")
- input()
- print("\nWarnings:")
- print()
- print("When you are one room away from the Wumpus or a hazard, the computer says:")
- print(" Wumpus - 'I smell a Wumpus'")
- print(" Superbat - 'Bats nearbay'")
- print(" pit - 'I feel a draft'\n")
- print("[Nele says: 'Good hunting!']")
- # init_cave() first creates a temporary array with five random numbers between 1 and 20. Then
- # it compares each array entry with the other entries to see if numbers are identical, e.g. if
- # the location of the wumpus is set to the location of the player. If that is the case, the
- # randomization is repeated.
- def init_cave():
- tmp = [0,0,0,0,0,0,0]
- fertig = False
- while (fertig == False):
- for i in range(0,6):
- tmp[i] = random.randint(1,20)
- fertig = True
- for i in range(0,6):
- for j in range(0,6):
- if (i != j) and (tmp[i] == tmp[j]): # one of the values is double, we are not finished
- fertig = False
- tmp[6] = 5 # the number of arrows is always 5
- return tmp
- # describe_room() just prints out the room number, the exits and the warnings. It does not write to
- # any variables
- def describe_room():
- # use of local variables to make the code more readable
- pl = game[player]
- wm = game[wumpus]
- b1 = game[bat1]
- b2 = game[bat2]
- p1 = game[pit1]
- p2 = game[pit2]
- print("\nI am in cave no. {}.".format(game[player]))
- # I don't use elif because then you could conclude from the order of the warnings
- # the room in which the danger lurks
- for i in range(0,3):
- if rooms[pl][i] == wm:
- print("I smell a Wumpus.")
- bat_found = False # used to prevent double warning of bats
- for i in range(0,3):
- if ((rooms[pl][i] == b1) or (rooms[pl][i] == b2)) and (bat_found == False):
- print("Bats nearby.")
- bat_found = True
- pit_found = False # used to prevent double warning of pits
- for i in range(0,3):
- if (rooms[pl][i] == p1) or (rooms[pl][i] == p2) and (pit_found == False):
- print("I feel a draft.")
- pit_found = True
- print("Exits go to caves no. {}, {}, and {}.\n".format(rooms[pl][0],rooms[pl][1],rooms[pl][2]))
- # input_number(min,max) asks for a numerical input between a minimum and a maximum. The loop
- # runs until a correct input is given.
- def input_number(minimum, maximum):
- fertig = False
- while (fertig == False):
- ein = input()
- if ein.isnumeric():
- number = int(ein)
- if (number > minimum-1) and (number < maximum + 1):
- fertig = True
- return number
- # input_yesno() asks for "y" or "n" as an answer (lower case as well as upper case)
- def input_yesno():
- fertig = False
- while (fertig == False):
- ein = input().lower()
- if (ein == "y") or (ein == "n"):
- fertig = True
- return ein
- # input_moveshoot() asks for "m" for "move" or "s" for shoot and doesn't accept anything else.
- def input_moveshoot():
- fertig = False
- while (fertig == False):
- print("Move or shoot (m/s)? ",end="")
- ein = input().lower()
- if (ein == "m") or (ein == "s"):
- fertig = True
- return ein
- # shoot_arrow() is the original shoot algorithm as devised by Yob. It is not very good.
- # the function returns:
- # 0 - missed, nothing happened
- # 1 - Wumpus was hit, game won
- # -1 - either player shot himself or was eaten by Wumpus. Game lost.
- def shoot_arrow():
- global game # the Wumpus may wander around and the game data must be changed
- # Step 1: player enters the path of the arrow
- game[arrows] = game[arrows]-1
- target = [] # this list will containt the room numbers
- print("\nHow many rooms (1-5)? ",end="")
- rng = input_number(1,5)
- # last_ein and ein are used to see if a target room is entered twice, i.e. the player
- # wants the arrow to do a 180° turn. Yob's original code is (probably) buggy since
- # it compares the target with the penultimate target, i.e. it is possible to shoot
- # yourself deliberately.
- last_ein = game[player] # the arrow obviously starts at the player's position
- print("\nIn which rooms should the arrow go (1-20)? ")
- for i in range(1,rng+1):
- fertig = False
- while fertig == False:
- fertig = True
- print("#{}: ".format(i),end="")
- ein = input_number(1,20)
- if ein == last_ein:
- print("\nThe arrow isn't that crooked. It cannot turn around in midair.")
- fertig = False
- else:
- target.append(ein)
- last_ein = ein # choice was ok. ein is entered as new last entry
- # Step 2: arrow flies through the cave
- a_pos = game[player] # a_pos is used to determine if next target is possible
- for i in range(len(target)):
- # is the target reachable from the current position of the arrow?
- if (rooms[a_pos][0] == target[i]) or (rooms[a_pos][1] == target[i]) or (rooms[a_pos][2] == target[i]):
- a_pos = target[i]
- else:
- # no way to reach the target, the arrow goes into a random exit.
- a_pos = rooms[a_pos][random.randint(0,2)]
- # arrow hit wumpus or player? -> game over
- if a_pos == game[wumpus]:
- print("Aha! I got the Wumpus.")
- return 1
- elif a_pos == game[player]:
- print("Ouch! Arrow got me.")
- return -1
- # Step 3: Wumpus moves (and perhaps eats player) with 75% if the game is not over
- # In Yob's algorithm, the Wumpus could move into rooms with bats and a pit.
- if random.randint(1,100) < 76:
- game[wumpus] = rooms[game[wumpus]][random.randint(0,2)]
- # Step 4: Does the Wumpus stumble onto the player? Are the arrows used up?
- if (game[player] == game[wumpus]):
- print("Tsk, tsk, tsk. The Wumpus got me.")
- return -1
- elif (game[arrows] == 0):
- print("I have run out of arrows. I can go home, now.")
- return -1
- return 0 # arrow has just landed somewhere and nothing special happened
- # move_player() manages player movement. The player can die by falling into a pit or
- # stumble into the Wumpus and be eaten. The function returns:
- # 0 - nothing happened, game goes on
- # -1 - player died, game over
- def move_player():
- global game # may have to be changed because the Wumpus moves
- # use of local variables to make the code more readable
- pl = game[player]
- wm = game[wumpus]
- b1 = game[bat1]
- b2 = game[bat2]
- p1 = game[pit1]
- p2 = game[pit2]
- fertig = True
- # Step 1: Enter the next movement and check if there is a way. If yes, move player
- fertig = False
- while fertig == False:
- print("\nWhere do you want to go (1-20)? ",end="")
- next_room = input_number(1,20)
- for i in range(0,3):
- if rooms[pl][i] == next_room:
- fertig = True
- if fertig == False:
- print("There is no exit in that direction.")
- else:
- game[player] = next_room
- pl = next_room
- # Step 2: Check if pits, bats or Wumpus are in the new room. I have put the whole
- # part in a loop because Yob's algorithm explicitely allows the bats to drop the
- # player into rooms with bats, pits, or the Wumpus.
- fertig = False
- bat_transport = False # player has been carried away by bats
- while fertig == False:
- if (pl == b1) or (pl ==b2): # Bats?
- print("ZAPP! A Super Bat snatches me and carries me elsewhere.")
- pl = random.randint(1,20)
- game[player] = pl
- bat_transport = True
- elif (pl == p1) or (pl == p2): # Pits?
- print("YYYYYIIIIEEEE... fell in pit.")
- return -1 # death, game over
- elif pl == wm: # Wumpus?
- print("Oops! I bumped into the Wumpus.")
- wumpus_moves = random.randint(1,4)
- if wumpus_moves in [0,1,2]:
- print("The Wumpus scurries off...")
- wm = rooms[wm][wumpus_moves]
- game[wumpus] = wm
- return 0 # lucky fuck. Game goes on.
- else:
- print("The Wumpus got me!")
- return -1 # death, game over
- else:
- if bat_transport == False: # only print when player walked on their own feet
- print("I carefully move through the tunnel...")
- return 0 # nothing remarkable happened
- ##############################################################################
- # Main program
- ##############################################################################
- print("\n\nHunt the Wumpus\n---------------")
- print("1972 by Gregory Yob, 2022 by Nele Abels\n")
- print("Do you want to read the instructions? ",end="")
- if input_yesno() == "y":
- instructions()
- game = init_cave()
- save = game[:]
- game_over = False
- while game_over == False:
- # Main game loop until player or Wumpus is dead
- gamestate = 0 # 1 - game won, -1 - game lost
- while gamestate == 0:
- describe_room() # Normal room description
- if input_moveshoot() == "m":
- gamestate = move_player()
- else:
- gamestate = shoot_arrow()
- # Play again?
- print("\nGame over.\n")
- print("Do you want to play again (y/n)? ",end="")
- again = input_yesno()
- if again == "n":
- print("Bye...")
- game_over = True
- else:
- print("Do you want to use the same game map (y/n)? ",end="")
- newgame = input_yesno()
- if newgame == "y":
- print("Restoring game...")
- game = save[:]
- game_over = False
- else:
- print("Setting up new game...")
- game = init_cave()
- save = game[:]
- game_over = False
Add Comment
Please, Sign In to add comment