def r2_procreate(self, abm, ca): neighborhood = ca.get_agent_neighborhood(self.x, self.y, 1) if self.is_fertile(): free_cells = [v[0] for v in list(neighborhood.values()) if v[1] is False and (v[0].x != self.x and v[0].y != self.y)] mates = [v[1] for v in list(neighborhood.values()) if not v[1] is False] if mates: m = get_RNG().choice(mates) both_wealthy1 = (self.sugar >= self.init_sugar and m.sugar >= m.init_sugar) both_wealthy2 = (self.spice >= self.init_spice and m.spice >= m.init_spice) # All criteria is fulfilled to procreate! if free_cells and m.is_fertile() and m.gender != self.gender and both_wealthy1 and both_wealthy2: # Take one free cell to place Junior there. c = get_RNG().choice(free_cells) n_x = c.x n_y = c.y # Give him / her initial resources n_su = int(self.init_sugar / 2) + int(m.init_sugar / 2) n_sp = int(self.init_spice / 2) + int(m.init_spice / 2) self.sugar -= int(self.init_sugar / 2) self.spice -= int(self.init_spice / 2) m.sugar -= int(m.init_sugar / 2) m.spice -= int(m.init_spice / 2) # Fuse mommy's and daddy's chromosomes to create Juniors attributes. # This is the actual creation of the baby. Behold the wonders of nature! n_chromosome = self.chromosome.merge_with(m.chromosome) child = SSAgent(n_x, n_y, self.gc, n_su, n_sp, 0, n_chromosome) # Give the parents a reference to their newborn so they can, # inherit their wealth to it before their inevitable demise. self.children.append(child) m.children.append(child) # Update the abm that it has to schedule a new agent. abm.add_agent(child)
def get_cell_with_pheromone(self, target_ph, neighborhood): """ Gets the cell with highest pheromone value (or random if no pheromones present) from the immediate neighborhood. :param: neighborhood is a dict of (x, y) -> cell mappings, where cell is a tuple of (ca_cell, [agent(s) on cell]). If no agent is on the cell then the list in the tuple is simply 'False' """ result = None result_list = [] backup_list = [] best_cell = None max_ph = 0 # Choose the possible directions the ants can currently look at. if self.current_dir == 5: possible_dirs = [4, 5, 0] elif self.current_dir == 0: possible_dirs = [5, 0, 1] else: possible_dirs = [self.current_dir - 1, self.current_dir, self.current_dir + 1] for i in possible_dirs: d = self.directions[i] _x = self.x + d[0] _y = self.y + d[1] if (_x, _y) in neighborhood: cell = neighborhood[_x, _y] if cell[0].pheromones[target_ph] > 0.00: # and (not cell[1] or len(cell[1]) < 10): ph = cell[0].pheromones[target_ph] if ph > max_ph: best_cell = cell max_ph = ph self.current_dir = i result_list.append((cell, ph, i)) # elif not cell[1] or len(cell[1]) < 10: else: backup_list.append((cell, i)) if result_list: if get_RNG().random() < 0.10: choice = AntAgent.weighted_choice(result_list) # choice = get_RNG().choice(result_list) result = choice[0] self.current_dir = choice[1] else: result = best_cell elif backup_list: choice = get_RNG().choice(backup_list) result = choice[0] self.current_dir = choice[1] else: # print('Ant Error: no cells found to move to!') self.current_dir = AntAgent.get_opposite_direction(self.current_dir) return self.get_cell_with_pheromone(target_ph, neighborhood) # Add a small random factor to the movement. return result
def __init__(self, x, y, gc, team, min_density, power): super().__init__(x, y, gc) self.min_density = min_density self.strategy_walk = cab_rng.get_RNG().randint(0, 1) # team.strategy_walk # 0 - random, 1 - min-based self.strategy_seed = cab_rng.get_RNG().randint(0, 1) # team.strategy_seed # 0 - random, 1 - min-based self.score = 0 self.power = power self.color = team.color self.team = team
def get_island_landscape(self): l1 = {} l2 = {} last_rand = 0 for j in range(self.height): for i in range(self.width): q = i - math.floor(j / 2) if get_RNG().randint(0, 100) < self.factor: c = get_RNG().choice([True, False]) if c: # last_rand = int(get_RNG().triangular(self.deepest, self.highest, self.water_level)) # l1[q, j] = last_rand l1[q, j] = self.highest for d in self.gc.HEX_DIRECTIONS: l1[q + d[0], j + d[1]] = int(get_RNG().triangular( self.water_level, self.highest, self.highest * 0.75)) # try: # l1[q + d[0], j + d[1]] = self.highest * 2 # except KeyError: # pass else: l1[q, j] = self.deepest for d in self.gc.HEX_DIRECTIONS: l1[q + d[0], j + d[1]] = int(get_RNG().triangular( self.deepest, self.water_level, self.deepest * 0.75)) else: l1[q, j] = self.water_level for _ in range(self.smoothness): for j in range(self.height): for i in range(self.width): n = 0 f = 0 q = i - math.floor(j / 2) for d in self.gc.HEX_DIRECTIONS: if not (d[0] == 0 and d[1] == 0): try: n += 1 f += l1[q + d[0], j + d[1]] except KeyError: pass avg = f / n if avg > l1[q, j]: diff = avg - l1[q, j] l2[q, j] = l1[q, j] + (diff * self.slope) elif avg < l1[q, j]: diff = l1[q, j] - avg l2[q, j] = l1[q, j] - (diff * self.slope) else: l2[q, j] = l1[q, j] l1, l2 = l2, l1 return l1
def __init__(self, x, y, gc, team, min_density, power): super().__init__(x, y, gc) self.min_density = min_density self.strategy_walk = cab_rng.get_RNG().randint( 0, 1) # team.strategy_walk # 0 - random, 1 - min-based self.strategy_seed = cab_rng.get_RNG().randint( 0, 1) # team.strategy_seed # 0 - random, 1 - min-based self.score = 0 self.power = power self.color = team.color self.team = team
def get_island_landscape(self): l1 = {} l2 = {} last_rand = 0 for j in range(self.height): for i in range(self.width): q = i - math.floor(j / 2) if get_RNG().randint(0, 100) < self.factor: c = get_RNG().choice([True, False]) if c: # last_rand = int(get_RNG().triangular(self.deepest, self.highest, self.water_level)) # l1[q, j] = last_rand l1[q, j] = self.highest for d in self.gc.HEX_DIRECTIONS: l1[q + d[0], j + d[1]] = int(get_RNG().triangular(self.water_level, self.highest, self.highest * 0.75)) # try: # l1[q + d[0], j + d[1]] = self.highest * 2 # except KeyError: # pass else: l1[q, j] = self.deepest for d in self.gc.HEX_DIRECTIONS: l1[q + d[0], j + d[1]] = int(get_RNG().triangular(self.deepest, self.water_level, self.deepest * 0.75)) else: l1[q, j] = self.water_level for _ in range(self.smoothness): for j in range(self.height): for i in range(self.width): n = 0 f = 0 q = i - math.floor(j / 2) for d in self.gc.HEX_DIRECTIONS: if not (d[0] == 0 and d[1] == 0): try: n += 1 f += l1[q + d[0], j + d[1]] except KeyError: pass avg = f / n if avg > l1[q, j]: diff = avg - l1[q, j] l2[q, j] = l1[q, j] + (diff * self.slope) elif avg < l1[q, j]: diff = l1[q, j] - avg l2[q, j] = l1[q, j] - (diff * self.slope) else: l2[q, j] = l1[q, j] l1, l2 = l2, l1 return l1
def perceive_and_act(self, abm, ca): self.has_spawned_creepling_this_turn = False neighborhood = ca.get_empty_agent_neighborhood(self.x, self.y, 1) possible_cells = list(neighborhood.values()) for c in possible_cells: if not c.team or c.team.number != self.team.number: self.dead = True break if self.current_creeplings < self.max_creeplings and not self.has_spawned_creepling_this_turn: density = cab_rng.get_RNG().randint(1, 15) power = cab_rng.get_RNG().randint(1, 10) abm.add_agent(CreeplingAgent( c.x, c.y, self.gc, self.team, density, power)) self.current_creeplings += 1 self.has_spawned_creepling_this_turn = True
def r4_diseases(self): """ All diseases, the agent is currently infected with, are trying to spread to its neighbors. """ #for n in neighbors: # if n[1] and not n[1].dead and not self.dead: # for _, d in self.diseases.items(): # d.spread(n[1]) for _, d in self.diseases.items(): targets = [ agent for (cell, agent) in self.neighbors if agent is not None and not agent.dead and not self.dead ] if targets: victim = get_RNG().choice(targets) d.spread(victim) # Let the immune system build another instance # and then attempt to fight the diseases. self.im_create_antibodies() self.immune_reaction() # Reset the metabolism values of the agent to clear all past diseases. # That way, the diseases just fought off by the immune system are not longer # afflicting the body and possible new diseases can act on the agent. self.meta_sugar = self.chromosome.meta_sugar self.meta_spice = self.chromosome.meta_spice # Have the diseases affect the agent for _, d in self.diseases.items(): d.affect(self)
def im_create_antibodies(self): if self.fertility[0] < self.age < self.fertility[1] and len(self.immune_system) <= 10: is_copy = copy.deepcopy(self.chromosome.immune_system) length = len(is_copy) index = get_RNG().choice(range(length)) is_copy[index] = 1 - is_copy[index] self.immune_system.append("".join(map(str, is_copy)))
def get_coastal_landscape(self): l1 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] l2 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] for j in range(self.y_dim): for i in range(self.x_dim): # l1[i][j] = int(get_RNG().triangular(self.deepest, self.highest, 5))s mode = (((i + j) / 200) * 20) - 15 l1[i][j] = int(cab_rng.get_RNG().triangular( self.deepest + 2 * mode, self.highest + 2 * mode, mode)) for _ in range(self.smoothness): for j in range(self.y_dim): for i in range(self.x_dim): n = 0 f = 0 for cy in range(-1, 2): for cx in range(-1, 2): if not (cy == 0 and cx == 0): try: n += 1 f += l1[i + cx][j + cy] except IndexError: pass avg = f / n if avg > l1[i][j]: diff = avg - l1[i][j] l2[i][j] = l1[i][j] + (diff * self.slope) elif avg < l1[i][j]: diff = l1[i][j] - avg l2[i][j] = l1[i][j] - (diff * self.slope) else: l2[i][j] = l1[i][j] l1, l2 = l2, l1 return l1
def get_coastal_landscape(self): l1 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] l2 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] for j in range(self.y_dim): for i in range(self.x_dim): # l1[i][j] = int(get_RNG().triangular(self.deepest, self.highest, 5))s mode = (((i + j) / 200) * 20) - 15 l1[i][j] = int(cab_rng.get_RNG().triangular(self.deepest + 2 * mode, self.highest + 2 * mode, mode)) for _ in range(self.smoothness): for j in range(self.y_dim): for i in range(self.x_dim): n = 0 f = 0 for cy in range(-1, 2): for cx in range(-1, 2): if not (cy == 0 and cx == 0): try: n += 1 f += l1[i + cx][j + cy] except IndexError: pass avg = f / n if avg > l1[i][j]: diff = avg - l1[i][j] l2[i][j] = l1[i][j] + (diff * self.slope) elif avg < l1[i][j]: diff = l1[i][j] - avg l2[i][j] = l1[i][j] - (diff * self.slope) else: l2[i][j] = l1[i][j] l1, l2 = l2, l1 return l1
def perceive_and_act(self, abm, ca): self.has_spawned_creepling_this_turn = False neighborhood = ca.get_empty_agent_neighborhood(self.x, self.y, 1) possible_cells = list(neighborhood.values()) for c in possible_cells: if not c.team or c.team.number != self.team.number: self.dead = True break if self.current_creeplings < self.max_creeplings and not self.has_spawned_creepling_this_turn: density = cab_rng.get_RNG().randint(1, 15) power = cab_rng.get_RNG().randint(1, 10) abm.add_agent( CreeplingAgent(c.x, c.y, self.gc, self.team, density, power)) self.current_creeplings += 1 self.has_spawned_creepling_this_turn = True
def r4_diseases(self): """ All diseases, the agent is currently infected with, are trying to spread to its neighbors. """ #for n in neighbors: # if n[1] and not n[1].dead and not self.dead: # for _, d in self.diseases.items(): # d.spread(n[1]) for _, d in self.diseases.items(): targets = [agent for (cell, agent) in self.neighbors if agent is not None and not agent.dead and not self.dead] if targets: victim = get_RNG().choice(targets) d.spread(victim) # Let the immune system build another instance # and then attempt to fight the diseases. self.im_create_antibodies() self.immune_reaction() # Reset the metabolism values of the agent to clear all past diseases. # That way, the diseases just fought off by the immune system are not longer # afflicting the body and possible new diseases can act on the agent. self.meta_sugar = self.chromosome.meta_sugar self.meta_spice = self.chromosome.meta_spice # Have the diseases affect the agent for _, d in self.diseases.items(): d.affect(self)
def get_coastal_landscape(self): l1 = {} l2 = {} for j in range(self.height): for i in range(self.width): # l1[i][j] = int(get_RNG().triangular(self.deepest, self.highest, 5))s q = i - math.floor(j / 2) mode = (((i + j) / 200) * 5) + self.water_level l1[q, j] = int(get_RNG().triangular(self.deepest + 2 * mode, self.highest + 2 * mode, mode)) # l1[i][j] = int(get_RNG().triangular(self.deepest + 2 * mode, self.highest + 2 * mode, mode)) for _ in range(self.smoothness): for j in range(self.height): for i in range(self.width): q = i - math.floor(j / 2) n = 0 f = 0 for d in self.gc.HEX_DIRECTIONS: if not (d[0] == 0 and d[1] == 0): try: n += 1 f += l1[q + d[0], j + d[1]] except KeyError: pass avg = f / n if avg > l1[q, j]: diff = avg - l1[q, j] l2[q, j] = l1[q, j] + (diff * self.slope) elif avg < l1[q, j]: diff = l1[q, j] - avg l2[q, j] = l1[q, j] - (diff * self.slope) else: l2[q, j] = l1[q, j] l1, l2 = l2, l1 return l1
def map_genome_to_attributes(self): """ Decodes the genome and creates the attribute of the individual. """ # The meta and init attributes cannot become smaller than 1, # even though that is possible by the encoding. We have to avoid that. meta_sugar = Chromosome.choose_dominant_gene(self.get_genome_substring('meta_sugar')) meta_spice = Chromosome.choose_dominant_gene(self.get_genome_substring('meta_spice')) init_sugar = Chromosome.choose_dominant_gene(self.get_genome_substring('init_sugar')) init_spice = Chromosome.choose_dominant_gene(self.get_genome_substring('init_spice')) vision = Chromosome.choose_dominant_gene(self.get_genome_substring('vision')) gender = get_RNG().choice(self.get_genome_substring('gender')) f1 = Chromosome.choose_dominant_gene(self.get_genome_substring('fertility_1')) f2 = Chromosome.choose_dominant_gene(self.get_genome_substring('fertility_2')) dying_age = Chromosome.choose_dominant_gene(self.get_genome_substring('dying_age')) self.meta_sugar = max(int(meta_sugar, 2), 1) self.meta_spice = max(int(meta_spice, 2), 1) self.init_sugar = max(int(init_sugar, 2), 1) self.init_spice = max(int(init_spice, 2), 1) self.vision = int(vision, 2) self.gender = int(gender, 2) self.dying_age = int(dying_age, 2) self.fertility = (int(f1, 2), int(f2, 2)) dna = "".join((meta_sugar, meta_spice, init_sugar, init_spice, vision, gender, f1, f2, dying_age)) self.dna_color = Chromosome.convert_to_color(dna)
def im_create_antibodies(self): if self.fertility[0] < self.age < self.fertility[1] and len( self.immune_system) <= 10: is_copy = copy.deepcopy(self.chromosome.immune_system) length = len(is_copy) index = get_RNG().choice(range(length)) is_copy[index] = 1 - is_copy[index] self.immune_system.append("".join(map(str, is_copy)))
def weighted_choice(choices): total = sum(w for c, w, i in choices) r = get_RNG().uniform(0, total) up_to = 0 for c, w, i in choices: if up_to + w > r: return c, i up_to += w assert False, "Shouldn't get here"
def weighted_choice(choices): total = sum(w for c, w, i in choices) r = get_RNG().uniform(0, total) up_to = 0 for c, w, i in choices: if up_to + w > r: return c, i up_to += w assert False, "Shouldn't get here"
def r2_procreate(self, abm, ca): neighborhood = ca.get_agent_neighborhood(self.x, self.y, 1) if self.is_fertile(): free_cells = [ v[0] for v in list(neighborhood.values()) if v[1] is False and (v[0].x != self.x and v[0].y != self.y) ] mates = [ v[1] for v in list(neighborhood.values()) if not v[1] is False ] if mates: m = get_RNG().choice(mates) both_wealthy1 = (self.sugar >= self.init_sugar and m.sugar >= m.init_sugar) both_wealthy2 = (self.spice >= self.init_spice and m.spice >= m.init_spice) # All criteria is fulfilled to procreate! if free_cells and m.is_fertile( ) and m.gender != self.gender and both_wealthy1 and both_wealthy2: # Take one free cell to place Junior there. c = get_RNG().choice(free_cells) n_x = c.x n_y = c.y # Give him / her initial resources n_su = int(self.init_sugar / 2) + int(m.init_sugar / 2) n_sp = int(self.init_spice / 2) + int(m.init_spice / 2) self.sugar -= int(self.init_sugar / 2) self.spice -= int(self.init_spice / 2) m.sugar -= int(m.init_sugar / 2) m.spice -= int(m.init_spice / 2) # Fuse mommy's and daddy's chromosomes to create Juniors attributes. # This is the actual creation of the baby. Behold the wonders of nature! n_chromosome = self.chromosome.merge_with(m.chromosome) child = SSAgent(n_x, n_y, self.gc, n_su, n_sp, 0, n_chromosome) # Give the parents a reference to their newborn so they can, # inherit their wealth to it before their inevitable demise. self.children.append(child) m.children.append(child) # Update the abm that it has to schedule a new agent. abm.add_agent(child)
def create_gamete(genomes): """ Creates and returns a gamete that consists of parts of both genomes in this chromosome. :return: Gamete in form of a single bitstring. """ # 1) Generate a random number (gaussian distributed) of # random indices which are then used to split the genes at the respective points. genome_size = len(genomes[0]) num_partitions = int(get_RNG().triangular(0, genome_size / 2, genome_size)) partitions = get_RNG().sample(range(genome_size), num_partitions) partitions.sort() # Now we have all our indices, and sorted. partitions.append(genome_size) # Append the end of the string start = 0 gamete = [] for p in partitions: i = get_RNG().choice([0, 1]) gamete.extend(genomes[i][start:p]) start = p # 'gamete' is now a list of integers. Convert the ints to strings and join 'em all together. return gamete
def mutate(self): """ Has a chance of 0.5% to perform a random mutation in the dna, and a chance of 1% to flip a few bits in the cultural dna. :return: """ # Flip bit in genome if get_RNG().random() < 0.005: length = len(self.genomes) index = get_RNG().randrange(length) l = list(self.genomes[0]) l[index] = Chromosome.invert_bit(l[index]) g1 = "".join(l) index = get_RNG().randrange(length) l = list(self.genomes[1]) l[index] = Chromosome.invert_bit(l[index]) g2 = "".join(l) self.genomes = (g1, g2) # Flip a bit in culture if get_RNG().random() < 0.01: length = len(self.culture) num_bits_changed = int(get_RNG().triangular(0, 1, length)) index = get_RNG().sample(range(length), num_bits_changed) for i in index: self.culture[i] = 1 - self.culture[i]
def spread_creep(self, neighborhood): cells = [c for c in list(neighborhood.values())] possible_cells = [ c for c in cells if c.team and self.team.number == c.team.number ] if possible_cells: if self.strategy_seed == 0: cab_rng.get_RNG().shuffle(cells) cell = cab_rng.get_RNG().choice(cells) else: min_val = min(possible_cells, key=attrgetter('temperature')) c_list = [ c for c in possible_cells if c.temperature == min_val.temperature ] c_list.extend([ c for c in cells if not c.team or self.team.number != c.team.number ]) cab_rng.get_RNG().shuffle(c_list) cell = cab_rng.get_RNG().choice(c_list) self.score += cell.inc_temperature(self.team, self.power) else: print("agent died: t{0} d{1} w{2} s{3} p{4}".format( self.team.number, self.min_density, self.strategy_seed, self.strategy_seed, self.power)) self.dead = True
def walk(self, neighborhood): possible_cells = [ c for c in list(neighborhood.values()) if c.team and self.team.number == c.team.number and c.temperature >= self.min_density ] self.prev_x = self.x self.prev_y = self.y if possible_cells: if self.strategy_walk == 0: cab_rng.get_RNG().shuffle(possible_cells) cell = cab_rng.get_RNG().choice(possible_cells) else: # self.strategy_walk == 1: min_val = min(possible_cells, key=attrgetter('temperature')) c_list = [ c for c in possible_cells if c.temperature == min_val.temperature ] cab_rng.get_RNG().shuffle(c_list) cell = cab_rng.get_RNG().choice(c_list) # Move to new cell self.x = cell.x self.y = cell.y else: print("agent died: t{0} d{1} w{2} s{3} p{4}".format( self.team.number, self.min_density, self.strategy_seed, self.strategy_seed, self.power)) self.dead = True
def mutate(self): """ Has a chance of 0.5% to perform a random mutation in the dna, and a chance of 1% to flip a few bits in the cultural dna. :return: """ # Flip bit in genome if get_RNG().random() < 0.005: length = len(self.genomes) index = get_RNG().randrange(length) l = list(self.genomes[0]) l[index] = Chromosome.invert_bit(l[index]) g1 = "".join(l) index = get_RNG().randrange(length) l = list(self.genomes[1]) l[index] = Chromosome.invert_bit(l[index]) g2 = "".join(l) self.genomes = (g1, g2) # Flip a bit in culture if get_RNG().random() < 0.01: length = len(self.culture) num_bits_changed = int(get_RNG().triangular(0, 1, length)) index = get_RNG().sample(range(length), num_bits_changed) for i in index: self.culture[i] = 1 - self.culture[i]
def create_gamete(genomes): """ Creates and returns a gamete that consists of parts of both genomes in this chromosome. :return: Gamete in form of a single bitstring. """ # 1) Generate a random number (gaussian distributed) of # random indices which are then used to split the genes at the respective points. genome_size = len(genomes[0]) num_partitions = int(get_RNG().triangular(0, genome_size / 2, genome_size)) partitions = get_RNG().sample(range(genome_size), num_partitions) partitions.sort() # Now we have all our indices, and sorted. partitions.append(genome_size) # Append the end of the string start = 0 gamete = [] for p in partitions: i = get_RNG().choice([0, 1]) gamete.extend(genomes[i][start:p]) start = p # 'gamete' is now a list of integers. Convert the ints to strings and join 'em all together. return gamete
def __init__(self, x, y, gc): """ Initializes an agent """ super().__init__(x, y, gc) self.id = "ant" self.prev_x = x self.prev_y = y self.max_ph = gc.MAX_PHEROMONE self.food = 1 self.has_food = False self.dead = False self.color = (0, 175, 200) self.directions = [(1, 0), (1, -1), ( 0, -1), (-1, 0), (-1, 1), ( 0, 1)] self.current_dir = get_RNG().randint(0, 5)
def __init__(self, x, y, gc): """ Initializes an agent """ super().__init__(x, y, gc) self.id = "ant" self.prev_x = x self.prev_y = y self.max_ph = gc.MAX_PHEROMONE self.food = 1 self.has_food = False self.dead = False self.color = (0, 175, 200) self.directions = [(1, 0), (1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1)] self.current_dir = get_RNG().randint(0, 5)
def choose_dominant_gene(strings): """ Takes two gene strings and returns the dominant one, or random if both are dominant/ recessive :param strings: Two sub-genes of the chromosome :return: The more dominant/ luckier string of both. """ # How do we determine dominance? # For now just by looking whether there is an even number of 'ones' in it. dominant0 = strings[0].count('1') % 2 == 0 dominant1 = strings[1].count('1') % 2 == 0 if (dominant0 and dominant1) or (not (dominant0 or dominant1)): return get_RNG().choice([strings[0], strings[1]]) elif dominant1: return strings[0] else: return strings[1]
def choose_dominant_gene(strings): """ Takes two gene strings and returns the dominant one, or random if both are dominant/ recessive :param strings: Two sub-genes of the chromosome :return: The more dominant/ luckier string of both. """ # How do we determine dominance? # For now just by looking whether there is an even number of 'ones' in it. dominant0 = strings[0].count('1') % 2 == 0 dominant1 = strings[1].count('1') % 2 == 0 if (dominant0 and dominant1) or (not (dominant0 or dominant1)): return get_RNG().choice([strings[0], strings[1]]) elif dominant1: return strings[0] else: return strings[1]
def update(self): """ This method regulates the cell's state according to the state of its neighbors. """ if self.zone.type == 'EMPTY': self.zone.update(self) else: if len(self.neighbor_zones) > 0: new_zone = get_RNG().choice(list(self.neighbor_zones)) if new_zone.type == 'RESIDENTIAL': self.zone = ResidentialZone() elif new_zone.type == 'COMMERCIAL': self.zone = CommercialZone() elif new_zone.type == 'INDUSTRIAL': self.zone = IndustrialZone() self.color = self.zone.color self.neighbor_zones.clear() print("self.color: ", self.color) self.update_color()
def update(self): """ This method regulates the cell's state according to the state of its neighbors. """ if self.zone.type == 'EMPTY': self.zone.update(self) else: if len(self.neighbor_zones) > 0: new_zone = get_RNG().choice(list(self.neighbor_zones)) if new_zone.type == 'RESIDENTIAL': self.zone = ResidentialZone() elif new_zone.type == 'COMMERCIAL': self.zone = CommercialZone() elif new_zone.type == 'INDUSTRIAL': self.zone = IndustrialZone() self.color = self.zone.color self.neighbor_zones.clear() print("self.color: ", self.color) self.update_color()
def r1_select_best_cell(self, ca): """ Agent selects the best cell to move to, according to: its resources, occupier and tribal alignment. """ neighborhood = ca.get_empty_agent_neighborhood(self.x, self.y, self.vision) best_cells = list() max_dist = 0 max_w = 0 # Find cells with the highest possible reward. # TODO: check if distance calculation is correct for hex grids # print('neighborhood: {0}'.format(list(neighborhood.keys()))) for cell in list(neighborhood.values()): if not best_cells: best_cells = [cell] max_w = self.welfare(cell.sugar, cell.spice) max_dist = (abs(cell.x - self.x) + abs(cell.y - self.y)) else: dist = ca.hex_distance(self.x, self.y, cell.q, cell.r) welfare = self.welfare(cell.sugar, cell.spice) if welfare > max_w: best_cells = [cell] max_w = welfare max_dist = dist elif welfare == max_w and dist < max_dist: best_cells = [cell] max_dist = dist elif welfare == max_w and dist == max_dist: best_cells.append(cell) result_cell = get_RNG().choice(best_cells) # TODO: In case the target cell is not directly adjacent, find an adjacent cell that leads into its direction. # TODO: Make sure to pick one adjacent cell that is NOT currently occupied. Maybe calculate a path. # if self.vision > 1 and CAHex.cube_distance(ca.ca_grid[self.x, self.y], result_cell) > 1: # next_in_direction = CAHex.get_cell_in_direction(ca.ca_grid[self.x, self.y], result_cell) # result_cell = ca.ca_grid[next_in_direction] self.move_to(result_cell) self.eat_from(result_cell)
def r1_select_best_cell(self, ca): """ Agent selects the best cell to move to, according to: its resources, occupier and tribal alignment. """ neighborhood = ca.get_empty_agent_neighborhood(self.x, self.y, self.vision) best_cells = list() max_dist = 0 max_w = 0 # Find cells with the highest possible reward. # TODO: check if distance calculation is correct for hex grids # print('neighborhood: {0}'.format(list(neighborhood.keys()))) for cell in list(neighborhood.values()): if not best_cells: best_cells = [cell] max_w = self.welfare(cell.sugar, cell.spice) max_dist = (abs(cell.x - self.x) + abs(cell.y - self.y)) else: dist = ca.hex_distance(self.x, self.y, cell.q, cell.r) welfare = self.welfare(cell.sugar, cell.spice) if welfare > max_w: best_cells = [cell] max_w = welfare max_dist = dist elif welfare == max_w and dist < max_dist: best_cells = [cell] max_dist = dist elif welfare == max_w and dist == max_dist: best_cells.append(cell) result_cell = get_RNG().choice(best_cells) # TODO: In case the target cell is not directly adjacent, find an adjacent cell that leads into its direction. # TODO: Make sure to pick one adjacent cell that is NOT currently occupied. Maybe calculate a path. # if self.vision > 1 and CAHex.cube_distance(ca.ca_grid[self.x, self.y], result_cell) > 1: # next_in_direction = CAHex.get_cell_in_direction(ca.ca_grid[self.x, self.y], result_cell) # result_cell = ca.ca_grid[next_in_direction] self.move_to(result_cell) self.eat_from(result_cell)
def get_island_landscape(self): l1 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] l2 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] lower_limit = int((self.y_dim + self.x_dim) * 0.33) upper_limit = int((self.y_dim + self.x_dim) * 0.9) print(lower_limit, upper_limit) last_rand = 0 for j in range(self.y_dim): for i in range(self.x_dim): if (i + j) % self.factor == 0: last_rand = int(cab_rng.get_RNG().triangular( self.deepest, self.highest, self.water_level)) l1[i][j] = last_rand for _ in range(self.smoothness): for j in range(self.y_dim): for i in range(self.x_dim): n = 0 f = 0 for cy in range(-1, 2): for cx in range(-1, 2): if not (cy == 0 and cx == 0): try: n += 1 f += l1[i + cx][j + cy] except IndexError: pass avg = f / n if avg > l1[i][j]: diff = avg - l1[i][j] l2[i][j] = l1[i][j] + (diff * self.slope) elif avg < l1[i][j]: diff = l1[i][j] - avg l2[i][j] = l1[i][j] - (diff * self.slope) else: l2[i][j] = l1[i][j] l1, l2 = l2, l1 return l1
def get_coastal_landscape(self): l1 = {} l2 = {} for j in range(self.height): for i in range(self.width): # l1[i][j] = int(get_RNG().triangular(self.deepest, self.highest, 5))s q = i - math.floor(j / 2) mode = (((i + j) / 200) * 5) + self.water_level l1[q, j] = int(get_RNG().triangular(self.deepest + 2 * mode, self.highest + 2 * mode, mode)) # l1[i][j] = int(get_RNG().triangular(self.deepest + 2 * mode, self.highest + 2 * mode, mode)) for _ in range(self.smoothness): for j in range(self.height): for i in range(self.width): q = i - math.floor(j / 2) n = 0 f = 0 for d in self.gc.HEX_DIRECTIONS: if not (d[0] == 0 and d[1] == 0): try: n += 1 f += l1[q + d[0], j + d[1]] except KeyError: pass avg = f / n if avg > l1[q, j]: diff = avg - l1[q, j] l2[q, j] = l1[q, j] + (diff * self.slope) elif avg < l1[q, j]: diff = l1[q, j] - avg l2[q, j] = l1[q, j] - (diff * self.slope) else: l2[q, j] = l1[q, j] l1, l2 = l2, l1 return l1
def get_island_landscape(self): l1 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] l2 = [[0 for _ in range(self.y_dim)] for _ in range(self.x_dim)] lower_limit = int((self.y_dim + self.x_dim) * 0.33) upper_limit = int((self.y_dim + self.x_dim) * 0.9) print(lower_limit, upper_limit) last_rand = 0 for j in range(self.y_dim): for i in range(self.x_dim): if (i + j) % self.factor == 0: last_rand = int(cab_rng.get_RNG().triangular(self.deepest, self.highest, self.water_level)) l1[i][j] = last_rand for _ in range(self.smoothness): for j in range(self.y_dim): for i in range(self.x_dim): n = 0 f = 0 for cy in range(-1, 2): for cx in range(-1, 2): if not (cy == 0 and cx == 0): try: n += 1 f += l1[i + cx][j + cy] except IndexError: pass avg = f / n if avg > l1[i][j]: diff = avg - l1[i][j] l2[i][j] = l1[i][j] + (diff * self.slope) elif avg < l1[i][j]: diff = l1[i][j] - avg l2[i][j] = l1[i][j] - (diff * self.slope) else: l2[i][j] = l1[i][j] l1, l2 = l2, l1 return l1
def map_genome_to_attributes(self): """ Decodes the genome and creates the attribute of the individual. """ # The meta and init attributes cannot become smaller than 1, # even though that is possible by the encoding. We have to avoid that. meta_sugar = Chromosome.choose_dominant_gene( self.get_genome_substring('meta_sugar')) meta_spice = Chromosome.choose_dominant_gene( self.get_genome_substring('meta_spice')) init_sugar = Chromosome.choose_dominant_gene( self.get_genome_substring('init_sugar')) init_spice = Chromosome.choose_dominant_gene( self.get_genome_substring('init_spice')) vision = Chromosome.choose_dominant_gene( self.get_genome_substring('vision')) gender = get_RNG().choice(self.get_genome_substring('gender')) f1 = Chromosome.choose_dominant_gene( self.get_genome_substring('fertility_1')) f2 = Chromosome.choose_dominant_gene( self.get_genome_substring('fertility_2')) dying_age = Chromosome.choose_dominant_gene( self.get_genome_substring('dying_age')) self.meta_sugar = max(int(meta_sugar, 2), 1) self.meta_spice = max(int(meta_spice, 2), 1) self.init_sugar = max(int(init_sugar, 2), 1) self.init_spice = max(int(init_spice, 2), 1) self.vision = int(vision, 2) self.gender = int(gender, 2) self.dying_age = int(dying_age, 2) self.fertility = (int(f1, 2), int(f2, 2)) dna = "".join((meta_sugar, meta_spice, init_sugar, init_spice, vision, gender, f1, f2, dying_age)) self.dna_color = Chromosome.convert_to_color(dna)
def spread_creep(self, neighborhood): cells = [c for c in list(neighborhood.values())] possible_cells = [ c for c in cells if c.team and self.team.number == c.team.number] if possible_cells: if self.strategy_seed == 0: cab_rng.get_RNG().shuffle(cells) cell = cab_rng.get_RNG().choice(cells) else: min_val = min(possible_cells, key=attrgetter('temperature')) c_list = [c for c in possible_cells if c.temperature == min_val.temperature] c_list.extend( [c for c in cells if not c.team or self.team.number != c.team.number]) cab_rng.get_RNG().shuffle(c_list) cell = cab_rng.get_RNG().choice(c_list) self.score += cell.inc_temperature(self.team, self.power) else: print("agent died: t{0} d{1} w{2} s{3} p{4}".format( self.team.number, self.min_density, self.strategy_seed, self.strategy_seed, self.power)) self.dead = True
def walk(self, neighborhood): possible_cells = [c for c in list(neighborhood.values( )) if c.team and self.team.number == c.team.number and c.temperature >= self.min_density] self.prev_x = self.x self.prev_y = self.y if possible_cells: if self.strategy_walk == 0: cab_rng.get_RNG().shuffle(possible_cells) cell = cab_rng.get_RNG().choice(possible_cells) else: # self.strategy_walk == 1: min_val = min(possible_cells, key=attrgetter('temperature')) c_list = [c for c in possible_cells if c.temperature == min_val.temperature] cab_rng.get_RNG().shuffle(c_list) cell = cab_rng.get_RNG().choice(c_list) # Move to new cell self.x = cell.x self.y = cell.y else: print("agent died: t{0} d{1} w{2} s{3} p{4}".format( self.team.number, self.min_density, self.strategy_seed, self.strategy_seed, self.power)) self.dead = True
def get_cell_with_pheromone(self, target_ph, neighborhood): """ Gets the cell with highest pheromone value (or random if no pheromones present) from the immediate neighborhood. :param: neighborhood is a dict of (x, y) -> cell mappings, where cell is a tuple of (ca_cell, [agent(s) on cell]). If no agent is on the cell then the list in the tuple is simply 'False' """ result = None result_list = [] backup_list = [] best_cell = None max_ph = 0 # Choose the possible directions the ants can currently look at. if self.current_dir == 5: possible_dirs = [4, 5, 0] elif self.current_dir == 0: possible_dirs = [5, 0, 1] else: possible_dirs = [ self.current_dir - 1, self.current_dir, self.current_dir + 1 ] for i in possible_dirs: d = self.directions[i] _x = self.x + d[0] _y = self.y + d[1] if (_x, _y) in neighborhood: cell = neighborhood[_x, _y] if cell[0].pheromones[ target_ph] > 0.00: # and (not cell[1] or len(cell[1]) < 10): ph = cell[0].pheromones[target_ph] if ph > max_ph: best_cell = cell max_ph = ph self.current_dir = i result_list.append((cell, ph, i)) # elif not cell[1] or len(cell[1]) < 10: else: backup_list.append((cell, i)) if result_list: if get_RNG().random() < 0.10: choice = AntAgent.weighted_choice(result_list) # choice = get_RNG().choice(result_list) result = choice[0] self.current_dir = choice[1] else: result = best_cell elif backup_list: choice = get_RNG().choice(backup_list) result = choice[0] self.current_dir = choice[1] else: # print('Ant Error: no cells found to move to!') self.current_dir = AntAgent.get_opposite_direction( self.current_dir) return self.get_cell_with_pheromone(target_ph, neighborhood) # Add a small random factor to the movement. return result
def get_random_valid_position(self) -> Tuple[int, int]: """ Returns coordinates of a random cell position that is within the boundaries of the grid. :returns Coordinates in hex form. """ return cab_rng.get_RNG().choice(list(self.ca_grid.keys()))
def generate_agent(self, abm, ca): # x, y = ca.get_random_valid_position() # while (x, y) in abm.agent_locations: # x, y = ca.get_random_valid_position() x, y = get_RNG().choice(self.possible_starting_locations) self.possible_starting_locations.remove((x, y)) meta_sugar = get_RNG().randint(self.gc.MIN_METABOLISM, self.gc.MAX_METABOLISM) meta_spice = get_RNG().randint(self.gc.MIN_METABOLISM, self.gc.MAX_METABOLISM) vision = get_RNG().randint(1, self.gc.VISION + 1) g = get_RNG().choice([0, 1]) if g == 1: f1 = get_RNG().randint(self.gc.F_FERTILITY_START[0], self.gc.F_FERTILITY_START[1]) f2 = get_RNG().randint(self.gc.F_FERTILITY_END[0], self.gc.F_FERTILITY_END[1]) f = (f1, f2) else: f1 = get_RNG().randint(self.gc.M_FERTILITY_START[0], self.gc.M_FERTILITY_START[1]) f2 = get_RNG().randint(self.gc.M_FERTILITY_END[0], self.gc.M_FERTILITY_END[1]) f = (f1, f2) su = get_RNG().randint(self.gc.STARTING_SUGAR[0], self.gc.STARTING_SUGAR[1]) sp = get_RNG().randint(self.gc.STARTING_SUGAR[0], self.gc.STARTING_SUGAR[1]) d = get_RNG().randint(f[1], self.gc.MAX_AGENT_LIFE) c = [get_RNG().randint(0, int((meta_sugar + meta_spice) / 2)) for _ in range(11)] # imm_sys = [get_RNG().getrandbits(self.gc.NUM_TRIBES - 1) for _ in range(self.gc.IMMUNE_SYSTEM_GENOME_LENGTH)] imm_sys = [get_RNG().getrandbits(int((meta_sugar + meta_spice) / 2)) for _ in range(self.gc.IMMUNE_SYSTEM_GENOME_LENGTH)] a = 0 # get_RNG().randint(0, int(self.gc.MAX_AGENT_LIFE / 2)) gene_string = "{0:03b}".format(meta_sugar) + "{0:03b}".format(meta_spice)\ + "{0:06b}".format(su) + "{0:06b}".format(sp) \ + "{0:03b}".format(vision) + "{0:01b}".format(g)\ + "{0:06b}".format(f[0]) + "{0:06b}".format(f[1]) + "{0:07b}".format(d) # We use generation to keep track of how far an agent has walked down the evolutionary road. generation = (0, 0) genome = (gene_string, gene_string, c, imm_sys, generation) # Retrieve a spawn position from the position list belonging to its tribe. # tribe_id = max(set(c), key=c.count) # get_RNG().shuffle(position_list[tribe_id]) # p = position_list[tribe_id].pop() # Create the new agent and add to both, dictionary and list. new_agent = SSAgent(x, y, self.gc, su, sp, a, genome) # self.agent_dict[x, y] = new_agent # self.agent_list.append(new_agent) # abm.add_agent(new_agent) return new_agent