## Creature Project ## CSC323 ## 4/17/10 ## localworld.py A local world with a torodial board and methods ## to access and change the board. from Species import Species from Instruction import * from ConflictResolutionPolicy import * import Direction import sys, pickle sys.path.append('../gui') sys.path.append('../network') import WorldSpec #import BoardScreen from SpeciesDatabase import * class LocalWorld(): """The Local User's World Class.""" def __init__ (self, startSpecies=None, x=10, y=10): """Fills an x by y board with the default species (most often will be the dead species)""" ##get instance of Species Database: do not pass it around! specdb = SpeciesDatabase.getInstance() if startSpecies == None: startSpecies = Species("dead", "black") specdb.addSpecies(startSpecies) self.default = startSpecies self.__board = [[startSpecies for y in range(y)] for x in range(x)] self.instructions = [[[None] for y in range(y)] for x in range(x)] self.specDatabase = specdb self.width = x self.height = y self.conflictResolver = ConflictResolutionPolicy(self.specDatabase) self.__listeners = [] self.__resolvedInstructions = [] def __str__(self): """Returns a string of human readable attributes of localworld.""" printer = "" for i in range(self.height): printer += "\n" for j in range(self.width): printer += self.__board[j][i].__str__() + " " return ("Width: " + str(self.width) + " Height: " + \ str(self.height) + " " + printer + "\n") def setSpeciesFromInstruction(self, inst): """Set species of a cell given a packed Instruction""" return setSpecies(inst.coords[0],inst.coords[1],inst.species) def setSpecies(self, x, y, species): """Makes the board reference the given species at cell (x,y). x and y toroidally wrap to eliminate bounds errors.""" x = x % self.width y = y % self.height if species == None: #replace with try/catch, add error checking here #print("Invalid creature") raise Exception("Invalid creature!") return self.__board[x][y] = species return True def getSpecies(self, x, y): """Returns species referenced by the board at (x,y)""" x = x % self.width y = y % self.height return self.__board[x][y] def step(self): """Move forward one generation on the board.""" self.__getInstructions__() self.__applyInstructions__() self.__sendUpdate(self.__resolvedInstructions) self.instructions = [[[None] for y in range(self.height)] \ for x in range(self.width)] self.__resolvedInstructions = [] def __applyInstructions__(self): """Takes the array of instructions and applies them to the board. Only one instruction can be applied to each cell, so the instructions at each cell are compared and one is chosen via a Conflict Resolution Policy (which returns the species that won) and the board is set to that species at that cell location.""" for y in range(self.height): for x in range(self.width): victor = self.conflictResolver.victor(self.instructions[x][y]) if victor != None: if self.__board[x][y] != victor: i = Instruction.Instruction(Direction.C, victor) i.pack((x,y)) self.__resolvedInstructions.append(i) self.__board[x][y] = victor def __getInstructions__(self): """Iterates over the board and checks for instructions. It does this by getting the packed instructions generated by every cell (putting them into tempInstructions[]), then taking each of those instructions and putting them into an empty 3D shadow of the board (instructions[]) where their changes actually occur (Example: Cell 4,4 generates a spawn right instruction and a spawn left instruction (aka it extends horizontally). These instructions will then be placed at 3,4 and 5,4 (the coordinates of the packed instructions). It will place no instruction at 4,4).""" tempInstructions = [] #Not every cell has an instruction, if it has no instructions it will remains as its current species. for y in range(self.height): for x in range(self.width): tempInstructions = self.getSpecies(x,y).next(self, (x,y)) for elem in tempInstructions: coords = elem.coords self.instructions[coords[0]%self.width][coords[1]%self.height].append(elem) def save_the_world(self): """ A function which returns a string representation of the world as we know it.""" worldString = "("+ str(self.width) + ")("+ str(self.height) + ")" + "\n" for y in range(self.height): for x in range (self.width): worldString += "$(" + self.getSpecies(x,y).save_the_species() + ")\n" return worldString def addListener(self,listener): """addListener: Register a WorldListener as listening to this World. It will then receive updates.""" self.__listeners.append(listener) def removeListener(self,listener): """removeListener: Unregisters a WorldListener from event notifications""" self.__listeners.remove(listener) def __sendUpdate(self, changes): """__sendUpdate: Sends a notification to all the listeners about changes to the World using the WorldListener interface""" for listener in self.__listeners: #Theoretically, we should check if each listener implements WorldListener, but this is Python... just try it? try: listener.update(changes) except TypeError: pass def __getstate__(self): """Returns the state of the dictionary""" tool = self.__dict__.copy() return tool def __setstate__(self, state): """Should set the state of the dictionary, but seemingly does nothing.""" pass def toWorldSpec(self): return WorldSpec.WorldSpec\ (self.specDatabase, self.width, self.height, self.default, self.__board) def picktest(self): """A test with pickles!!""" pickle.dumps(self.specDatabase) pickle.dumps(self.width) pickle.dumps(self.height) pickle.dumps(self.default) pickle.dumps(self.__board) @staticmethod def fromWorldSpec(spec): w = LocalWorld(spec.default, spec.x, spec.y) w.__board = spec.board w.specDatabase = spec.db return w