Created
April 3, 2014 03:12
-
-
Save anonymous/9947656 to your computer and use it in GitHub Desktop.
A Solution to /r/dailyprogrammer challenge 154[Hard]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 "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