From 0df01ca7967f6152ab3ccad095eac338018c1a86 Mon Sep 17 00:00:00 2001 From: Nicholas Tollervey Date: Thu, 6 May 2010 17:56:09 +0100 Subject: [PATCH] Added week 6 starting state --- adventure/week6/README | 11 ++ adventure/week6/adventure.py | 297 ++++++++++++++++++++++++++++++++++ adventure/week6/commands.bays | 197 ++++++++++++++++++++++ adventure/week6/data.txt | 98 +++++++++++ adventure/week6/train.py | 34 ++++ 5 files changed, 637 insertions(+) create mode 100644 adventure/week6/README create mode 100755 adventure/week6/adventure.py create mode 100644 adventure/week6/commands.bays create mode 100644 adventure/week6/data.txt create mode 100644 adventure/week6/train.py diff --git a/adventure/week6/README b/adventure/week6/README new file mode 100644 index 0000000..6f19b33 --- /dev/null +++ b/adventure/week6/README @@ -0,0 +1,11 @@ +The starting state for week 6. Based upon work done in week 5. + +To make this work you need to run: + +easy_install reverend + +or download the source from here: + +http://www.divmod.org/trac/wiki/DivmodReverend + +Peter will provide a 5 minute lightning talk about DivmodReverend diff --git a/adventure/week6/adventure.py b/adventure/week6/adventure.py new file mode 100755 index 0000000..183d7ed --- /dev/null +++ b/adventure/week6/adventure.py @@ -0,0 +1,297 @@ +#!/usr/bin/python +import re +try: + from reverend.thomas import Bayes +except ImportError: + Bayes = None +from cmd import Cmd + +DIRECTIONS = 'N', 'E', 'S', 'W' +NORTH, EAST, SOUTH, WEST = DIRECTIONS + +all_item_names = {} + +class Player(object): + def __init__(self, location, name='Player'): + assert isinstance(location, Location) + self.location = location + self.name = name + self.items = {} + + def inventory(self): + if not self.items: + return "Your hands are empty!" + return "You are carrying: " + ", ".join(self.items) + + +class Location(object): + def __init__(self, name, description=""): + self.name = name + self.description = description + self.exits = {} + self.items = {} + + def __str__(self): + return self.name + + def add_direction(self, direction, other_location): + assert direction in DIRECTIONS + self.exits[direction] = other_location + + def describe(self): + out = '' + out += "Current location: %s\n%s\n" % (self.name, self.description) + out += "You can see: " + out += ", ".join(item.name + for item in self.items.itervalues() if not item.hidden) + out += "\n" + for direction, location in self.exits.iteritems(): + out += "\t%s (%s)\n" % (location, direction) + return out + + +class Item(object): + def __init__(self, name, description="", location=None): + self.name = name + self.description = description + self.location = location + self.aliases = [] + self.fixed = False + self.hidden = False + + def __str__(self): + return self.name + + def add_aliases(self, aliases): + self.aliases.extend(aliases) + + def describe(self): + return self.description + + + +sample_universe = """ +:Garage +You are in the garage. There are no cars here currently. +E:Bedroom +W:Kitchen + +:Kitchen +The kitchen is immaculate. You suspect that nobody has ever actually prepared any food here. +E:Garage + +""" + +def test_location(): + startroot = Location('Start room') + kitchen = Location('Kitchen') + startroot.add_direction(NORTH, kitchen) + +def test_player(): + lobby = Location('Lobby') + john = Player(lobby, 'John') + + +def find_item(items, name): + name = name.lower() + for item in items.itervalues(): + if name == item.name.lower() or name in item.aliases: + return item + return None + + +def load_universe(content): + location = first_location = None + item = None + locations = {} + items = {} + + for line in content: + line = line.strip() + if not line or line.startswith('#'): + continue + + if line.startswith(':'): + item = None + location = Location(line[1:]) + locations[line[1:]] = location + if not first_location: + first_location = location + elif line.startswith('*'): + location = None + item = Item(line[1:]) + items[line[1:]] = item + elif location is not None and not location.description: + location.description = line + elif location is not None: + direction, destination = line.split(':', 1) + location.add_direction(direction, destination) + elif item is not None and not item.location and not item.description: + item.location = line + elif item is not None and not item.description: + item.description = line + elif item is not None: + cmd, arg = line.split(':', 1) + if cmd == 'A': + item.add_aliases(s.strip().lower() for s in arg.split(',')) + elif cmd == "F": + item.fixed = arg + elif cmd == "H": + item.hidden = True + + for location in locations.itervalues(): + for direction, destination in location.exits.items(): + try: + location.add_direction(direction, locations[destination]) + except KeyError: + raise SystemError("Your universe file sucks! %s" % destination) + + for item in items.itervalues(): + location = locations[item.location] + location.items[item.name] = item + + all_item_names[item.name] = item.name + for alias in item.aliases: + all_item_names[alias] = item.name + + + return locations, first_location + + +class Game(Cmd): + + def __init__(self, gamefile, player_name): + Cmd.__init__(self) + self.locations, self.start_room = load_universe(file(gamefile)) + self.player = Player(self.start_room, player_name) + + + self.guesser = self._load_guesser() + if self.guesser is not None: + # check that you can guess that 'grab' aliases to 'take' + assert self.guesser.guess('grab') + + print self.player.location.describe() + + def _load_guesser(self): + if Bayes is None: + return None + guesser = Bayes() + guesser.load('commands.bays') + return guesser + + def do_move(self, direction): + direction = direction.upper() + + newroom = self.player.location.exits.get(direction,None) + if newroom == None: + print "No pass around!" + return + + self.player.location = self.player.location.exits[direction] + print self.player.location.describe() + + def do_go(self, direction): + return self.do_move(direction) + + def do_look(self, where): + if where == "": + print self.player.location.describe() + else: + # TODO validate where + target = self.player.location.exits.get(where.upper()) + if target: + print target.describe() + return + item = find_item(self.player.location.items, where) + if not item: + item = find_item(self.player.items, where) + if item: + print item.describe() + else: + print "You can't see", where + + def do_examine(self, where): + return self.do_look(where) + + def do_ex(self, where): + return self.do_look(where) + + def do_get(self, target): + item = find_item(self.player.location.items, target) + if item: + if item.fixed: + print item.fixed + return + del self.player.location.items[item.name] + self.player.items[item.name] = item + print "Taken", item.name + else: + print "You can't see", target + + def do_take(self, target): + return self.do_get(target) + + def do_drop(self, target): + item = find_item(self.player.items, target) + if item: + del self.player.items[item.name] + self.player.location.items[item.name] = item + print "Dropped", item.name + else: + print "You don't have", target + + def do_inventory(self, target): + print self.player.inventory() + + def do_inv(self, target): + return self.do_inventory(target) + + def do_i(self, target): + return self.do_inventory(target) + + def do_put(self, target): + return self.do_drop(target) + + def postcmd(self, stop, x): + pass + + def default(self, line): + # failed all the above, + if self.guesser is not None: + # let's use Bayes + all_item_names['north'] = 'N' + all_item_names['east'] = 'E' + all_item_names['west'] = 'W' + all_item_names['south'] = 'S' + all_item_names['N'] = 'N' + all_item_names['E'] = 'E' + all_item_names['W'] = 'W' + all_item_names['S'] = 'S' + for name in all_item_names: + if re.search(r'\b%s\b' % re.escape(name), line, re.I): + guesses = self.guesser.guess(line.replace(name,'')) + if guesses: + method_name = guesses[0][0] + getattr(self, method_name)(all_item_names[name]) + return + +def play(gamefile): + #start_room = _create_universe() + + player_name = raw_input('Player name?: ') or 'No name' + g = Game(gamefile, player_name) + + g.cmdloop() + +if __name__ == '__main__': + import sys + if sys.argv[1] == 'test': + test_location() + test_player() + sys.exit(0) + + try: + play(sys.argv[1]) + except KeyboardInterrupt: + pass diff --git a/adventure/week6/commands.bays b/adventure/week6/commands.bays new file mode 100644 index 0000000..4657adc --- /dev/null +++ b/adventure/week6/commands.bays @@ -0,0 +1,197 @@ +(dp1 +S'__Corpus__' +p2 +ccopy_reg +_reconstructor +p3 +(creverend.thomas +BayesData +p4 +c__builtin__ +dict +p5 +(dp6 +S'head' +p7 +I4 +sS'north' +p8 +I3 +sS'armour' +p9 +I4 +sS'of' +p10 +I2 +sS'lift' +p11 +I8 +sS'wear' +p12 +I2 +sS'put' +p13 +I1 +sS'climb' +p14 +I1 +sS'spin' +p15 +I4 +sS'the' +p16 +I21 +sS'me' +p17 +I1 +sS'on' +p18 +I3 +sS'use' +p19 +I1 +sS'armor' +p20 +I3 +sS'west' +p21 +I3 +sS'self' +p22 +I1 +sS'up' +p23 +I8 +sS'fetch' +p24 +I8 +sS'to' +p25 +I4 +sS'place' +p26 +I2 +sS'suit' +p27 +I2 +sS'grab' +p28 +I8 +sS'east' +p29 +I3 +sS'into' +p30 +I1 +sS'south' +p31 +I3 +sS'pick' +p32 +I8 +stRp33 +(dp34 +S'tokenCount' +p35 +I109 +sS'training' +p36 +(lp37 +sS'name' +p38 +g2 +sS'pool' +p39 +NsS'trainCount' +p40 +I51 +sbsS'do_take' +p41 +g3 +(g4 +g5 +(dp42 +g9 +I4 +sg32 +I8 +sg11 +I8 +sg12 +I2 +sg13 +I1 +sg14 +I1 +sg17 +I1 +sg18 +I3 +sg19 +I1 +sg20 +I3 +sg10 +I2 +sg22 +I1 +sg23 +I8 +sg24 +I8 +sg26 +I2 +sg28 +I8 +sg27 +I2 +sS'the' +p43 +I17 +sg30 +I1 +stRp44 +(dp45 +g35 +I81 +sg36 +(lp46 +sg38 +g41 +sg39 +Nsg40 +I39 +sbsS'do_move' +p47 +g3 +(g4 +g5 +(dp48 +g7 +I4 +sg8 +I3 +sg21 +I3 +sg25 +I4 +sg16 +I4 +sg29 +I3 +sg15 +I4 +sg31 +I3 +stRp49 +(dp50 +g35 +I28 +sg36 +(lp51 +sg38 +g47 +sg39 +Nsg40 +I12 +sbs. \ No newline at end of file diff --git a/adventure/week6/data.txt b/adventure/week6/data.txt new file mode 100644 index 0000000..4d01f45 --- /dev/null +++ b/adventure/week6/data.txt @@ -0,0 +1,98 @@ +# This is how it works +# +# Colon at the start of the line indicates a new location definition. +# After the colon is the name of the location. +# The next line is a description of the location. +# Following is zero or multiple other directions and destinations. +# These directions are described by : +# +# A * at the beginning of a line denotes a new object. +# The next line after the star is the location of the object +# The 3rd line is the long description of the object +# The line beginning A: is a list of comma separate daliases for the object + +:Driveway +You wake up on the driveway with a screaming headache and a sense of deja vu. As you stand up your head throbs in torturous pain. You put your hand to your head and it feels...wrong. You look at your hand and you think it is covered with blood. Bile rises and you stumble. To the north of you is an entrance to a house. Behind you is nothing but impenetrable and strangely threatening fog that you want to get away from. To the east is a garage, with a strange wet track about 2 feet across going into it. +N:Hall +E:Garage + +*House +Driveway +An overly-described horror film-style house which utilises far too many adjectives. +F:You're not superman, you can't pick up a house. +H: + +:Garage +You are in a musty garage, that would be greatly improved by smelling of motor oil rather than, whatever the smell is. The smell reminds you of something. Something you've done. You can't quite remember, but a feeling of guilt floods over you as you look at the wet streak through the dust on the floor. The streak ends in the centre of the garage. Tied over one of the rafters is a rope that has been cut. It hangs over a pool of viscous ooze that is at the end of the wet streak. +W:Driveway + +*Rope +Garage +A short length of rope with one end roughly cut that is starting to fray. It would probably support your weight if it was long enough to tie around anything. +A:noose + +:Hall +There is mud trampled into a rich Persian rug. A suit of armor has been knocked off its pedestal and has tumbled onto the floor. Grim portraits stare down at you with malevolent eyes. The streak of mud turns to the west and goes through a door. To the east, two great muddy footprints stand before a dark carved wooden door that seems to pulsate with some strange force that feels almost alive and... intelligent? +W:Dining Room +E:Library + +*Suit of Armour +Hall +A rusty suit of armor. It looks as if it might have actually been used. +A:armor, armour, suit + +*Persian Rug +Hall +A fine Persian rug of exceedingly high quality, sadly ruined by mud. It breaks your heart to see such treasures maltreated like this. +A:rug, carpet + +:Library +The door to the library begrudgingly opens with a groan, as if some force or thing was attempting to keep it closed from the other side. The room is stack high with books that are mouldering from damp. Some piles crumble into a mushy pile as you walk past them. In the centre of the room stands a wooden pedestal. On top of it is a thick tome tightly bound in something that looks like leather. You feel sick to your stomach as you approach it, yet at the same time you find it attractive and feel you must have it. +W:Hall + +*Necronomicon +Library +A leather-bound book of impressive thickness. It feels evil to the touch. You feel the urge to take it. +A:book, tome + +:Dining Room +An upturned banquet table greets you. Broken glass and china litters the dimly lit room... has there been a struggle here? Muddy footprints lead north to a doorway illuminated by a flickering light. You feel a strange presence watching you from the rafters of the ornately painted ceiling. Curiously, the banquet was without food, judging from the pieces of carnage surrounding you, and the only untouched furniture is a solitary candlestick lying in the centre of the room. + +*Candlestick +Dining Room +A bronze candle stick intricately decorated with Celtic symbology all swirly knots that appear to writhe as if alive. The candlestick hold a limp and well used white candle. +A:candle, candelabra, stick + +:Kitchen +The kitchen is strewn with blood and thick green ichor. The walls have diagonal slashes across them, as if made by a heavy knife. Surprisingly, the rest of the kitchen look intact. +E:Cellar +S:Dining Room + +:Cellar +You're in a lovely smelly cellar. +N:Cave +W:Kitchen + +:Cave +You have arrived in a cave! It is dark, you are likely to be eaten by a fishman. +E:Temple Entrance +S:Cellar + +:Temple Entrance +A temple entrance. +W:Cave +E:Chamber + +:Chamber +A chamber. Woohoo. +N:Altar +S:Crypt +W:Temple Entrance + +:Altar +An altar of misspelling. +S:Chamber + +:Crypt +A crypt. +N:Chamber diff --git a/adventure/week6/train.py b/adventure/week6/train.py new file mode 100644 index 0000000..888e1fc --- /dev/null +++ b/adventure/week6/train.py @@ -0,0 +1,34 @@ +from reverend.thomas import Bayes + + +guesser = Bayes() + +for each in ('north','south','east','west'): + guesser.train('do_move', 'to the %s' % each) + guesser.train('do_move', 'head %s' % each) + guesser.train('do_move', 'spin %s' % each) + + # if we don't do this 'do_move' is going to get too dominant + guesser.train('do_take', 'grab') + guesser.train('do_take', 'grab the') + guesser.train('do_take', 'pick up') + guesser.train('do_take', 'pick up the') + guesser.train('do_take', 'lift') + guesser.train('do_take', 'lift the') + guesser.train('do_take', 'fetch') + guesser.train('do_take', 'fetch the') + +bulk = """wear suit of armour +put on suit of armour +use armor +climb into armour +wear the armor +place armour on me +place armor on self""" +for line in bulk.splitlines(): + guesser.train('do_take', line) + +guesser.save('commands.bays') +#print guesser.guess('fetch') + + \ No newline at end of file