class Arena: def __init__(self, filename, config): self.filename = filename self.entities = None self.read_map(config) def read_map(self, config): try: with open(self.filename) as f: lines = f.readlines() related_data = ''.join(lines[0:3]) map_data = lines[3:] # First line: rows \d+ # Second line: cols \d+ # Third line: players \d+ related_data_re = "rows\s+(\d+)\s+cols\s+(\d+)\s+players\s+(\d)" m = re.match(related_data_re, related_data, re.DOTALL) if not m: raise MapException("Map file '%s' is not valid - header not correct", self.filename) self.rows = int(m.group(1)) self.cols = int(m.group(2)) self.nb_players = int(m.group(3)) self.entities = EntityManager(self.nb_players) view_radius = config.getint('initial', 'view_radius') view_radiusf = config.getfloat('initial', 'view_radius') self.relative_visible_cells = [] # Compute relative visible cells for row in xrange(-view_radius, view_radius + 1): for col in xrange(-view_radius, view_radius + 1): if row == 0 and col == 0: continue if sqrt(row*row + col*col) <= view_radiusf: self.relative_visible_cells.append((row, col)) self.arena = [[Cell() for i in xrange(self.cols)] for j in xrange(self.rows)] try: for row in xrange(self.rows): for col in xrange(self.cols): if map_data[row][col] == '%': # Water cell self.arena[row][col].surface = Surface.WATER elif map_data[row][col] == '+': # Human on this cell entity = Entity(row, col) entity.create_human() self.entities.add_np_entity(entity) elif map_data[row][col] == '*': # Cop on this cell entity = Entity(row, col) entity.create_cop(config.getint('initial', 'bullet_amount')) self.entities.add_np_entity(entity) elif map_data[row][col] == '$': # Berzerk on this cell entity = Entity(row, col) entity.create_berzerk(config.getint('initial', 'berzerk_delay')) self.entities.add_np_entity(entity) elif ord(map_data[row][col]) in range(ord('1'), ord('8')): # Initial zombie for a player team = int(map_data[row][col]) entity = Entity(row, col) entity.create_zombie(team, config.getint('initial', 'contagion_amount')) self.entities.add_zombie(entity) else: # Probability to spawn a human or a cop if random.random() <= 0.09: if random.random() <= 0.05: # Cop on this cell entity = Entity(row, col) entity.create_cop(config.getint('initial', 'bullet_amount')) self.entities.add_np_entity(entity) else: # Human on this cell entity = Entity(row, col) entity.create_human() self.entities.add_np_entity(entity) except IndexError: raise MapException("Map file '%s' not valid - col/row problem", self.filename) except IOError: raise MapException("Can't open map file '%s'", self.filename) def get_targeted_cell(self, entity, direction): # Compute the targeted cell if direction == Direction.NORTH: t_row, t_col = entity._row - 1, entity._col elif direction == Direction.SOUTH: t_row, t_col = entity._row + 1, entity._col elif direction == Direction.EAST: t_row, t_col = entity._row, entity._col + 1 elif direction == Direction.WEST: t_row, t_col = entity._row, entity._col - 1 return t_row, t_col def is_valid_move(self, entity, direction): """ Return whether or not the move is valid for this entity """ t_row, t_col = self.get_targeted_cell(entity, direction) # Valid move = target inside the map and the cell is not water if t_row < 0 or t_row >= self.rows or \ t_col < 0 or t_col >= self.cols or \ self.arena[t_row][t_col].surface == Surface.WATER: return False return True def get_opposite_dirs(self, entity, avoid): """ Return directions that get away entity from avoid entity """ possible_dir = ['N', 'S', 'W', 'E'] ret = [] for dir in possible_dir: target = self.get_targeted_cell(entity, dir) if entity.distance_to(avoid) < avoid.distance_to_location(*target): ret.append(dir) return ret def get_towards_dirs(self, entity, avoid): possible_dir = ['N', 'S', 'W', 'E'] ret = [] for dir in possible_dir: target = self.get_targeted_cell(entity, dir) if entity.distance_to(avoid) < avoid.distance_to_location(*target): ret.append(dir) return ret