# class for the labyrinth from enum import Enum from functools import reduce directions = {"north": (-1, 0), "east": (0, 1), "west": (0, -1), "south": (1, 0)} class Labyrinth: class GroundType(Enum): FLOOR = 1 WALL = 2 class Field: def __init__(self,groundtype,column,row,labyrinth): # please only read from these members self.groundtype = groundtype self.column = column self.row = row self.labyrinth = labyrinth # the following usually change self.things = [] # list of things/players on this field def _removeThing(self,thing): self.things.remove(thing) def _addThing(self,thing): assert self.things.count(thing) == 0 assert self.groundtype != Labyrinth.GroundType.WALL self.things.append(thing) def neighbor(self,dy,dx): self.labyrinth.getTileAt(self.row + dy, self.column + dx) def isWalkable(self): # this may be more complicated in the future return self.groundtype == Labyrinth.GroundType.FLOOR def toString(self): # always starts with there is/there are if self.groundtype == Labyrinth.GroundType.WALL: return "there is a wall" else: if len(self.things) == 0: return "there is nothing" elif len(self.things) == 1: return "there is "+self.things[0].toString() else: return "there are "+(", ".join([x.toString() for x in self.things[:-1]]))+" and "+self.things[-1].toString() # constructor for a completely read labyrinth def __init__(self,width=None,height=None,stream=None): if width is not None: # empty labyrinth of given size assert height is not None assert stream is None self.tiles = [[Labyrinth.Field(Labyrinth.GroundType.FLOOR,col,row,self) for col in range(width)] for row in range(height)] elif height is not None: assert False # width None, height not elif stream is not None: self.tiles = self._readlab(stream) # function for reading a labyrinth from a file def _readlab (self,stream): tiles = [] for rownum,line in enumerate(stream): row = [] for colnum,char in enumerate(line): if char in [' ','0','_']: row.append(Labyrinth.Field(Labyrinth.GroundType.FLOOR,colnum,rownum,self)) elif char in ['W','w','#','1']: row.append(Labyrinth.Field(Labyrinth.GroundType.WALL,colnum,rownum,self)) tiles.append(row) return tiles def getWidth(self): return len(self.tiles[0]) def getHeight(self): return len(self.tiles) def outOfBounds(self,row,column): return row < 0 or column < 0 or row >= self.getHeight() or column >= self.getWidth() def getTileAt(self,row,column): if self.outOfBounds(row,column): return None else: return self.tiles[row][column] def getTiles(self): return reduce(lambda x,y:x+y, self.tiles) def getFreeTiles (self): return list(filter(lambda f: f.groundtype == Labyrinth.GroundType.FLOOR and len(f.things) == 0 ,self.getTiles())) def getDescription (self, field): descr = "" for name,field in zip(["North","South","West","East"], [self.getTileAt(field.row+row,field.column+column) for row,column in [(-1,0),(1,0),(0,-1),(0,1)]]): descr += "In the "+name+" "+("there is a wall" if field is None else str(field))+".\n" return descr def moveThing (self, thing, newField): if thing.onMove(newField) == False: return False assert thing.field.labyrinth == self assert newField.labyrinth == self thing.field._removeThing(thing) thing.field = newField newField._addThing(thing) return True def createThing (self, thing, field): thing.field = field field._addThing(thing)