## Creature Project ## CSC323 ## 4/26/10 ## SpeciesDatabase.py: Contains a database for holding Species objects, including ## load and save them from/to disk. from Species import Species from Predicate import * import Instruction, Direction, Rule, IterParser def getInstance(): return SpeciesDatabase.getInstance() class SpeciesDatabase: #This is a Singleton. __single = None @staticmethod def getInstance(): """Returns the same SpeciesDatabase every time. Dont use the init method""" if not SpeciesDatabase.__single: SpeciesDatabase.__single = SpeciesDatabase() return SpeciesDatabase.__single @staticmethod def setInstance(instance): '''Allow the setting of the SpeciesDatabase.''' assert(isinstance(instance, SpeciesDatabase)) __single = instance def __init__(self): """Initializes a SpeciesDatabase with an empty dictionary of species""" assert(SpeciesDatabase.__single is None) SpeciesDatabase.__single = self self.species={} self.speciesByColor = {} self.strengthDict = {} def reset(self): '''Resets a SpeciesDatabase back to defaults''' self.species = {} self.speciesByColor = {} self.strengthDict = {} def allSpeciesNames(self): """Returns the names of all Species stored in this SpeciesDatabase""" return self.species def count(self): """Returns the number of species in this SpeciesDatabase""" return len(self.species) def addSpecies(self, species, defaultStrength = .5, strongerList=None, weakerList=None, ow = 0): """Adds a species to the species database, and adds entries to the strength dictionary. StrongerList = list that species is stronger than""" if isinstance(species,Species): self.species[species.kind]=species self.speciesByColor[species.color]=species if strongerList != None: for s in strongerList: self.addStrengthPair(species, s, defaultStrength, ow) if weakerList !=None: for w in weakerList: self.addStrengthPair(w, species, defaultStrength, ow) self.addDefaultStrength(species, defaultStrength, overwrite = ow) else: raise Error("addSpecies expects a Species") def addStrengthPair(self, spec1, spec2, num, overwrite = 1): """Adds an entry in the strength dictionary. Automatically adds the reverse relationship as well. If overwrite is disabled, will not overwrite existing relationship. """ if isinstance(spec1,str): spec1 = self.species[spec1] if isinstance(spec2,str): spec2 = self.species[spec2] if overwrite == 0: if (spec1, spec2) in self.strengthDict: return self.strengthDict[(spec1, spec2)] = num self.strengthDict[(spec2,spec1)] = 0-num def addDefaultStrength(self, species, num, overwrite = 1): """Adds strength dictionary entries for species against all other species in the database""" for s in self.species: self.addStrengthPair(species, s, num, overwrite) def loadFile(self,speciesfile): '''populate self.db from a file Precondition: species file is a string naming a file Postcondition: self.db is populated from the file handle opened against speciesfile ''' self.db = {} with open(speciesfile) as fi: for stat in IterParser.IterParser(fi): #print("calling gen on: ", stat) self.gen(stat) self.exportdb() def exportdb(self): '''a helper method to export species parsed from a file to the main databases''' for key, value in self.db.items(): if isinstance(value, Species): self.addSpecies(value) def getSpeciesfromColor(self,color): return self.speciesByColor[color] def getColorfromName(self, name): return self.species[name].color def getSpecies(self,name): """Given the name of a species in the database, will return the corresponding Species""" return self.species[name] def interpret(tree): '''interpret the commands present in the parse tree''' #not something we actually need to implement pass def instruction(self, direction, species): '''helps build instructions from our tree''' cases = [ ('N', Direction.N), ('NE', Direction.NE), ('E', Direction.E), ('SE', Direction.SE), ('S', Direction.S), ('SW', Direction.SW), ('W', Direction.W), ('NW', Direction.NW), ('C', Direction.C) ] for d, c in cases: if d == direction: return Instruction.Instruction(c(), species) raise Exception("Syntax Error!") def gen(self, tree, debug=False): if debug: print(tree) '''parse the mini-programming language of species files''' if tree[0] == 'define': self.db[tree[1]] = self.gen(tree[2]) elif tree[0] == 'instruction': return self.instruction(tree[1], tree[2]) elif tree[0] == 'rule': if debug: print("tree is") if debug: print(tree) instructions = [] #-1 can be used to access the last item in the list for i in tree[2:-1]: instructions.append(self.gen(i)) return Rule.Rule(self.gen(tree[1]),\ instructions) elif tree[0] == 'predicate': if debug: print("predicate") if debug: print(tree[1]) return self.genpred(tree[1]) elif tree[0] == 'species': rules = tree[3:] rules = [self.gen(r) for r in rules] assert \ [isinstance(r, Rule.Rule) for r in tree[2:]], "Syntax Error!" return Species(tree[1], tree[2], rules) elif isinstance(tree, str): if tree in self.db: return self.db[tree] else: raise("Referencing undefined variable!") else: if debug: print("throwing exception, here is the tree:") print('%s' % str(tree[0])) print("db") print(self.db) raise Exception("Syntax Error!") def genpred(self, tree): '''build some predicates out of the parse tree''' cases = [ ('OR', lambda:OrPredicate([self.genpred(t) for t in tree[1:]])), ('AND', lambda:AndPredicate([self.genpred(t) for t in tree[1:]])), ('NOT', lambda:NotPredicate(self.genpred(tree[1]))), ('DIRECTION', lambda:DirectionalTestPredicate(tree[1], tree[2])), ('QUANTITY', lambda:QuantityPredicate(tree[1], int(tree[2]))), ('TRUE', lambda:TruePredicate()), ('LIVE', lambda:LiveNeighbors(int(true[1]), eval(tree[2]))), # Ravi should check this one! ] for cond, response in cases: if tree[0] == cond: return response() if isinstance(tree, str) and tree in self.db: return self.db[tree] else: raise Exception("Referencing undefined variable %s" % tree) raise Exception("Syntax Error!") def __getstate__(self): print(self.__dict__) return self.__dict__