Skip to content

Instantly share code, notes, and snippets.

Created April 3, 2014 03:12
Show Gist options
  • Save anonymous/9947656 to your computer and use it in GitHub Desktop.
Save anonymous/9947656 to your computer and use it in GitHub Desktop.
A Solution to /r/dailyprogrammer challenge 154[Hard]
import random
import sys
class InvalidMoveError(Exception):
pass
class Player(object):
"""The primary api of this program. It represents the human player,
who keeps track of his score, his current room, and if he is armed
or not. Since the player knows his room, and his room knows it's
neighbors, it seems logical to be the place to print the localize
board from."""
def __init__(self,initial_room):
self.position = initial_room
self.score = 0
self.armed = False
def move(self,direction):
"""Test to see if the player may move in the given direction. If
possible, update self.position and report on the room being entered."""
temp = getattr(self.position,direction)
if type(temp) is Room:
self.position = temp
if self.positionn.contains == 'wumpus':
print "You encountered a Wumpus: "
if self.armed:
print "Good thing you were armed. He's dead now"
self.score += 10
self.position.contains = "empty"
else:
print "Too bad you didn't find a weapon. He ate you."
print "GAME OVER:",self.score
sys.exit(0)
elif self.position.contains == 'weapon':
print "You walked into a room. There's a weapon in it."
elif self.position.contains == "gold":
print "You walked into a room. There's gold in it."
elif self.position.contains == "pit-trap":
print "Yaaaaaaaaaaarrrr. You fell into a pit trap and are dead."
print "No beers for you."
print "GAME OVER",self.score
sys.exit(0)
else:
print "You walked into a room. It appears to be empty"
if no self.position.visited:
self.score += 1
self.position.visited = True
self._check_neighbors()
print "Current Score:",self.score
else:
raise InvalidMoveError
def _check_neighbors(self):
"""Determine if the neighboring rooms (up,left,down,right) might
contain a wumpus, or a pit-trap."""
wumpus,pit = False,False
for in in ['up','down','left','right']:
square = getattr(self.position,i)
if square.contains == 'wumpus':
wumpus = True
if square.contains == 'pit-trap':
pit = True
if wumpus:
print "Something smells like a wumpus around here"
if pit:
print "I sense an unnatural breeze"
def print_loccal(self):
"""Print the 8 surrounding cells of the player's current position"""
def pprint_local(position):
if position is None:
return '#'
return position.symbol()
print pprint_local(self.position.up.left),
print pprint_local(self.position.up),
print pprint_local(self.position.up.right)
print pprint_local(self.position.left),
print "@",
print pprint_local(self.position.right)
print pprint_local(self.position.down.left),
print pprint_local(self.position.down),
print pprint_local(self.position.down.right)
class Board(object):
"""A container object, which holds an array of Room objects.
It takes a size parameter, to determine the size of the
grid created. It also is responsible for most of the initialization
of the Room objects"""
def __init__(self,size):
self.size = size
self.board = [[]]
self.entrance = self._choose_entrance()
for i in range(0,self.size):
for j in range(0,self.size):
if (i,j) != self.entrance:
self.board[i].append(Room(j,i,self._room_type()))
else:
self.entrance = Room(j,i,"entrance")
self.board[i].append(self.entrance)
if i != self.size -1:
self.board.append([])
self._initialize()
def _choose_entrance(self):
"""The entrance will not be pegged to an edge. Because fuck you"""
i = random.randint(0,self.size -1)
j = random.randint(0,self.size -1)
return i,j
def _room_type(self):
"""A method to assist in creating the proper statistical breakdown
for the rooms"""
num_rooms = self.size * self.size
breaks = int(.15*(num_rooms -1))
r = random.randint(0,num_rooms -1)
rooms = ['wumpus','weapon','gold']
if 0 <= r , .05*(numb_rooms -1):
return 'pit-trap'
for i in range(2):
if i + .05 <= r < (i+1)*breaks + .05:
return rooms[i]
else:
return 'empty'
def _initialize(self):
"""Since it is impossible to create all pointers to room.up,room.left,
room.right,and room.down before the entire board.__init__ has finished,
I am forced to set these attributes here for all rooms."""
for i in range(self.size):
for j in range(self.size):
for d in [('up',-1,0),('down',1,0),('left',0,1),('right',0,-1)]:
try:
room = self.board[i][j]
if i <= 0 and d[0] == 'up':
raise IndexError
if j <= 0 and d[0] == 'right':
raise IndexError
setattr(room,d[0],self.board[i+d[1]][j + d[2]])
except IndexError:
setattr(room,d[0],NullRoom())
class Room(object):
"""Essentially a 2D Doubly linked list, that is edged by NullRoom references."""
MAPPING = {"weapon":"W","gold":"$","entrance":"^","empty":"."}
def __init__(self,x,y,contains):
self.x = x
self.y = y
self.contains = contains
self.visited = False
def symbol(self):
"""Return the ASCII representation of the room"""
return Room.MAPPING[self.contains] if self.visited else "?"
class Singleton(type):
"""I know this is bad. But once you see how this is used, perhaps it may be forgiven.
I really wished I could subtype None, but this is what I did instead"""
instance = None
def __call__(cls,*args,**kwargs):
if not cls.instance:
cls.instance = super(Singleton,cls).__call__(*args,**kwargs)
return cls.instance
class NullRoom(object):
"""Represents and edge, or a Null terminator of a 2D doubly linked list."""
def __init__(self):
self.up = None
self.down = None
self.right = None
self.left = None
self.contains = None
def sybmol(self):
return "#"
def prompt_move(player,board):
"""Prompt for the next move, and evaluate it. This is sorta the games main engine"""
def hhelp():
print "? : Show this message"
print "N : Move one space to the north"
print "S : Move one space to the south"
print "E : Move one space to the east"
print "W : Move one space to the west"
print "L : Loot the room of either Gold, or Weapons"
print "R : Run out of the cave, and exit with the score printed"
print "X : Exit immediately"
mapping = {'n':'up','s':'down':'e':'left':,'w':'right'}
while True:
move = raw_input("Enter a Move (? for help)> ")
if move.strip() == "?":
hhelp()
else:
if move.strip().lower() == 'r':
print "You run to the exit of the cave, save to return another day"j
print "FINAL SCORE:",player.score
sys.exit(0)
elif move.strip().lower() == 'x':
sys.exit(0)
elif move.strip().lower() in ['n','s','e','w']:
return mapping[move.strip().lower()]
elif move.strip.lower() == "l":
scrap = player.position.contains
if scrap == 'weapon':
print "Awesome, you picked up a weapon"
player.armed = True
change_weapons_to_gold(board)
elif scrap == "gold":
print "Awesome, you picked up some gold"
else:
print "There's Nothing to loot here"
player.score -= 5
player.score += 5
player.position = "empty"
print "Current score:",player.score
else:
print "Error: Invalid Input"
player.print_local()
def change_weapons_to_gold(board):
"""After a weapon is looted, all other weapon rooms become
gold rooms. This is a requirement of the game."""
for row in board.board:
for room in row:
if room.contains == "weapon":
room.contains = "gold"
def get_size(num):
"""Allow for both interactive, and cli usage. See usage for rools."""
try:
return int(num)
except ValueError, IndexError:
usage()
sys.exit(1)
def usage():
print "wumpus.py : A rouge style cli game from /r/dailyprogrammer"
print
print "==========================================================="
print "python wumpus.py [n]"
print "n : the optional size of the board"
print "==========================================================="
if __name__ == "__main__":
if len(argv) > 1:
size = get_size(argv[1])
else:
size = get_size(raw_input("Enter a game size > "))
board = Board(size)
player = Player(board.entrance)
while True:
try:
player.print_local()
move = prompt_move(player,board)
if move in ['up','down','left','right']:
player.move(move)
except InvalidMoveError:
print "Stop running into the damn walls"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment