def grow_up(self): info('%s grew up (%d years)' % (self, self.age + 1), village=self.village.name) # Simulates growing up and updates stats self.age += 1 self.baby = self.age <= config['age']['baby'] self.adult = self.age >= config['age']['adulthood'] self.retired = self.age >= config['age']['retirement'] self.calculate_stats() self.actual_stats() # When reaches adulthood, gets into job selection if self.adult and not self.retired and self.job is None: self.job_selection() elif self.adult: # If adult, old and has job, time for retirement, otherwise another year of service if self.job is not None: if self.retired: self.job = None else: self.job.year_service() # Calculates mortality risk self.mortality_risk()
def day_pass(self): # Simulates a day passed in the world info('DAY: %d YEAR: %d' % (self.date['day'], self.date['year']), village=self.name) # Day start self.village1.day_start() self.village2.day_start() # Resolves every action for i in range(config['action-extra']['actions-per-day']): self.village1.population_activities() self.village2.population_activities() self.resolve_actions() self.village1.remove_dead() self.village2.remove_dead() # Day end self.village1.day_end() self.village2.day_end() self.date_update() # Checks if day limit reached cmd_args = get_cmd_args() if 'until' in cmd_args: if self.date['days'] >= cmd_args['until']: # Stops the simulation stop()
def die(self): # Makes villager die info('%s died' % self, village=self.village.name) self.alive = False self.actual_health = 0
def run(self): while True: if not self.should_run: # Should stop break # Waits at barrier before updating again self.barrier.wait() try: self.world_obj.day_pass() if get_cmd_args()['victory']: if len(self.world_obj.village1.population) == 0: info('%s wins' % self.world_obj.village2.name, village=self.world_obj.name) close_dump_file() exit(0) elif len(self.world_obj.village2.population) == 0: info('%s wins' % self.world_obj.village1.name, village=self.world_obj.name) close_dump_file() exit(0) except Exception as exc: # Exception occurred, simulation is over raise SimulationError( 'Exception occurred during simulation %s' % exc.__class__.__name__, exc) close_dump_file()
def generate(self, village): # Gets generated list and instantiates villagers and to be appended on the village population to_generate = self.generate_list() for i in to_generate: v = Villager(i['sex'], village, age=i['age']) if 'job' in i: v.job = self.job = Job.get_job(i['job']) info('Generated %s: %s and %d years old (%s)' % (v, v.sex, v.age, v.job), village='Gen') else: info('Generated %s: %s and %d years old' % (v, v.sex, v.age), village='Gen') # Puts the generated villager in the population village.population.append(v)
def process_healing(villager1, villager2, villager_index): # Simulates a healing made by the healer on other villager info('%s heals %s' % (villager1, villager2), village=villager1.village.name) # Calculates the amount to be healed healing_amount = config['jobs']['healer']['healing-base'] * villager1.actual_intelligence if (villager2.actual_health + healing_amount) > villager2.health: # If healing more than health, health becomes full instead villager2.actual_health = villager2.health else: # Otherwise, heals the patient by the amount villager2.actual_health += healing_amount return villager_index,
def process_rest(villager, target_index): # Simulates resting info('%s rests' % villager.name, village=villager.village.name) if not villager.alive: return target_index # Calculates amount to heal heal_amount = int(villager.health * config['action-extra']['rest-percentage'] / 100) print('heal', heal_amount) # If life will be full, sets to full life instead if (villager.actual_health + heal_amount) > villager.health: villager.actual_health = villager.health else: villager.actual_health += heal_amount villager.actual_stats() return ()
def job_selection(self): # Simulates a job selection process sex_map = {'male': 'man', 'female': 'woman'} selected = None jobs = config['jobs']['names'] job_probabilities = [] for i in range(len(jobs)): job_probabilities.append( config['jobs']['selection'][sex_map[self.sex]][i] + reduce(lambda a, b: a + b, job_probabilities[:i + 1], 0)) rand_num = randint(0, 100) # Selects job based on the probabilities of each sex for i in range(len(job_probabilities)): if rand_num <= job_probabilities[i]: selected = jobs[i] break info('%s became %s' % (self, selected), village=self.village.name) self.job = Job.get_job(selected)
def process_procreating(villager1, villager2, villager_index, partner_index): # Simulates procreating between partners info('%s procreates with %s' % (villager1, villager2), village=villager1.village.name) # If one is sterile, not happening if villager1.fertility == 0: return villager_index, if villager2.fertility == 0: return partner_index, # Gets the average fertility based on both villagers avg_fertility = (villager1.fertility + villager2.fertility) / 2 chance_reduction = config['jobs']['breeder']['multiple-babies-chance-reduction'] max_children = config['jobs']['breeder']['maximum-children-per-pregnancy'] children = [] stat_range = [1 - config['base-stats']['stat-variation'], 1 + config['base-stats']['stat-variation']] # Tries fertilization for i in range(0, max_children): if uniform(0, 1) <= avg_fertility * (chance_reduction ** i): # Success baby_sex = choice(('male', 'female')) sex = {'male': 'man', 'female': 'woman'}[baby_sex] max_var = config['base-stats']['stat-variation'] + 1 children.append(({ 'health': maximum( int((villager1.base_health + villager2.base_health) / 2 * uniform(*stat_range)), int(config['base-stats'][sex]['health'] * max_var)), 'strength': maximum( int((villager1.base_strength + villager2.base_strength) / 2 * uniform(*stat_range)), int(config['base-stats'][sex]['strength'] * max_var)), 'resistance': maximum( int((villager1.base_resistance + villager2.base_resistance) / 2 * uniform(*stat_range)), int(config['base-stats'][sex]['resistance'] * max_var)), 'intelligence': maximum( int((villager1.base_intelligence + villager2.base_intelligence) / 2 * uniform(*stat_range)), int(config['base-stats'][sex]['intelligence'] * max_var)), 'accuracy': maximum((villager1.base_accuracy + villager2.base_accuracy) / 2, config['base-stats']['base-accuracy'] * max_var) }, baby_sex)) # Sets the baby data on the female villager if villager1.sex == 'female': villager1.pregnant = True villager1.pregnant_time = 0 villager1.children_pregnant = children else: villager2.pregnant = True villager2.pregnant_time = 0 villager2.children_pregnant = children return villager_index, partner_index
def process_combat(villager1, villager2, target_off_guard, villager_index, target_index): # Simulates a combat between the attacker and the target info('%s attacks %s' % (villager1, villager2), village=villager1.village.name) not_flee_chance = 1 - config['action-extra']['flee-chance'] resistance_effect = config['action-extra']['resistance-effect'] off_guard_penalty = config['action-extra']['off-guard-penalty'] turns = 0 # Runs loop while there's no fleeing # If target is baby, can't flee # When one or both villagers die, fight is over while True: if not villager1.alive or not villager2.alive: break turns += 1 # Calculates flee chance if uniform(0, 1) > (1 - not_flee_chance ** turns) and not villager2.baby: # Target fled, fight is over break # Villager 1 attacks if randint(0, 100) <= villager1.actual_accuracy and villager1.alive: target_resistance = villager2.actual_resistance if target_off_guard: # Applies off-guard penalty target_resistance *= 1 - off_guard_penalty target_resistance = int(target_resistance) # Calculates damage dmg = villager1.actual_strength dmg *= ((1 - resistance_effect) ** target_resistance) dmg = int(dmg) # Applies damage villager2.lose_health(dmg) if randint(0, 100) <= villager2.actual_accuracy and villager2.alive: # If villager is baby, can't do anything if not villager2.baby: # Calculates damage dmg = villager2.actual_strength dmg *= ((1 - resistance_effect) ** villager1.actual_resistance) dmg = int(dmg) # Applies damage villager1.lose_health(dmg) return villager_index, target_index
w = World(v1, v2) # Instantiates an updater thread object to deal with day loops wu = WorldUpdater(w, barrier) # Instantiates plot animation handler pl = PlotAnim(config['village-names'], wu, barrier) # Starts day loop and plotting wu.start() pl.start_animation() if __name__ == '__main__': try: main() except Exception as e: # If any exception occurs, logs it and exits info('') info('[EXCEPTION]') info('Exception occurred during program execution:\n %s:\n %s' % (e, format_exc())) print('Exception occurred during program execution:\n %s:\n %s' % (e, format_exc())) exit(-1)