import cTurtle import random ## In order to be usable with the World class, a thing must support the following operations: ## thing.setX(newx) ## thing.setY(newy) ## thing.getX() ## thing.getY() ## thing.setWorld(theWorld) ## thing.appear() ## thing.hide() ## thing.liveALittle() ## ## The setX and setY methods are intended just to update the thing's own idea of its position, ## not to update information stored within the World, nor to update the graphical display. ## ## The appear and hide methods are intended to update the graphical display. ## ## To update the World's idea of where a thing is located, the World's moveThing method ## must be used. This updates only the World's information, not the postion stored within ## the thing nor the graphical display. ## ## Each kind of thing can also provide a move method: ## thing.move(newx,newy) ## This does all the various kinds of updating needed to move the thing to a new location: ## (1) The World's information is updated using the World's moveThing method. ## (2) The thing's own idea of its location is updated the same as with setX and setY. ## (3) The graphical display is updated. class World: ## Listing 11.1 (with the loading of Fish and Bear images removed) def __init__(self, mx, my): self.maxX = mx self.maxY = my self.thingList = [] self.grid = [] for arow in range(self.maxY): row = [] for acol in range(self.maxX): row.append(None) self.grid.append(row) self.wturtle = cTurtle.Turtle() self.wturtle.setWorldCoordinates(0,0,self.maxX-1,self.maxY-1) self.wturtle.hideturtle() ## Listing 11.2 def draw(self): self.wturtle.tracer(0) self.wturtle.forward(self.maxX-1) self.wturtle.left(90) self.wturtle.forward(self.maxY-1) self.wturtle.left(90) self.wturtle.forward(self.maxX-1) self.wturtle.left(90) self.wturtle.forward(self.maxY-1) self.wturtle.left(90) for i in range(self.maxY-1): self.wturtle.forward(self.maxX-1) self.wturtle.backward(self.maxX-1) self.wturtle.left(90) self.wturtle.forward(1) self.wturtle.right(90) self.wturtle.forward(1) self.wturtle.right(90) for i in range(self.maxX-2): self.wturtle.forward(self.maxY-1) self.wturtle.backward(self.maxY-1) self.wturtle.left(90) self.wturtle.forward(1) self.wturtle.right(90) self.wturtle.tracer(1) ## Listing 11.3 def freezeWorld(self): self.wturtle.exitOnClick() def addThing(self, athing, x, y): athing.setX(x) athing.setY(y) self.grid[y][x] = athing athing.setWorld(self) self.thingList.append(athing) athing.appear() def delThing(self,athing): athing.hide() self.grid[athing.getY()][athing.getX()] = None self.thingList.remove(athing) def moveThing(self,oldx,oldy,newx,newy): self.grid[newy][newx] = self.grid[oldy][oldx] self.grid[oldy][oldx] = None def getMaxX(self): return self.maxX def getMaxY(self): return self.maxY def liveALittle(self): if self.thingList != [ ]: athing = random.randrange(len(self.thingList)) randomthing = self.thingList[-1] # -1 was athing randomthing.liveALittle() def emptyLocation(self,x,y): if self.grid[y][x] == None: return True else: return False def lookAtLocation(self,x,y): return self.grid[y][x] class Animal: ## Listing 11.5 def setX(self,newx): self.xpos = newx def setY(self,newy): self.ypos = newy def getX(self): return self.xpos def getY(self): return self.ypos def setWorld(self,aworld): self.world = aworld def appear(self): self.turtle.goto(self.xpos, self.ypos) self.turtle.showturtle() def hide(self): self.turtle.hideturtle() def move(self,newx,newy): self.world.moveThing(self.xpos,self.ypos,newx,newy) self.xpos = newx self.ypos = newy self.turtle.goto(self.xpos, self.ypos) ## Listing 11.8 def tryToMove(self): offsetList = [(-1,1) ,(0,1) ,(1,1), (-1,0) ,(1,0), (-1,-1),(0,-1),(1,-1)] randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] while not(0 <= nextx < self.world.getMaxX() and 0 <= nexty < self.world.getMaxY() ): randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] if self.world.emptyLocation(nextx,nexty): self.move(nextx,nexty) ## Listing 11.7 def tryToBreed(self): offsetList = [(-1,1) ,(0,1) ,(1,1), (-1,0) ,(1,0), (-1,-1),(0,-1),(1,-1)] randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] while not (0 <= nextx < self.world.getMaxX() and 0 <= nexty < self.world.getMaxY() ): randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] if self.world.emptyLocation(nextx,nexty): childThing = self.__class__() self.world.addThing(childThing,nextx,nexty) self.breedTick = 0 def __init__(self,image): self.turtle = cTurtle.Turtle() self.turtle.up() self.turtle.hideturtle() if image not in self.turtle.getshapes(): self.turtle.addshape(image) self.turtle.shape(image) self.xpos = 0 self.ypos = 0 self.world = None self.breedTick = 0 ## Listing 11.4 (with loading of Fish.gif added) class Fish(Animal): def tryToMove(self): offsetList = [(-2,2) ,(0,2) ,(2,2), (-2,0) ,(2,0), (-2,-2),(0,-2),(2,-2)] randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] while not(0 <= nextx < self.world.getMaxX() and 0 <= nexty < self.world.getMaxY() ): randomOffsetIndex = random.randrange(len(offsetList)) randomOffset = offsetList[randomOffsetIndex] nextx = self.xpos + randomOffset[0] nexty = self.ypos + randomOffset[1] if self.world.emptyLocation(nextx,nexty): self.move(nextx,nexty) def __init__(self): Animal.__init__(self,"Fish.gif") ## Listing 11.6 (with missing parentheses inserted) def liveALittle(self): offsetList = [(-1,1) ,(0,1) ,(1,1), (-1,0) ,(1,0), (-1,-1),(0,-1),(1,-1)] adjfish = 0 for offset in offsetList: newx = self.xpos + offset[0] newy = self.ypos + offset[1] if (0 <= newx < self.world.getMaxX() and 0 <= newy < self.world.getMaxY()): if ((not self.world.emptyLocation(newx,newy)) and isinstance(self.world.lookAtLocation(newx,newy),Fish)): adjfish = adjfish + 1 if adjfish >= 2: self.world.delThing(self) else: self.breedTick = self.breedTick + 1 if self.breedTick >= 12: self.tryToBreed() self.tryToMove() ## Listing 11.9 (with loading of Bear.gif added) class Bear(Animal): def __init__(self): Animal.__init__(self,"Bear.gif") self.starveTick = 0 ## Listing 11.10 def liveALittle(self): self.breedTick = self.breedTick + 1 if self.breedTick >= 8: self.tryToBreed() self.tryToEat() if self.starveTick == 10: self.world.delThing(self) else: self.tryToMove() ## Listing 11.11 (with missing parentheses inserted) def tryToEat(self): offsetList = [(-1,1) ,(0,1) ,(1,1), (-1,0) ,(1,0), (-1,-1),(0,-1),(1,-1)] adjprey = [] for offset in offsetList: newx = self.xpos + offset[0] newy = self.ypos + offset[1] if (0 <= newx < self.world.getMaxX() and 0 <= newy < self.world.getMaxY()): if ((not self.world.emptyLocation(newx,newy)) and isinstance(self.world.lookAtLocation(newx,newy),Fish)): adjprey.append(self.world.lookAtLocation(newx,newy)) if len(adjprey)>0: randomprey = adjprey[random.randrange(len(adjprey))] preyx = randomprey.getX() preyy = randomprey.getY() self.world.delThing(randomprey) self.move(preyx,preyy) self.starveTick = 0 else: self.starveTick = self.starveTick + 1 ## Listing 11.12 def mainSimulation(): numberOfBears = 1 numberOfFish = 0 worldLifeTime = 2500 worldWidth = 50 worldHeight = 25 myworld = World(worldWidth,worldHeight) myworld.draw() for i in range(numberOfFish): newfish = Fish() x = random.randrange(myworld.getMaxX()) y = random.randrange(myworld.getMaxY()) while not myworld.emptyLocation(x,y): x = random.randrange(myworld.getMaxX()) y = random.randrange(myworld.getMaxY()) myworld.addThing(newfish,x,y) for i in range(numberOfBears): newfish = Bear() x = random.randrange(myworld.getMaxX()) y = random.randrange(myworld.getMaxY()) while not myworld.emptyLocation(x,y): x = random.randrange(myworld.getMaxX()) y = random.randrange(myworld.getMaxY()) myworld.addThing(newfish,x,y) for i in range(worldLifeTime): myworld.liveALittle() myworld.freezeWorld()