class JM17290Bot(Bot): """ This not (jm17290_ea.JM17290Bot) is used during optimization and hence contains code to facilitate this. This bot should NOT be run during a competition. use jm17290.JM17290(Bot) instead, which has hard-coded weights for expert rules set through optimization. """ def select(self, players, count): """ Select players on an individual basis using weighted expert rule phenotypes 'res_selection' and 'spy_selection' for Resistance members and spies respectively. If weighted-expert selection rules cannot choose enough suitable players to go on the mission then the remaining slots are populated randomly.""" maybe = [] selection = [self] # Resistance and Spy selecting self by default. for p in self.others(): self.to_select = p if len(selection) < count: if not self.spy: if self.res_select.run(): selection.append(p) else: maybe.append(p) else: if self.spy_selection.run(): selection.append(p) else: maybe.append(p) while len(selection) < count: p = random.choice(maybe) selection.append(p) maybe.remove(p) return selection def sabotage(self): """ Resistance members cannot sabotage a mission. Spy sabotage is determined by 'spy_sabotage' weighted expert rules phenotype.""" if not self.spy: return False else: return self.spy_sabotage.run() def vote(self, team): """ Vote for Resistance and Spies is determined by 'res_vote' and 'spy_vote' weighted expert rule phenotypes respectively. """ if not self.spy: return self.res_vote.run() else: return self.spy_vote.run() def onGameRevealed(self, players, spies): """ Create phenotypes that will be used for this games by acquiring them randomly from persistent storage. Resistance play is made up of two phenotypes: Select and Vote. Spy play is made up of three phenotypes: Select, Vote and Sabotage. Phenotypes are executed and return a boolean decision based on the weights of the active expert rules at the current point in the game. """ self.root = 'jm17290-src/' self.population = Population() self.gen = self.population.gen(self.root) self.population_size = self.population.size(self.root) self.perfect_record = set(self.others()) self.unselected = set(self.others()) self.failed_one_mission = set() self.failed_two_missions = set() if not self.spy: # RESISTANCE. self.res_genotype = self.population.genotype( random.randint(0, self.population_size - 1), self.gen, ResGenotype.Type, self.root) # SELECT - Phenotype self.res_select = Phenotype( # Yes. # Select player with perfect record. # Select previously unselected player. # Forgive one mission fail. # Default up vote to avoid deadlock. [(lambda: self.to_select in self.perfect_record, self.res_genotype[ResGenotype.PickYesPerfectRecord]), (lambda: self.to_select in self.unselected, self.res_genotype[ResGenotype.PickYesUntested]), (lambda: self.to_select in self.failed_one_mission, self.res_genotype[ResGenotype.PickYesFailed1Mission]), (lambda: True, self.res_genotype[ResGenotype.PickYesDefault]) ], # No. # Player failed one mission. # Player failed two missions. # Default up vote to avoid deadlock. [(lambda: self.to_select in self.failed_one_mission, self.res_genotype[ResGenotype.PickNoFailed1Mission]), (lambda: self.to_select in self.failed_two_missions, self.res_genotype[ResGenotype.PickNoFailed2Missions]), (lambda: True, self.res_genotype[ResGenotype.PickNoDefault])]) # VOTE - Phenotype. self.res_vote = Phenotype( # Yes. # Vote last attempt to save the mission. # Vote for the first mission. # Approve own mission. # Default vote up to avoid deadlock. [(lambda: self.game.tries == 5, self.res_genotype[ResGenotype.VoteYesAttempt5]), (lambda: self.game.turn == 1, self.res_genotype[ResGenotype.VoteYesMission1]), (lambda: self.game.leader == self, self.res_genotype[ResGenotype.VoteYesLeader]), (lambda: True, self.res_genotype[ResGenotype.VoteYesDefault]) ], # No. # Reject if left out of team of three. # Reject if team member failed one mission. # Reject if team member failed two missions. # Default vote up to avoid deadlock. [(lambda: len(self.game.team) == 3 and not bool( {self}.intersection(set(self.game.team))), self.res_genotype[ResGenotype.VoteNoNotIncludedTeam3]), (lambda: bool( set(self.game.team).intersection(self.failed_one_mission) ), self.res_genotype[ResGenotype.VoteNoFailed1Mission]), (lambda: bool( set(self.game.team).intersection(self.failed_two_missions) ), self.res_genotype[ResGenotype.VoteNoFailed2Missions]), (lambda: True, self.res_genotype[ResGenotype.VoteNoDefault])]) else: # SPY self.spies = spies self.spy_genotype = self.population.genotype( random.randint(0, self.population_size - 1), self.gen, SpyGenotype.Type, self.root) # SELECT - Phenotype self.spy_selection = Phenotype( # Yes. # Select player with a perfect record. # Select previously unselected player. # Default vote up to avoid deadlock. # Picked self, don't pick another spy. # Don't pick VERY suspicious player. [(lambda: self.to_select in self.perfect_record, self.spy_genotype[SpyGenotype.PickYesPerfectRecord]), (lambda: self.to_select in self.unselected, self.spy_genotype[SpyGenotype.PickYesUntested]), (lambda: True, self.spy_genotype[SpyGenotype.PickYesDefault]) ], # No. # Picked self, don't pick another spy. # Don't pick VERY suspicious player. # Default vote up to avoid deadlock. [(lambda: self.to_select in self.spies, self.spy_genotype[SpyGenotype.PickNoAreSpy]), (lambda: self.to_select in self.failed_two_missions, self.spy_genotype[SpyGenotype.PickNoFailed2Missions]), (lambda: True, self.spy_genotype[SpyGenotype.PickNoDefault])]) # VOTE - Phenotype. self.spy_vote = Phenotype( # Yes. # Vote for final try to avoid detection. # Vote for first mission, pretend nothing known. # Vote for own mission. # Support spy on mission. # Support the win. # Vote up to avoid deadlock. [(lambda: self.game.tries == 5, self.spy_genotype[SpyGenotype.VoteYesAttempt5]), (lambda: self.game.turn == 1, self.spy_genotype[SpyGenotype.VoteYesMission1]), (lambda: self.game.leader == self, self.spy_genotype[SpyGenotype.VoteYesLeader]), (lambda: bool( set(self.game.team).intersection(set(self.spies))), self.spy_genotype[SpyGenotype.VoteYesAtLeastOneSpy]), (lambda: bool( set(self.game.team).intersection(set(self.spies)) ) and self.game.losses == 2, self.spy_genotype[SpyGenotype.VoteYesAtLeastOneSpyOneToWin]), (lambda: True, self.spy_genotype[SpyGenotype.VoteYesDefault]) ], # No. # Not included in team of three. # Vote against team with suspicious member to avoid detection. # Vote against team with VERY suspicious member to avoid detection. # Vote against a team with no spies. # Vote against a team of all spies. # Default vote against to avoid deadlock. [(lambda: len(self.game.team) == 3 and not bool( {self}.intersection(set(self.game.team))), self.spy_genotype[SpyGenotype.VoteNoNotIncludedTeam3]), (lambda: bool( set(self.game.team).intersection(self.failed_one_mission) ), self.spy_genotype[SpyGenotype.VoteNoFailed1Mission]), (lambda: bool( set(self.game.team).intersection(self.failed_two_missions) ), self.spy_genotype[SpyGenotype.VoteNoFailed2Missions]), (lambda: not bool( set(self.game.team).intersection(set(self.spies))), self.spy_genotype[SpyGenotype.VoteNoNoSpies]), (lambda: set(self.game.team) == set(self.spies), self.spy_genotype[SpyGenotype.VoteNoAllSpies]), (lambda: True, self.spy_genotype[SpyGenotype.VoteNoDefault])]) # SABOTAGE - Phenotype. self.spy_sabotage = Phenotype( # Yes. # Sabotage to win the game. # Sabotage own mission. # Sabotage if only spy on the mission. # Default vote up to avoid deadlock. [(lambda: self.game.losses == 2, self.spy_genotype[SpyGenotype.SabotageYesToWin]), (lambda: self.game.leader == self, self.spy_genotype[SpyGenotype.SabotageYesLeader]), (lambda: {self} == ({self}.intersection(set(self.game.team))), self.spy_genotype[SpyGenotype.SabotageYesOnlySpyOnMission]), (lambda: True, self.spy_genotype[SpyGenotype.SabotageYesDefault])], # No. # Do not sabotage a game with all spies. # Do not sabotage the first mission. # Default vote up to avoid deadlock. [(lambda: set(self.game.team) == set(self.spies), self.spy_genotype[SpyGenotype.SabotageNoAllSpies]), (lambda: self.game.turn == 1, self.spy_genotype[SpyGenotype.SabotageNoMission1]), (lambda: True, self.spy_genotype[SpyGenotype.SabotageNoDefault])]) def onTeamSelected(self, leader, team): """ Note players who have been on a mission. """ for p in team: self.unselected.discard(p) def onMissionComplete(self, sabotaged): """ Note players who have lost a perfect record, failed 1 mission, or failed two missions. """ if sabotaged: for p in self.game.team: self.perfect_record.discard(p) if p in self.failed_one_mission: # Note players who've failed one mission. self.failed_two_missions.add( p) # Note players who've failed two missions. self.failed_one_mission.add(p) def onGameComplete(self, win, spies): """ Update the genotype with the outcome of the game and persist the result. """ if not self.spy: self.res_genotype.update(win) self.population.update_genotype(self.res_genotype, self.gen, self.root) else: self.spy_genotype.update(win) self.population.update_genotype(self.spy_genotype, self.gen, self.root)
# J.Madge 05.11.2017 'promote' and 'tournament_num' must add up to the population size. promote = 3 # J.Madge 05.11.2017 Number of genes to automatically advance to the next generation. tournament_num = 17 # J.Madge 05.11.2017 Number of tournaments to select remaining member of the population. tournament_size = 4 # J.Madge 05.11.2017 Number of genes to be randomly selected for each tournament. # J.Madge 05.11.2017 Cross at points to share selection/vote/sabotage strategies. res_cross_pos = [7, 15] spy_cross_pos = [6, 18, 25] res_mutations = 3 # J.Madge 05.11.2017 Number of mutations in child Resistance genes. spy_mutations = 5 # J.Madge 05.11.2017 Number of mutations in child Spy genes. mutation_lower = 0.8 # J.Madge 05.11.2017 Lower limit of the mutation operator. mutation_upper = 1.2 # J.Madge 05.11.2017 Upper limit of the mutation operator. p = Population() current_gen = p.gen() next_gen = current_gen + 1 # J.Madge 06.11.2017 Select the best Resistance and best Spy to represent this generation. best_res = p.top(1, current_gen, ResGenotype.Type)[0] best_res.set_index(current_gen) p.insert(best_res, 'Best') best_spy = p.top(1, current_gen, SpyGenotype.Type)[0] best_spy.set_index(current_gen) p.insert(best_spy, 'Best') # J.Madge 05.11.2017 Create database for the next generation. p.create(next_gen) # J.Madge 05.11.2017 RESISTANCE: Create the next generation. res_next_gen_genes = []