26 June, 2008
SimulaE Cartography Program - simulae-kaart.py
05 June, 2008
Simulae3 Update: Room Object? What ever do you mean?
21 May, 2008
Simulae3: A Testament to Socratic Design.
27 April, 2008
SimulaE - Model Update
10 July, 2007
Python's 'Pickle' Module
The solution was sitting right in front of me all along, the standard library's 'pickle' module (or alternatively the 'cpickle' variation for speed's sake). Due to the issues presented in a virtual world simulation the topic of object blueprints and simulation population ease come to mind rather quickly. The best environment for manipulating these new objects will ultimately be via the methods provided by both the the SimulaE package (SimulaE.loadObject(filename_to_load, [optional_load_path]) as well as at the code level in the parent class in SimulaE.SimulaeObject.saveObject(filename_to_save_as, [optional_save_path]).
By going this route it has been realised that a simple loop and/or script-like routine could be used to create all the generic object templates needed for design platforms, and for customisation all one need do is use the loadObject routine, make the necessary alterations and re-save said item as a more concrete, concise and specialised object, named appropriately of course.
Let us take an example of a room type object (more simply put, a larger container object). We'll use simple constructor information here for the sake of staying on focus. We're going to make a 4 metre x 5.5 metre dining room, with a 2.75 metre ceiling, simple called "Dining Room". It will be empty sans an already pickled to storage butler object we've created for the sake of this example (whose filename is simply "butler_jeeves"), though future discussions on SimulaE's container and stack loading methods are forthcoming.
import SimulaE
generic_dr = SimulaE.SimulaeObject(name='Dining Room', width=4.0, length=5.5, height=2.75)
generic_butler = SimulaE.loadObject('butler_jeeves')
generic_dr.addToContents(generic_butler)
generic_dr.saveObject('diningroom4x5.5x2.75wButler')
We now have a pickled version of this generic dining room of the aforementioned dimensions, sporting its own copy of Jeeves the butler, saved to a physical file on whatever storage device we're set to utilise. We can overwrite said object by simply saving the item with the filename as it exists on whatever storage device is in use. There is also the flexibility of specifying alternative file save and load paths with allow for multiple parallel simulations and/or individuals to work in safe separate but equal spaces, very much along the lines of a Unix mentality. Another advantage by working in this manner is being able to create a path full of simulation objects and copy said path en masse for alternative and/or backup purposes.
Either way you slice the pickle (module), it proves to be quite (ful)filling, making one feel quite (programmatically) satisfied.
05 July, 2007
Check External Data/Configurations First.
I was recently on holiday with my family visiting other members of my family as well as friends. It was at this time I pulled out my trusty MacBook Pro, fired up TextMate, pulled down the newest subversion repository of my simulation software 'SimulaE' and attempted to show my friend the crafty english parser component I wrote. I showed him the test suite with all of its various scenarios and then suggested he throw an attempt at it so that he may be amazed at its crafty logic.
He did, and it failed, and I was surprised to say the last. So given that I was on vacation, I wasn't going to focus must time on this issue other than updating the subversion repository so that I could look into the issue at a later time. Well, two days ago I finally did so, and found out after careful checking that one of the datafiles utilised for cross checking and sub classifications of parts of speech of english lacked the necessary word (also the culprit of the mis-parse). After making a quick addition to the aforementioned lookup file, the test ran just fine, and passed with flying colours.
Lesson learned (for what feels like the millionth time); check your support configuration and/or data files, because your code isn't broken, just doing what it is supposed to, based upon the information it has available (data files) to it.
26 May, 2007
Present Tense English Parser : Part I
As part of an ongoing project during which I have been designing, building and testing in one way or another over the past decade and a half, I have arrived as the parser phase. Well, I will correct that statement. I have tinkered with creating parsers before, but thanks to the expressive nature of the Python language, I was finally ready to make a serious attempt at writing an English present tense command based parser. I'm not going to make a massive post about this, though I am going to post the test results.
Note, all the tests pass. What a passing result actually means is this; The parsers job as of version 0.5.4 is to break apart the sentence(s) properly into their components via identification of verbs, conjunctions, prepositions, articles, conjunctions, pronouns and punctuation.
Creating Parser Instance: : Passed
Loading Configuration for Instance: : Passed
Testing for version: 0.5.0
paint the gold bucket black : Passed
get the big , heavy hammer and kill Bob with it ! : Passed
get hammer and squirrel from Bob and then hammer squirrel into the wall . : Passed
get the gold gold : Passed
kill elf and get gold : Passed
paint the bucket gold : Passed
paint the gold bucket black ! : Passed
get gold : Passed
kill elf , get gold : Passed
get the large gold brick . : Passed
paint the bucket gold . : Passed
get the large , gold brick . : Passed
Testing for version: 0.5.1
get rock , pliers , hammer and squirrel and hammer squirrel into the wall . : Passed
Testing for version: 0.5.2
kill the trite little elf with my sword , then wipe the blood off of it ! : Passed
destroy the cantankerous creature before you eat your dessert : Passed
kill the trite little elf with my sword , then wipe the blood off of my sword ! : Passed
kill the trite little elf with my sword . : Passed
Testing for version: 0.5.3
hammer the hammer into the big hammer : Passed
hammer the hammer into the hammer : Passed
Testing for version: 0.5.4
kill the trite little elf with my lavacious sword , then wipe the blood off it ! : Passed
go to the store and buy a new cellphone : Passed
slit Fred's throat and capture the warm , red blood in a cup ! : Passed
play with my toys and listen to my music . : Passed
play with my toys and listen to music . : Passed
As can be seen, the variety of possible inputs for the parser vary from simple to complex, from grammatically perfect to questionable fragments. Being that the purpose of this parse is first and foremost for use in a command environment in which interaction is needed, thus the present tense only requirement. This is a massive relief on the demands of the parser, but even still, it can be see from the above that the system can differentiate key words which can be used in both noun and adjective forms. The system also handle post adjective usage.
The system currently most notably recognises over 9,000 verbs (regular and irregular), 50 prepositions, and a whopping 46,000+ adjectives. A call for test case phrases is hereby announced. I am satisfied enough with the stage one parse process that I hereby am moving on to the second parse stage, that is the creation and order of individual statements (as dictated by their prepositions), in preparation for the third and final stage, in which the parser sends the results from stage two to the action engine. Both those phases will be the subjects of new posts, accordingly.
28 June, 2006
Rethinking Real-World Object Models in Simulations
In many cases these ‘games’ were written in the low level language du jour, such as ‘C’, or in a custom language like ‘Inform’ (in the case of Infocom games) which was also written in ‘C’. There were languages which would’ve been better suited for these games/simulations, object oriented programming (OOP) languages such as Smalltalk, or Objective-C, but they were generally not utilised as such.
Recently in my workplace I have been developing full time (for the past couple of years) in Python, a wonderful high level language written by Guido van Rossum which is a proper OOP language. As such, the idea of writing a simulation (not a ‘game’ per se) which would allow me to focus on not only how one would model the real world (to a certain depth), but as an exercise in python objects.
While the code is still an ongoing side work of mine, I am posting the parent class (SimObject) and it’s associated child classes (Place, Person and ExitObject) for review by those who are interested. Please note that due to certain conflicts with word press, proper pythonic indentation (required for execution) is not established as such.
#####################################################
# S I M O B J E C T C L A S S #
#####################################################
class SimObject:
object_master_list=[]
def __init__(self,
object_id = 0,
object_sku = 0,
short_description = 'Short Description',
long_description = 'Long Description',
name = 'Name',
weight = 1.0,
height = 1.0,
width = 1.0,
depth = 1.0,
visible = True,
closed = False,
contents = [],
stack = []):
self._object_id = object_id
self._object_sku = object_sku
self._short_description = short_description
self._long_description = long_description
self._name = name
self._weight = weight
self._height = height
self._width = width
self._depth = depth
self._visible = visible
self._closed = closed
self._contents = []
self._stack = []
self.object_master_list.append(self)
def getObjectById(self,object_id):
for sim_objects in self.object_master_list:
if sim_objects.getObjectId() == object_id:
return sim_objects
def addContents(self,item):
try:
self._contents.append(item)
return True
except:
return False
def addToStack(self,item):
try:
self._stack.append(item)
return True
except:
return False
def isVisible(self):
return self._visible
def getContents(self):
return self._contents
def getShortDescription(self):
return self._short_description
def getLongDescription(self):
return self._long_description
def getSize(self):
return "Object Details ... Weight: %.2f, Height: %.2f, Width: %.2f, Depth: %.2f" % (self._weight, self._height, self._width, self._depth)
def getHeight(self):
return self._height
def getWeight(self):
return self._weight
def getName(self):
return self._name
def getObjectId(self):
return self._object_id
def getDescription(self):
output = ''
vowels = ['a','e','i','o','u']
if isinstance(self,Place):
short_desc = self.getShortDescription()
output += short_desc + "\n"
underline = ''
for i in str(short_desc):
underline += '-'
output += underline + "\n"
output += self.getLongDescription() + '\n'
for thing in self.getContents():
if isinstance(thing,ExitObject):
if thing.isVisible():
output += "There is "
if thing.getName()[0].lower() in vowels:
output += 'an '
else:
output += 'a '
output += thing.getName() + ' '
output += 'here.\n'
else:
### Don't short exits if they are just cardinal directions (_visible=False)
pass
itemlist = []
peoplelist = []
for thing in self.getContents():
if isinstance(thing,SimObject) and not isinstance(thing,ExitObject) and not isinstance(thing,Person):
itemlist.append(thing.getName())
elif isinstance(thing,Person):
peoplelist.append(thing.getName())
if len(itemlist) == 1:
output += "There is "
if itemlist[0][0].lower() in vowels:
output += 'an '
else:
output += 'a '
output += itemlist[0] + ' '
output += 'here.\n'
if len(itemlist) >= 2:
total_items = len(itemlist)
item_counter = 1
output += "There are "
for items in itemlist:
if items[0].lower() in vowels:
output += 'an '
else:
output += 'a '
if item_counter <= total_items-2:
output += str(items)+', '
elif item_counter == total_items-1:
output += str(items)+' and '
else:
output += items + " "
item_counter += 1
output += "here.\n"
output += "\n"
if len(peoplelist) == 1:
output += str(peoplelist[0]) + " is here.\n"
elif len(peoplelist) > 1:
item_counter = 1
total_items = len(peoplelist)
for items in peoplelist:
if item_counter <= total_items-2:
output += str(items) + ', '
elif item_counter == total_items-1:
output += str(items) + ' and '
else:
output += str(items)
item_counter += 1
output += "are here.\n"
elif isinstance(self,Person):
output += self.getName()
output += "is standing before you!\n"
elif isinstance(self,ExitObject):
if self.isVisible():
output += str(self.getShortDescription()) + '\n'
else:
output += "You see nothing out of the ordinary here.\n"
else:
output += "unsure of type!\n"
output += "\n"
return output
#####################################################
# P L A C E C L A S S #
#####################################################
class Place(SimObject):
def __init__(self,
object_id = 0,
object_sku = 0,
short_description = 'Short Description',
long_description = 'Long Description',
name = 'Name',
weight = 1.0,
height = 1.0,
width = 1.0,
depth = 1.0,
visible = True,
contents = []):
SimObject.__init__(self,
object_id=object_id,
short_description = short_description,
long_description = long_description,
name = name,
weight = weight,
height = height,
width = width,
depth = depth,
visible = visible,
object_sku = object_sku,
contents = [])
#####################################################
# P E R S O N C L A S S #
#####################################################
class Person(SimObject):
def __init__(self,name="",object_id=0,object_sku=0):
SimObject.__init__(self,name=name,object_id=object_id,object_sku=object_sku)
self._hp = 100
def isAlive(self):
if self._hp > 0:
return True
else:
return False
def getStats(self):
print "%s has %i hit points remaining!" % (self._name,self._hp)
def receiveHit(self,damage="0"):
self._hp = self._hp - damage
if self._hp <>
self._hp = 0
def attack(self,enemy):
if type(enemy) == type(self):
attempt_roll = randint(1,10)
if attempt_roll > 5:
enemy.receiveHit(attempt_roll)
else:
print "Missed %s!" % str(enemy._name)
else:
print "Cannot attack %s" % str(enemy)
def getSize(self):
return "Person Details ... Weight: %.1f, Height: %.1f, Width: %.1f, Depth: %.1f" % (self._weight, self._height, self._width, self._depth)
def move(self,destination):
#### add test against dimensions. person WxD must be greater than Exit HxW, and the smallest Person dimension much be
#### smaller than the smallest Exit dimension
destination_room = self.getObjectById(destination)
destination_room.addContents(self)
#####################################################
# E X I T C L A S S #
#####################################################
class ExitObject(SimObject):
def __init__(self,visible=False,name="ExitName",short_description='Exit',
long_description='an Exit',aliases=(), destination=0,object_id=0,object_sku=0, weight=1.0,width=1.0,height=1.0,depth=1.0,closed=False):
"""Aliases are lists of names by which this exit can be referenced"""
SimObject.__init__(self,visible=visible,name=name,short_description=
short_description, long_description=long_description,object_id=object_id,
object_sku=object_sku, weight=weight,width=width,height=height,depth=depth,
closed=closed)
self._aliases = aliases
self._destination = destination
def getDestination(self):
return self._destination
def getAliases(self):
return self._aliases