def execute(self): (result, building) = super(LumberjackEvaluator, self).execute() if result != BUILD_RESULT.OK: return (result, None) for coords in building.position.get_radius_coordinates(Entities.buildings[BUILDINGS.LUMBERJACK_CLASS].radius): if coords in self.area_builder.plan and self.area_builder.plan[coords][0] == BUILDING_PURPOSE.NONE: self.area_builder.register_change(coords[0], coords[1], BUILDING_PURPOSE.TREE, None) # TODO: don't ignore the return value Builder.create(BUILDINGS.TREE_CLASS, self.area_builder.land_manager, Point(coords[0], coords[1])).execute() return (BUILD_RESULT.OK, building)
def create(cls, area_builder, x, y, new_field_purpose): building_id = None if new_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: building_id = BUILDINGS.POTATO_FIELD elif new_field_purpose == BUILDING_PURPOSE.PASTURE: building_id = BUILDINGS.PASTURE elif new_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: building_id = BUILDINGS.SUGARCANE_FIELD elif new_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: building_id = BUILDINGS.TOBACCO_FIELD builder = Builder.create(building_id, area_builder.land_manager, Point(x, y)) if not builder: return None value = 0 personality = area_builder.owner.personality_manager.get('ModifiedFieldEvaluator') if new_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: value += personality.add_potato_field_value elif new_field_purpose == BUILDING_PURPOSE.PASTURE: value += personality.add_pasture_value elif new_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: value += personality.add_sugarcane_field_value elif new_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: value += personality.add_tobacco_field_value old_field_purpose = area_builder.plan[(x, y)][0] if old_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: value -= personality.remove_unused_potato_field_penalty elif old_field_purpose == BUILDING_PURPOSE.PASTURE: value -= personality.remove_unused_pasture_penalty elif old_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: value -= personality.remove_unused_sugarcane_field_penalty elif old_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: value -= personality.remove_unused_tobacco_field_penalty return ModifiedFieldEvaluator(area_builder, builder, value, old_field_purpose)
def make_builder(self, building_id, x, y, needs_collector, orientation = 0): """ Return a Builder object containing the info. If it is impossible to build it then the return value could either be None or a Builder object that evaluates to False. """ return Builder.create(building_id, self.land_manager, Point(x, y), orientation = orientation)
def build_road(self, path): """Build the road given a valid path or None. Return True if it worked, False if the path was None.""" if path is not None: for x, y in path: self.register_change(x, y, BUILDING_PURPOSE.ROAD, None) building = self.island.ground_map[(x, y)].object if building is not None and building.id == BUILDINGS.TRAIL: continue assert Builder.create(BUILDINGS.TRAIL, self.land_manager, Point(x, y)).execute() return path is not None
def _load(self, db, worldid, success_callback, failure_callback): db_result = db("SELECT land_manager, ship, warehouse_builder, state FROM ai_mission_found_settlement WHERE rowid = ?", worldid)[0] self.land_manager = WorldObject.get_object_by_id(db_result[0]) self.warehouse_location = Builder.load(db, db_result[2], self.land_manager) self.warehouse = None self.state = self.missionStates[db_result[3]] super(FoundSettlement, self).load(db, worldid, success_callback, failure_callback, WorldObject.get_object_by_id(db_result[1])) if self.state == self.missionStates.moving: self.ship.add_move_callback(Callback(self._reached_destination_area)) self.ship.add_blocked_callback(Callback(self._move_to_destination_area)) else: assert False, 'invalid state'
def build_roads(self): """Try to build all roads in the village area, record the result in the field roads_built.""" all_built = True for coords, (purpose, (section, _)) in self.plan.iteritems(): if section > self.current_section: all_built = False continue if purpose != BUILDING_PURPOSE.ROAD: continue object = self.island.ground_map[coords].object if object is not None and object.id == BUILDINGS.TRAIL_CLASS: continue if Builder.create(BUILDINGS.TRAIL_CLASS, self.land_manager, Point(coords[0], coords[1])).execute() is None: all_built = False self.roads_built = all_built
def build_roads(self): """Try to build all roads in the village area, record the result in the field roads_built.""" all_built = True for coords, (purpose, (section, _)) in self.plan.iteritems(): if section > self.current_section: all_built = False continue if purpose != BUILDING_PURPOSE.ROAD: continue object = self.island.ground_map[coords].object if object is not None and object.id == BUILDINGS.TRAIL: continue if Builder.create(BUILDINGS.TRAIL, self.land_manager, Point(coords[0], coords[1])).execute() is None: all_built = False self.roads_built = all_built
def find_warehouse_location(cls, ship, land_manager): """ Finds a location for the warehouse on the given island @param LandManager: the LandManager of the island @return _BuildPosition: a possible build location """ moves = [(-1, 0), (0, -1), (0, 1), (1, 0)] island = land_manager.island world = island.session.world personality = land_manager.owner.personality_manager.get('FoundSettlement') options = [] for (x, y), tile in sorted(island.ground_map.iteritems()): ok = False for x_offset, y_offset in moves: for d in xrange(2, 6): coords = (x + d * x_offset, y + d * y_offset) if coords in world.water_body and world.water_body[coords] == world.water_body[ship.position.to_tuple()]: # the planned warehouse should be reachable from the ship's water body ok = True if not ok: continue build_info = None point = Point(x, y) warehouse = Builder(BUILDINGS.WAREHOUSE, land_manager, point, ship = ship) if not warehouse: continue cost = 0 for coords in land_manager.village: distance = point.distance(coords) if distance < personality.too_close_penalty_threshold: cost += personality.too_close_constant_penalty + personality.too_close_linear_penalty / (distance + 1.0) else: cost += distance for settlement_manager in land_manager.owner.settlement_managers: cost += warehouse.position.distance(settlement_manager.settlement.warehouse.position) * personality.linear_warehouse_penalty options.append((cost, warehouse)) for _, build_info in sorted(options): (x, y) = build_info.position.get_coordinates()[4] if ship.check_move(Circle(Point(x, y), BUILDINGS.BUILD.MAX_BUILDING_SHIP_DISTANCE)): return build_info return None
def build(self, settlement_manager, resource_id): production_builder = settlement_manager.production_builder purpose = self.get_purpose(resource_id) if not production_builder.unused_fields[purpose]: return (BUILD_RESULT.NEED_PARENT_FIRST, None) if not self.have_resources(settlement_manager): return (BUILD_RESULT.NEED_RESOURCES, None) assert len(production_builder.unused_fields[purpose]) > 0, "expected field spot to be available" coords = production_builder.unused_fields[purpose][0] builder = Builder.create(self.id, settlement_manager.land_manager, Point(coords[0], coords[1])) building = builder.execute() if not building: return (BUILD_RESULT.UNKNOWN_ERROR, None) production_builder.unused_fields[purpose].popleft() production_builder.register_change(coords[0], coords[1], purpose, None) return (BUILD_RESULT.OK, building)
def build(self, settlement_manager, resource_id): production_builder = settlement_manager.production_builder purpose = self.get_purpose(resource_id) if not production_builder.unused_fields[purpose]: return (BUILD_RESULT.NEED_PARENT_FIRST, None) if not self.have_resources(settlement_manager): return (BUILD_RESULT.NEED_RESOURCES, None) assert production_builder.unused_fields[purpose], 'expected field spot to be available' coords = production_builder.unused_fields[purpose][0] builder = Builder.create(self.id, settlement_manager.land_manager, Point(coords[0], coords[1])) building = builder.execute() if not building: return (BUILD_RESULT.UNKNOWN_ERROR, None) production_builder.unused_fields[purpose].popleft() production_builder.register_change(coords[0], coords[1], purpose, None) return (BUILD_RESULT.OK, building)
def create(cls, area_builder, x, y, new_field_purpose): building_id = None if new_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: building_id = BUILDINGS.POTATO_FIELD elif new_field_purpose == BUILDING_PURPOSE.PASTURE: building_id = BUILDINGS.PASTURE elif new_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: building_id = BUILDINGS.SUGARCANE_FIELD elif new_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: building_id = BUILDINGS.TOBACCO_FIELD builder = Builder.create(building_id, area_builder.land_manager, Point(x, y)) if not builder: return None value = 0 personality = area_builder.owner.personality_manager.get( 'ModifiedFieldEvaluator') if new_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: value += personality.add_potato_field_value elif new_field_purpose == BUILDING_PURPOSE.PASTURE: value += personality.add_pasture_value elif new_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: value += personality.add_sugarcane_field_value elif new_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: value += personality.add_tobacco_field_value old_field_purpose = area_builder.plan[(x, y)][0] if old_field_purpose == BUILDING_PURPOSE.POTATO_FIELD: value -= personality.remove_unused_potato_field_penalty elif old_field_purpose == BUILDING_PURPOSE.PASTURE: value -= personality.remove_unused_pasture_penalty elif old_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: value -= personality.remove_unused_sugarcane_field_penalty elif old_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: value -= personality.remove_unused_tobacco_field_penalty return ModifiedFieldEvaluator(area_builder, builder, value, old_field_purpose)
def _create(cls, area_builder, farm_x, farm_y, road_dx, road_dy, min_fields, field_purpose): builder = area_builder.make_builder(BUILDINGS.FARM, farm_x, farm_y, True) if not builder: return None farm_plan = {} # place the farm area road existing_roads = 0 for other_offset in xrange(-3, 6): coords = None if road_dx == 0: coords = (farm_x + other_offset, farm_y + road_dy) else: coords = (farm_x + road_dx, farm_y + other_offset) if not cls._suitable_for_road(area_builder, coords): return None if coords in area_builder.plan and area_builder.plan[coords][0] == BUILDING_PURPOSE.NONE: road = Builder.create(BUILDINGS.TRAIL, area_builder.land_manager, Point(coords[0], coords[1])) if road: farm_plan[coords] = (BUILDING_PURPOSE.ROAD, road) else: farm_plan = None break else: existing_roads += 1 if farm_plan is None: return None # impossible to build some part of the road # place the fields fields = 0 for (dx, dy) in cls.__field_offsets: if fields >= 8: break # unable to place more anyway coords = (farm_x + dx, farm_y + dy) field = area_builder.make_builder(BUILDINGS.POTATO_FIELD, coords[0], coords[1], False) if not field: continue for coords2 in field.position.tuple_iter(): if coords2 in farm_plan: field = None break if field is None: continue # some part of the area is reserved for something else fields += 1 for coords2 in field.position.tuple_iter(): farm_plan[coords2] = (BUILDING_PURPOSE.RESERVED, None) farm_plan[coords] = (field_purpose, None) if fields < min_fields: return None # go for the most fields possible # add the farm itself to the plan for coords in builder.position.tuple_iter(): farm_plan[coords] = (BUILDING_PURPOSE.RESERVED, None) farm_plan[(farm_x, farm_y)] = (BUILDING_PURPOSE.FARM, builder) # calculate the alignment value and the rectangle that contains the whole farm alignment = 0 min_x, max_x, min_y, max_y = None, None, None, None for x, y in farm_plan: min_x = x if min_x is None or min_x > x else min_x max_x = x if max_x is None or max_x < x else max_x min_y = y if min_y is None or min_y > y else min_y max_y = y if max_y is None or max_y < y else max_y for dx, dy in cls.__moves: coords = (x + dx, y + dy) if coords in farm_plan: continue if coords not in area_builder.plan or area_builder.plan[coords][0] != BUILDING_PURPOSE.NONE: alignment += 1 # calculate the value of the farm road end points (larger is better) personality = area_builder.owner.personality_manager.get('FarmEvaluator') immediate_connections = 0 for other_offset in [-4, 6]: if road_dx == 0: coords = (farm_x + other_offset, farm_y + road_dy) else: coords = (farm_x + road_dx, farm_y + other_offset) if coords in area_builder.land_manager.roads: immediate_connections += personality.immediate_connection_road elif coords in area_builder.plan: if area_builder.plan[coords][0] == BUILDING_PURPOSE.NONE: immediate_connections += personality.immediate_connection_free extra_space = (max_x - min_x + 1) * (max_y - min_y + 1) - 9 * (fields + 2) value = fields + existing_roads * personality.existing_road_importance + \ alignment * personality.alignment_importance - extra_space * personality.wasted_space_penalty + \ immediate_connections * personality.immediate_connection_importance return FarmEvaluator(area_builder, builder, value, farm_plan, fields, field_purpose)
def _create(cls, area_builder, farm_x, farm_y, road_dx, road_dy, min_fields, field_purpose): builder = area_builder.make_builder(BUILDINGS.FARM, farm_x, farm_y, True) if not builder: return None farm_plan = {} # place the farm area road existing_roads = 0 for other_offset in xrange(-3, 6): coords = None if road_dx == 0: coords = (farm_x + other_offset, farm_y + road_dy) else: coords = (farm_x + road_dx, farm_y + other_offset) if not cls._suitable_for_road(area_builder, coords): return None if coords in area_builder.plan and area_builder.plan[coords][ 0] == BUILDING_PURPOSE.NONE: road = Builder.create(BUILDINGS.TRAIL, area_builder.land_manager, Point(coords[0], coords[1])) if road: farm_plan[coords] = (BUILDING_PURPOSE.ROAD, road) else: farm_plan = None break else: existing_roads += 1 if farm_plan is None: return None # impossible to build some part of the road # place the fields fields = 0 for (dx, dy) in cls.__field_offsets: if fields >= 8: break # unable to place more anyway coords = (farm_x + dx, farm_y + dy) field = area_builder.make_builder(BUILDINGS.POTATO_FIELD, coords[0], coords[1], False) if not field: continue for coords2 in field.position.tuple_iter(): if coords2 in farm_plan: field = None break if field is None: continue # some part of the area is reserved for something else fields += 1 for coords2 in field.position.tuple_iter(): farm_plan[coords2] = (BUILDING_PURPOSE.RESERVED, None) farm_plan[coords] = (field_purpose, None) if fields < min_fields: return None # go for the most fields possible # add the farm itself to the plan for coords in builder.position.tuple_iter(): farm_plan[coords] = (BUILDING_PURPOSE.RESERVED, None) farm_plan[(farm_x, farm_y)] = (BUILDING_PURPOSE.FARM, builder) # calculate the alignment value and the rectangle that contains the whole farm alignment = 0 min_x, max_x, min_y, max_y = None, None, None, None for x, y in farm_plan: min_x = x if min_x is None or min_x > x else min_x max_x = x if max_x is None or max_x < x else max_x min_y = y if min_y is None or min_y > y else min_y max_y = y if max_y is None or max_y < y else max_y for dx, dy in cls.__moves: coords = (x + dx, y + dy) if coords in farm_plan: continue if coords not in area_builder.plan or area_builder.plan[ coords][0] != BUILDING_PURPOSE.NONE: alignment += 1 # calculate the value of the farm road end points (larger is better) personality = area_builder.owner.personality_manager.get( 'FarmEvaluator') immediate_connections = 0 for other_offset in [-4, 6]: if road_dx == 0: coords = (farm_x + other_offset, farm_y + road_dy) else: coords = (farm_x + road_dx, farm_y + other_offset) if coords in area_builder.land_manager.roads: immediate_connections += personality.immediate_connection_road elif coords in area_builder.plan: if area_builder.plan[coords][0] == BUILDING_PURPOSE.NONE: immediate_connections += personality.immediate_connection_free extra_space = (max_x - min_x + 1) * (max_y - min_y + 1) - 9 * (fields + 2) value = fields + existing_roads * personality.existing_road_importance + \ alignment * personality.alignment_importance - extra_space * personality.wasted_space_penalty + \ immediate_connections * personality.immediate_connection_importance return FarmEvaluator(area_builder, builder, value, farm_plan, fields, field_purpose)