def __draw_geology(self, item): ########################################################################### draw_mode = curr_draw_mode() prequire(is_geological(draw_mode), "Bad draw mode ", draw_mode) self._draw_with_offset("geology", item.__class__.__name__.lower() + ".jpg", (100, 100)) # Figure out what string to print and what color it should be if (draw_mode == DrawMode.GEOLOGY): pass # already drawn elif (draw_mode in [DrawMode.TENSION, DrawMode.MAGMA]): value = item.tension() if draw_mode == DrawMode.TENSION \ else item.magma() to_draw = ("%.3f" % value) if (value < .333): color = _GREEN elif (value < .666): color = _YELLOW else: color = _RED self._print_with_offset(to_draw, color, (30, 40)) else: prequire(False, "Should not draw geology in mode: ", draw_mode)
def __gain_exp_impl(self, exp): ########################################################################### check_access(self.ALLOW_GAIN_EXP) self.__exp += exp # Check for level-up while (self.__exp >= self.__next_level_cost): self.__level += 1 old_max = self.__max_mana self.__max_mana = self.__MANA_POOL_FUNC(self.level()) self.__mana_regen = self.__max_mana * self.__MANA_REGEN_RATE increase = self.__max_mana - old_max self.__mana += increase self.__exp -= self.__next_level_cost self.__next_level_cost = self.__EXP_LEVEL_COST_FUNC(self.level()) # Check exp invariant prequire(self.__exp < self.__next_level_cost, "exp(", self.__exp, ") > ", "next_level_cost(", self.__next_level_cost, ")") # Check mana invariant prequire(self.__mana <= self.__max_mana, "mana(", self.__mana, ") > max_mana(", self.__max_mana, ")")
def exp_growth(base, value, threshold=0, diminishing_returns=None): ############################################################################### prequire(base > 1, "Invalid base: ", base) x = value - threshold if (x < 0.0): # We're more aggressive on the penalty side. We want to reward # the player for having all of the ingredients in place, so # being weak in a certain ingrediant is heavily penalized. return pow(base + ((base - 1.0) * 2), x) elif (diminishing_returns is None or x <= diminishing_returns): return pow(base, x) else: beyond_dim = x - diminishing_returns # Compute divisor of exponent based on base; IE divisor of 2 would # give sqrt behavior. The idea is for the more-slowly growing functions # to plateou faster. divisor = 2.0 if (base <= 1.02): divisor = 5.0 elif (base <= 1.03): divisor = 4.0 elif (base <= 1.05): divisor = 3.0 additional = pow(beyond_dim, 1.0 / divisor) - 1 # root if (additional < 0.0): additional = 0.0 return pow(base, diminishing_returns) + additional
def __destroy_defense(self, levels): ########################################################################### check_access(self.ALLOW_DESTROY_DEFENSE) prequire(self.defense() >= levels, "Invalid destroy levels: ", levels) self.__defense -= levels
def _compute_nearby_food_and_prod_tiles(location, filter_tiles_near_other_cities=False): ############################################################################### """ Returns a 2-ple of (food-tiles, production-tiles); both lists are sorted from highest to lowest based on yield. Only unworked tiles are added. """ world = engine().world() food_tiles = [] # sorted highest to lowest prod_tiles = [] # sorted highest to lowest row, col = location.unpack() for row_delta in xrange(-1, 2): for col_delta in xrange(-1, 2): # Cannot work tile that has city if (row_delta != 0 or col_delta != 0): loc_delta = Location(row + row_delta, col + col_delta) if (world.in_bounds(loc_delta) and not (filter_tiles_near_other_cities and _is_too_close_to_any_city(loc_delta, 1))): tile = world.tile(loc_delta) prequire( not (filter_tiles_near_other_cities and tile.worked()), "How can tile be worked if it's not near a city") if (not tile.worked()): if (tile.yield_().food > 0): _ordered_insert(food_tiles, tile) else: _ordered_insert(prod_tiles, tile) return food_tiles, prod_tiles
def help(cls, extra_args=None): ########################################################################### if (_is_text_interface()): full_usage = "%s Learnable spells:\n" % cls._TEXT_USAGE # Add info on learnable spells to usage string for spell_name, spell_level in engine().player().learnable(): full_usage += " %s%s\n" % (spell_name, "" if spell_level == 1 else " (new)") return _create_text_help_str(cls, full_usage) else: prequire(extra_args is not None and len(extra_args) == 1, "Expect spell name in extra_args") spell_name = extra_args[0] spell = SpellFactory.create_spell(spell_name) help_str = cls._GRAPHICAL_USAGE help_str += "\nDescription of %s spell:\n" % spell_name help_str += spell.info() + "\n" help_str += "Player has skill level %d in this spell\n" % \ engine().player().spell_skill(spell_name) return help_str
def __cycle_turn_impl(self): ########################################################################### check_access(self.ALLOW_CYCLE_TURN) cls = self.__class__ world = engine().world() cities_orig = list(world.cities()) # Manage cities. Note that this may cause additional cities to # be created, which is why we needed the list copy above for city in cities_orig: city.cycle_turn() # Adjust tech based on population tech_points = cls.__TECH_POINT_FUNC(self.population()) self.__tech_points += tech_points # Check if level-up in tech while (self.__tech_points >= self.__next_tech_level_cost): self.__tech_level += 1 self.__tech_points -= self.__next_tech_level_cost # rollover points self.__next_tech_level_cost = \ cls.__TECH_NEXT_LEVEL_COST_FUNC(self.tech_level()) # Tech invariants prequire(self.__tech_points < self.__next_tech_level_cost, "Expect tech-points(", self.__tech_points, ") < tech-cost(", self.__next_tech_level_cost, ")")
def __compute_atmos_color(self, draw_mode, field_value): ########################################################################### for upper_bound, color in self._ATMOS_FIELD_COLOR_MAP[draw_mode]: if (field_value < upper_bound): return color prequire(False, "Failed to find color for ", draw_mode, ", val ", field_value)
def __compute_color(self, draw_mode, field_value, color_map): ########################################################################### for upper_bound, color in color_map[draw_mode]: if (field_value < upper_bound): return color prequire(False, "Failed to find color for ", draw_mode, ", val ", field_value)
def instance(cls): """ Retrieve singleton instance. Note this does *not* construct the singleton if it does not exist; the private creation class method needs to be called to create the singleton. """ prequire(cls.__instance is not None, "Uninitialized global instance") return cls.__instance
def _base_tension_buildup(cls): prequire(False, "Must override") # # ==== Implementation ==== # ########################################################################### def __init_impl(self, plate_movement):
def __cast_impl(self, spell): ########################################################################### check_access(self.ALLOW_CAST) self.__mana -= spell.cost() # Maintain mana invariant (m_mana is unsigned, so going below zero will # cause it to become enormous). prequire(self.__mana <= self.__max_mana, "mana(", self.__mana, ") > max_mana(", self.__max_mana, ")")
def create_interface(): ############################################################################### interface = _get_inteface_config_str() if (Interfaces.TEXT == interface): return TextInterface() elif (Interfaces.PYGAME == interface): return PygameInterface() else: prequire(False, "Missing support for ", interface)
def __cycle_turn_impl(self): ########################################################################### check_access(self.ALLOW_CYCLE_TURN) # Tension/magma build up more slowly as they reach 100% self.__tension += (1 - self.__tension) * self.__tension_buildup self.__magma += (1 - self.__magma) * self.__magma_buildup prequire(self.__tension < 1.0, "Invariant violated: ", self.__tension) prequire(self.__magma < 1.0, "Invariant violated: ", self.__magma)
def __validate_invariants_impl(self): ########################################################################### level_sum = 0 for spell_name, spell_level in self.__learned_spells.iteritems(): prequire(spell_level >= 1 and spell_level <= self._MAX_SPELL_LEVEL, "Bad spell level: ", spell_level) level_sum += spell_level prequire(self.__num_learned == level_sum, "Num-learned invariant failed")
def __contains_impl(self, spell_spec): ########################################################################### if (isinstance(spell_spec, Spell)): spell_tuple = (spell_spec.name(), spell_spec.level()) else: prequire(type(spell_spec) == tuple) spell_tuple = spell_spec spell_name, spell_level = spell_tuple return spell_name in self.__learned_spells and \ spell_level <= self.__learned_spells[spell_name]
def __cycle_turn_impl(self): ########################################################################### check_access(self.ALLOW_CYCLE_TURN) self.__mana += self.__mana_regen if (self.__mana > self.__max_mana): self.__mana = self.__max_mana # Maintain mana invariant prequire(self.__mana <= self.__max_mana, "m_mana(", self.__mana, ") > m_max_mana(", self.__max_mana, ")")
def __init__(self): prequire(False, "Do not instantiate Command") # # ==== Public API ==== # # # Instance API # def apply(self):
def parse_command(cls, text): ########################################################################### """ Given some command text, create a Command object """ # Get command name tokens = text.split() prequire(tokens, "Empty string made it into CommandFactory") name = tokens[0] # Instantiate and return new Command object return cls.get(name)(tokens[1:])
def _instance(cls): ########################################################################### """ Do not call. Use free function to get a handle to an Engine """ if (cls.__instance is None): prequire(not cls.__initializing, "Engine instantiation has re-entered itself") cls.__initializing = True cls.__instance = Engine() cls.__initializing = False return cls.__instance
def __build_infra(self, tile): ########################################################################### prequire(tile.can_build_infra(), "Error in build eval") infra_level = tile.infra_level() next_infra_level = infra_level + 1 prod_cost = next_infra_level * City._INFRA_PROD_COST if (prod_cost < self.__prod_bank): self.__prod_bank -= prod_cost tile.build_infra() return True return False
def __kill_impl(self, killed): ########################################################################### check_access(self.ALLOW_KILL) prequire(self.__population >= killed, "Invalid killed: ", killed) self.__population -= killed while (self.__population < self.__next_rank_pop / City._CITY_RANK_UP_MULTIPLIER and self.__rank > 1): self.__rank -= 1 self.__next_rank_pop /= City._CITY_RANK_UP_MULTIPLIER
def help(cls, extra_args=None): ########################################################################### if (_is_text_interface()): return _create_text_help_str(cls, cls._TEXT_USAGE) else: prequire(extra_args is not None and len(extra_args) == 1, "Expect draw_mode in extra_args") draw_mode = extra_args[0] help_str = cls._GRAPHICAL_USAGE help_str += "\nDescription of draw-mode %s:\n" % draw_mode help_str += explain_draw_mode(draw_mode) return help_str
def __get_field_for_draw_mode(self, item, draw_mode): ########################################################################### if (draw_mode == DrawMode.WIND): return item.wind().speed() elif (draw_mode == DrawMode.DEWPOINT): return item.dewpoint() elif (draw_mode == DrawMode.TEMPERATURE): return item.temperature() elif (draw_mode == DrawMode.PRESSURE): return item.pressure() elif (draw_mode == DrawMode.PRECIP): return item.precip() else: prequire(False, "Bad draw mode: ", draw_mode)
def __draw_time(self, item): ########################################################################### # Compute color if (item.season() == Season.WINTER): color = BLUE elif (item.season() == Season.SPRING): color = GREEN elif (item.season() == Season.SUMMER): color = RED elif (item.season() == Season.FALL): color = YELLOW else: prequire(False, "Unhandled season ", item.season()) cprint(color, item.season(), ", Year ", item.year())
def __init_impl(self, width, height, tiles): ########################################################################### self.__width = width self.__height = height self.__time = Time() self.__rows = [] total = 0 for idx, tile in enumerate(tiles): if (idx % width == 0): self.__rows.append([]) self.__rows[-1].append(tile) total += 1 prequire(total == width * height, "Wrong number of tiles") self.__recent_anomalies = [] self.__cities = []
def draw(self, item): ########################################################################### if (isinstance(item, Time)): self.__draw_time(item) elif (isinstance(item, Geology)): self.__draw_geology(item) elif (isinstance(item, Player)): self.__draw_player(item) elif (isinstance(item, PlayerAI)): self.__draw_player_ai(item) elif (isinstance(item, Atmosphere)): self.__draw_atmosphere(item) elif (isinstance(item, Anomaly)): self.__draw_anomaly(item) elif (isinstance(item, World)): self.__draw_world(item) elif (isinstance(item, WorldTile)): self.__draw_world_tile(item) else: prequire(False, "Class not drawable: ", item.__class__)
def __draw_time(self, item): ########################################################################### # Compute color if (item.season() == Season.WINTER): color = _BLUE elif (item.season() == Season.SPRING): color = _GREEN elif (item.season() == Season.SUMMER): color = _RED elif (item.season() == Season.FALL): color = _YELLOW else: prequire(False, "Unhandled season ", item.season()) self._print_with_offset("%s, Year: %s" % (item.season(), item.year()), color, (200, 5), font=self._LARGE_FONT) self.__y_pos += 30 self.__x_pos = 0
def __draw_geology(self, item): ########################################################################### draw_mode = curr_draw_mode() prequire(is_geological(draw_mode), "Bad draw mode ", draw_mode) expected_length = self.TILE_TEXT_WIDTH # Figure out what string to print and what color it should be if (draw_mode == DrawMode.GEOLOGY): color, symbol = self._GEOLOGY_MAP[item.__class__] to_draw = symbol.center(expected_length) elif (draw_mode in [DrawMode.TENSION, DrawMode.MAGMA]): value = item.tension() if draw_mode == DrawMode.TENSION \ else item.magma() to_draw = ("%.3f" % value).center(expected_length) if (value < .333): color = GREEN elif (value < .666): color = YELLOW else: color = RED else: prequire(False, "Should not draw geology in mode: ", draw_mode) prequire(len(to_draw) == self.TILE_TEXT_WIDTH, "Symbol '", to_draw, "' is wrong length") cprint(color, to_draw)
def __draw_land_property(self, draw_mode, tile): ########################################################################### self.__draw_land(tile) if (draw_mode == DrawMode.MOISTURE): field = tile.soil_moisture() elif (draw_mode == DrawMode.YIELD): field = tile.yield_() elif (draw_mode == DrawMode.ELEVATION): field = tile.elevation() elif (draw_mode == DrawMode.SNOWPACK): field = tile.snowpack() elif (draw_mode == DrawMode.SEASURFACETEMP): field = tile.sea_surface_temp() else: prequire(False, "Unknown draw mode ", draw_mode) if (field is not None): color = self.__compute_color(draw_mode, field, self._LAND_COLOR_MAP) to_draw = self.__determine_precision(field) self._print_with_offset(to_draw, color, (30, 40))