Skip to content

Instantly share code, notes, and snippets.

@paul-english
Created December 14, 2017 20:37
Show Gist options
  • Save paul-english/25724607c262925fb6fbcbecc724acc1 to your computer and use it in GitHub Desktop.
Save paul-english/25724607c262925fb6fbcbecc724acc1 to your computer and use it in GitHub Desktop.
Avalon
import random
import numpy as np
from sacred import Experiment
ex = Experiment()
@ex.config
def config():
n_sims = 1000
verbose = False
n_players = 5
n_bad_guys = {
5: 2,
6: 2,
7: 3,
8: 3,
9: 3,
10: 4,
}[n_players]
# TODO this depends on the n_players
# turn_team_size = [3, 3, 4, 4, 3]
# turn_mission_required_fails = [1, 1, 1, 2, 1]
turn_team_size = [2, 3, 2, 3, 3]
turn_mission_required_fails = [1, 1, 1, 1, 1]
class Player:
def __init__(self, player_id, is_merlin, is_bad_guy, bad_guys):
self.player_id = player_id
self.is_merlin = is_merlin
self.is_bad_guy = is_bad_guy
self.bad_guys = bad_guys
def choose_team(self, n_players, team_size):
# TODO players use belief of team to make choice
return np.random.choice(n_players, team_size, replace=False)
def vote_on_team(self, proposed_team):
# TODO if we think the mission will fail
return np.random.randint(2)
def vote_mission_passes(self, mission_team):
# TODO player can make strategic choice on how
# they vote, e.g. if two bad votes in the
if self.is_bad_guy:
return np.random.randint(2)
else:
return 1
def vote_on_team_callback(self, proposed_team, player_votes):
# team votes should inform you on player beliefs
pass
def mission_callback(self, mission_votes, mission_team):
# mission success should inform you on player votes
pass
# TODO encapsulate game state
class Avalon:
def __init__(self, n_players):
n_players
@ex.capture
def game(n_players, n_bad_guys, turn_team_size, turn_mission_required_fails, verbose):
special_roles = np.random.choice(n_players, n_bad_guys+1, replace=False)
merlin = special_roles[0]
bad_guys = special_roles[1:]
if verbose:
print('Merlin', merlin)
print('Bad guys', bad_guys)
players = [
Player(i, i == merlin, i in bad_guys, bad_guys if i in special_roles else None)
for i in range(n_players)
]
turn = 0
mission_turn = 0
n_successes = 0
n_fails = 0
n_passes = 0
while True:
if verbose: print('Turn %s, mission %s (s %s, f %s, p %s)' % (turn, mission_turn, n_successes, n_fails, n_passes))
team_size = turn_team_size[mission_turn]
turn_required_success_count = team_size - turn_mission_required_fails[mission_turn]
players_turn = turn % n_players
current_player = players[players_turn]
proposed_team = current_player.choose_team(n_players, team_size)
if verbose: print('Proposed team', proposed_team)
votes = [
player.vote_on_team(proposed_team)
for player in players
]
if verbose: print('Team votes', votes)
team_vote_succeeds = np.mean(votes) > 0.5
for player in players:
player.vote_on_team_callback(proposed_team, votes)
if not team_vote_succeeds:
if verbose: print('- Pass')
n_passes += 1
else:
mission_votes = [players[i].vote_mission_passes(proposed_team) for i in proposed_team]
if verbose: print('- Mission votes', mission_votes)
mission_success_count = sum(mission_votes)
for player in players:
player.mission_callback(mission_success_count, proposed_team)
if mission_success_count > turn_required_success_count:
if verbose: print('- Success')
n_successes += 1
else:
if verbose: print('- Fail')
n_fails += 1
mission_turn += 1
if n_successes >= 3:
# TODO allow an assasination of merlin
return 1
elif n_fails >= 3:
return 0
elif n_passes >= 5:
return 0
turn += 1
@ex.automain
def main(n_sims):
games = [game() for i in range(n_sims)]
avg_wins = np.mean(games)
return avg_wins
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment