From 12316a9238e0f630f81cd600f1c1a910f52f0383 Mon Sep 17 00:00:00 2001 From: Barak Michener Date: Mon, 4 Aug 2014 15:34:53 -0400 Subject: [PATCH] deal in probability, not in repetition --- game_evaluator.py | 77 ++++++++++---------------- models/default_model.py | 140 ++++++++++++++++++++---------------------------- tim.py | 16 +++--- 3 files changed, 97 insertions(+), 136 deletions(-) diff --git a/game_evaluator.py b/game_evaluator.py index cbd2e85..076bbb7 100644 --- a/game_evaluator.py +++ b/game_evaluator.py @@ -29,6 +29,7 @@ class DeceptionGame(object): self.n_players = len(player_array) self.n_good = len([x for x in player_array if x[1] is True]) self.trace = None + self.trace_score = 0.0 self.observations = [] self.seen = [] self.tid = 0 @@ -63,7 +64,7 @@ class DeceptionGame(object): def obs(deal): if self.player_is_good(deal, player_id, None) == is_good: - return True + return 1.0 else: return None transaction.append(obs) @@ -80,7 +81,7 @@ class DeceptionGame(object): rnd = round - 1 def obs(deal): - return True + return 1.0 self.lancelots_switch_at.append(rnd) @@ -96,7 +97,7 @@ class DeceptionGame(object): def obs(deal): if self.player_role(deal, player_id) == role_str: - return True + return 1.0 else: return None transaction.append(obs) @@ -200,47 +201,29 @@ class DeceptionGame(object): deck = self.quick_permutations[:] else: deck = self.all_permutations[:] - new_deck = [] trace = {} progress = progressbar.ProgressBar( widgets=["Simulating games: ", progressbar.Bar(marker="*"), " ", progressbar.ETA()]) - for i in progress(range(length)): - falses = 0 - trues = 0 - nones = 0 - for deal in deck: - f_list = [] - for obs in self.observations: - for tid in obs: - f_list.append(tid) - is_bad = False - dont_copy = False - for f in f_list: - out = f(deal) - if out is None: - is_bad = True - dont_copy = True - nones += 1 - break - if out is True: - trues += 1 - continue - if out is False: - is_bad = True - falses += 1 - break - if not is_bad: - if deal not in trace: - trace[deal] = 1 - trace[deal] += 1 - if not dont_copy: - new_deck.append(deal) - deck = new_deck - new_deck = [] + f_list = [] + for obs in self.observations: + for tid in obs: + f_list.append(tid) + total_score = 0.0 + for deal in progress(deck): + this_score = 1.0 + for f in f_list: + score = f(deal) + if score is None: + this_score = 0.0 + break + this_score = this_score * score + total_score += this_score + trace[deal] = this_score self.trace = trace + self.trace_score = total_score def report(self): return self.get_player_data() @@ -251,24 +234,22 @@ class DeceptionGame(object): out.append({}) out[i]["role"] = dd(float) out[i]["side"] = dd(float) - - size = sum(self.trace.values()) * 1.0 + top_k = [(0.0, None)] * 5 for deal, score in self.trace.items(): + weighted_score = score / self.trace_score for i, card in enumerate(deal): role, side = card - out[i]["role"][role] += (score * 1.0) / size - out[i]["side"][side] += (score * 1.0) / size + out[i]["role"][role] += weighted_score + out[i]["side"][side] += weighted_score + if weighted_score > top_k[-1][0]: + top_k.append((weighted_score, deal)) + top_k = sorted(top_k, reverse=True)[:-1] + for i in range(self.n_players): out[i]["role"] = dict(out[i]["role"]) out[i]["side"] = dict(out[i]["side"]) - return out - def _aggregate(self, l, i): - out = dd(float) - size = len(l) * 1.0 - for deal in l: - out[deal[i]] += 1 / size - return dict(out) + return out, top_k def __str__(self): return "%d Player Game (%d constraints)" % (self.n_players, diff --git a/models/default_model.py b/models/default_model.py index d736b4e..f7a8257 100644 --- a/models/default_model.py +++ b/models/default_model.py @@ -1,6 +1,3 @@ -from util import Bernoulli - - # Models work like this; feel free to inherit from BaseModel to get the # necessary helpful things. # @@ -21,6 +18,7 @@ from util import Bernoulli # * None -- This set of statements could NEVER happen, please remove them from # consideration. + class BaseModel(object): def __init__(self, game): self.game = game @@ -61,39 +59,26 @@ class DefaultModel(BaseModel): def __init__(self, game): super(DefaultModel, self).__init__(game) - self.lady_will_duck = Bernoulli(0.7) - self.mission_ducks_on_round = [None] * 5 - self.mission_ducks_on_round[0] = Bernoulli(0.5) - self.mission_ducks_on_round[1] = Bernoulli(0.5) - self.mission_ducks_on_round[2] = Bernoulli(0.5) - self.early_spy_duck = Bernoulli(0.3) - self.multiple_spy_one_duck = Bernoulli(0.15) - self.ignorance_on_round = [None] * 5 - self.ignorance_on_round[0] = Bernoulli(0.9) - self.ignorance_on_round[1] = Bernoulli(0.7) - self.ignorance_on_round[2] = Bernoulli(0.5) - self.ignorance_on_round[3] = Bernoulli(0.3) - self.ignorance_on_round[4] = Bernoulli(0.3) - self.spy_vote_duck_on_round = [None] * 5 - self.spy_vote_duck_on_round[0] = Bernoulli(0.9) - self.spy_vote_duck_on_round[1] = Bernoulli(0.7) - self.spy_vote_duck_on_round[2] = Bernoulli(0.5) - self.spy_vote_duck_on_round[3] = Bernoulli(0.3) - self.spy_vote_duck_on_round[4] = Bernoulli(0.3) - self.multiple_spy_vote_duck = Bernoulli(0.75) - self.merlin_ignorance = Bernoulli(0.2) + self.lady_will_duck = 0.7 + self.mission_ducks_on_round = [0.5, 0.5, 0.5, 0.0, 0.0] + self.early_spy_duck = 0.3 + self.multiple_spy_one_duck = 0.15 + self.ignorance_on_round = [0.9, 0.7, 0.5, 0.3, 0.3] + self.spy_vote_duck_on_round = [0.9, 0.7, 0.5, 0.3, 0.3] + self.multiple_spy_vote_duck = 0.75 + self.merlin_ignorance = 0.2 def player_sees_player_and_claims(self, p1, p2, claim, rnd): if self.is_good(p1, rnd) or self.is_role(p1, "Mordred"): if self.is_good(p2, rnd) == claim: - return True + return 1.0 else: return None else: if claim is True: - return self.lady_will_duck.rand() + return self.lady_will_duck if claim is False: - return not self.lady_will_duck.rand() + return (1.0 - self.lady_will_duck) def mission(self, team, fails, must_fail, rnd): n_actually_good_people = sum( @@ -106,7 +91,7 @@ class DefaultModel(BaseModel): if fails != 0: return None else: - return True + return 1.0 else: # There's at least one spy. if fails == 0: @@ -114,12 +99,12 @@ class DefaultModel(BaseModel): if must_fail: return None if n_spies > 1: - return not self.multiple_spy_one_duck.rand() + return not self.multiple_spy_one_duck if rnd >= 0 and rnd < 3: - return self.mission_ducks_on_round[rnd].rand() + return self.mission_ducks_on_round[rnd] elif rnd == 3: # They always duck on 4 - return True + return 1.0 elif rnd == 4: # They never duck on 5 return None @@ -127,23 +112,23 @@ class DefaultModel(BaseModel): # One fail, one spy. spy = spy_names[0] if rnd >= 0 and rnd < 3: - return self.mission_ducks_on_round[rnd].rand() + return self.mission_ducks_on_round[rnd] elif rnd == 3: if spy == "Oberon": - return True + return 1.0 if spy == "GLance": - return True - return False + return 1.0 + return 0.0 elif rnd == 4: - return True + return 1.0 elif fails < n_spies: - return self.multiple_spy_one_duck.rand() + return self.multiple_spy_one_duck elif fails > 1: # collision! - return True + return 1.0 else: - return True - return True + return 1.0 + return 1.0 def votes(self, team, votes, fail_req, rnd): for player, vote in enumerate(votes): @@ -153,14 +138,14 @@ class DefaultModel(BaseModel): votes, fail_req, rnd): continue else: - return False + return 0.0 else: if default_vote(self, player, team, votes, fail_req, rnd): continue else: - return False - return True + return 0.0 + return 1.0 def default_vote(game, player, team, votes, fail_req, rnd): @@ -168,31 +153,31 @@ def default_vote(game, player, team, votes, fail_req, rnd): [int(game.is_good(x, rnd)) for x in team]) n_spies = len(team) - n_actually_good_people if player in team: - return True + return 1.0 if game.is_good(player, rnd): if n_spies > fail_req - 1: # Bad Team! if votes[player] == 1: - return game.ignorance_on_round[rnd].rand() + return game.ignorance_on_round[rnd] else: - return True + return 1.0 else: # Good Team! if votes[player] == 0: - return game.ignorance_on_round[rnd].rand() + return game.ignorance_on_round[rnd] else: - return True + return 1.0 else: if n_spies < fail_req: if votes[player] == 1: - return not game.spy_vote_duck_on_round[rnd].rand() + return not game.spy_vote_duck_on_round[rnd] else: - return game.spy_vote_duck_on_round[rnd].rand() + return game.spy_vote_duck_on_round[rnd] elif n_spies == fail_req: - return True + return 1.0 elif n_spies > fail_req: - return game.multiple_spy_vote_duck.rand() - return True + return game.multiple_spy_vote_duck + return 1.0 def merlin_vote(model, player_id, team, votes, fail_req, r): @@ -204,32 +189,28 @@ def merlin_vote(model, player_id, team, votes, fail_req, r): n_spies = n_spies - 1 if player_id in team: - return True + return 1.0 # At this point, this is the number of spies Merlin counts if n_spies == 0: if votes[player_id] == 0: # Voted down an apparently good team. Ignore this. - return True + return 1.0 if votes[player_id] == 1: - if model.merlin_ignorance.rand(): - return False - return True + return (1.0 - model.merlin_ignorance) elif n_spies == 1: # He'll either duck or vote it down. Either is fine - return True + return 1.0 elif n_spies > 1 and fail_req == 1: # Merlin wants spies to be butting heads. if votes[player_id] == 1: # Voted down an apparently good team. Ignore this. - return True + return 1.0 if votes[player_id] == 0: - if model.merlin_ignorance.rand(): - return True - return False + return model.merlin_ignorance elif n_spies > 1 and fail_req > 1: # Ignore the vote here - return True - return True + return 1.0 + return 1.0 def mordred_vote(game, player_id, team, votes, fail_req, r): @@ -241,30 +222,25 @@ def mordred_vote(game, player_id, team, votes, fail_req, r): n_spies = n_spies - 1 if player_id in team: - return True + return 1.0 # At this point, this is the number of spies Mordred knows. if n_spies == 0: # The chance that merlin doesn't know Mordred is 1 - Merlin's ignorance # Read this as "if Merlin is not ignorant of my role" - if not game.merlin_ignorance.rand(): - if votes[player_id] == 1: - return False - else: - return True - # Merlin is ignorant... + if votes[player_id] == 1: + return game.merlin_ignorance else: - # Vote it up or down, doesn't matter, both could happen - return True + return 1.0 elif n_spies == 1: # He'll either duck or vote it down. Either is fine - return True + return 1.0 elif n_spies > 1: # Never vote up a team of more than one spy, unless fail_req is high if fail_req > 1: - return True + return 1.0 else: - return False - return True + return 0.0 + return 1.0 def guen_vote(game, player_id, team, votes, fail_req, rnd): @@ -274,9 +250,9 @@ def guen_vote(game, player_id, team, votes, fail_req, rnd): return default_vote(game, player_id, team, votes, fail_req, rnd) if glance in team and elance in team: if votes[player_id] == 1: - return False + return 0.0 else: - return True + return 1.0 else: return default_vote(game, player_id, team, votes, fail_req, rnd) @@ -288,9 +264,9 @@ def percy_vote(game, player_id, team, votes, fail_req, rnd): return default_vote(game, player_id, team, votes, fail_req, rnd) if merlin in team and morgana in team: if votes[player_id] == 1: - return False + return 0.0 else: - return True + return 1.0 else: return default_vote(game, player_id, team, votes, fail_req, rnd) diff --git a/tim.py b/tim.py index fa3f690..8d69bb6 100644 --- a/tim.py +++ b/tim.py @@ -9,8 +9,7 @@ from models.default_model import DefaultModel from game_evaluator import DeceptionGame, AvalonGame - -def repl_report(report, namemap, ngood): +def repl_report(report, top_k, namemap, ngood): sort_order = sorted( [(report[i]["side"].get(True, 0.0), i) for i in range(len(report))], @@ -40,7 +39,9 @@ def repl_report(report, namemap, ngood): print(row) still_good += 1 - + for prob, deal in top_k: + print prob + print deal def display_statement(statement, namemap): out = "" @@ -168,15 +169,18 @@ def main(): if len(command_list) > 1: times = int(command_list[1]) game.eval(times, quick=True) - repl_report(game.report(), namemap, game.n_good) + players, top_k = game.report() + repl_report(players, top_k, namemap, game.n_good) elif command == "fulleval": times = 200 / (game.n_players - 4) * 2 if len(command_list) > 1: times = int(command_list[1]) game.eval(times) - repl_report(game.report(), namemap, game.n_good) + players, top_k = game.report() + repl_report(players, top_k, namemap, game.n_good) elif command == "report": - repl_report(game.report(), namemap, game.n_good) + players, top_k = game.report() + repl_report(players, top_k, namemap, game.n_good) elif command == "save": if len(command_list) < 2: print(Fore.RED + "Need an output file")