Last active
December 11, 2015 20:19
-
-
Save KGZM/4654649 to your computer and use it in GitHub Desktop.
Sequel to textgame.py:
Intrigued by python I decided to take the text game idea a little further. Added server things and multiuser mode. Just experimenting. (I have no idea how to rename a multifile gist or reorder it, so the files are in alphabetical order not in a semantic order.)
This file contains 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
class Message(object): | |
def __init__(self, string): | |
self.breakdown = [] | |
self.tokens = {} | |
for part in string.split('{'): | |
self.breakdown.extend(part.split('}')) | |
for i, part in enumerate(self.breakdown): | |
if i % 2 == 1: | |
self.tokens[part] = self.breakdown[i] = Token(name=part) | |
else: | |
self.breakdown[i] = Token(string=part, evaluated=True) | |
def format(self, **kwargs): | |
for key, value in kwargs.iteritems(): | |
if key in self.tokens: | |
self.tokens[key].sub(value) | |
return self | |
def __str__(self): | |
return ''.join(str(token) for token in self.breakdown) | |
def __repr__(self): | |
return '"' + ''.join(repr(token) for token in self.breakdown) + '"' | |
class Token(object): | |
def __init__(self, name=None, string=None, evaluated=False): | |
self.name = name | |
self.string = string | |
self.evaluated = evaluated | |
def sub(self,value): | |
self.string = str(value) | |
self.evaluated = True | |
def __repr__(self): | |
if self.name is not None: | |
return "{%s: %s}" % (self.name,self.string) | |
else: | |
return self.string | |
def __str__(self): | |
if self.evaluated: | |
return self.string | |
else: | |
return '' | |
def new(*args): | |
return Message(*args) |
This file contains 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 SocketServer | |
import space | |
import traceback | |
class UserHandler(SocketServer.StreamRequestHandler): | |
def setup(self): | |
SocketServer.StreamRequestHandler.setup(self) | |
print self.client_address, 'connected!' | |
self.request.send('hi ' + str(self.client_address) + '\n') | |
self.player = space.Player(conn=self.wfile) | |
def handle(self): | |
while 1: | |
data = self.rfile.readline().strip() | |
try: | |
self.player.parse_line(data) | |
except Exception as e: | |
self.player.hear("An error has occured: " + str(e)) | |
self.player.hear(traceback.format_exc()) | |
print traceback.format_exc() | |
if data == 'bye': | |
return | |
def finish(self): | |
print self.client_address, 'disconnected!' | |
self.request.send('bye ' + str(self.client_address) + '\n') | |
#server host is a tuple ('host', port) | |
SocketServer.TCPServer.allow_reuse_address = True | |
server = SocketServer.ThreadingTCPServer(('localhost', 5000), UserHandler) | |
server.serve_forever() |
This file contains 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
from collections import defaultdict | |
from compiler import compile | |
from message import Message | |
import operator | |
class Room(object): | |
def __init__(self, name="Nowhere",desc="Nothing to see here.", coords=(0,0)): | |
self.name = name | |
self.desc = desc | |
self.coords = Point(coords) | |
self.contents = set() | |
def display(self): | |
msg = Message("{name} {coords}\n{desc}\nContents: {contents}") | |
contents = ', '.join(str(thing) for thing in self.contents) | |
msg.format(name=self.name,coords=str(self.coords),desc=self.desc,contents=contents) | |
return msg | |
def emit(self, text, exclude=None): | |
for thing in self.contents: | |
if exclude is None or thing not in exclude: | |
thing.hear(text) | |
def get(self,thing): | |
self.contents.add(thing) | |
def drop(self,thing): | |
self.contents.discard(thing) | |
def __repr__(self): | |
return "(Room {0} at {1})".format(self.name,str(self.coords)) | |
class Player(object): | |
def __init__(self, name="John Doe", conn=None): | |
self.conn = conn | |
self.name = name | |
self.coords = Point(0,0) | |
self.local_context = {} | |
self.move_to(Point(0,0)) | |
def __str__(self): | |
return self.name | |
def command_look(self, arguments): | |
self.hear(self.location.display()) | |
def hear(self, msg): | |
self.conn.write(str(msg) + "\n") | |
def command_say(self, line): | |
msg = Message("{name} says, \"{line}\"") | |
msg.format(name=self.name,line=line) | |
self.location.emit(msg) | |
def command_quit(self, arguments): | |
msg = Message("*{name} quits.") | |
msg.format(name=self.name) | |
self.location.emit(msg) | |
self.hear("Bye") | |
exit() | |
def command_eval(self, arguments): | |
global_context = dict(me=self, here=self.location, space=space) | |
try: | |
result = eval(arguments, global_context, self.local_context) | |
except Exception as e: | |
result = e | |
self.hear("=> {0}".format(result)) | |
def command_exec(self, arguments): | |
global_context = dict(me=self, here=self.location, space=space) | |
try: | |
exec compile(arguments, "", "single") in global_context, self.local_context | |
except Exception as e: | |
self.hear("=> {0}".format(e)) | |
def move_to(self, new_coords): | |
space[self.coords].drop(self) | |
place = space[new_coords] | |
self.coords = new_coords | |
self.location = place | |
place.get(self) | |
self.hear(place.display()) | |
def run_command(self, command, arguments): | |
method = getattr(self, "command_" + command, None) | |
if method is not None: | |
method(arguments) | |
return True | |
else: | |
return False | |
def walk(self,direction): | |
outmsg = Message("{name} walks {direction}.") | |
inmsg = Message("{name} walks in.") | |
outmsg.format(name=self.name,direction=direction) | |
inmsg.format(name=self.name) | |
self.location.emit(outmsg, exclude=[self]) | |
self.move_to(self.coords + directions[direction]) | |
self.location.emit(inmsg, exclude=[self]) | |
def parse_line(self, line): | |
command, _, arguments = line.partition(' ') | |
if command in directions: | |
self.walk(command) | |
elif self.run_command(command, arguments): | |
pass | |
else: | |
self.hear("I don't get it.") | |
# Utility classes. | |
class keyinitdict(defaultdict): | |
"""dictionary that passes key to its factory function,""" | |
def __init__(self, *args): | |
defaultdict.__init__(self, *args) | |
def __missing__(self, key): | |
if self.default_factory is None: | |
raise KeyError((key,)) | |
self[key] = value = self.default_factory(key) | |
return value | |
class Point(tuple): | |
"""Point class with vector addition""" | |
def __new__(cls, *tup): | |
if tup[0].__class__ is not Point: | |
return super(Point, cls).__new__(cls, tup) | |
else: | |
return tup[0] | |
def __add__(self, other): | |
return self.__class__(*map(operator.add, self, other)) | |
space = keyinitdict(lambda coords: Room(coords=coords)) | |
directions = dict( | |
north=Point(0,1), | |
south=Point(0,-1), | |
east=Point(1,0), | |
west=Point(-1,0) | |
) | |
if __name__ == "__main__": | |
player = Player() | |
player.move_to(Point(0,0)) | |
while True: | |
line = raw_input("> ") | |
player.parse_line(line) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment