from otree.api import * c = Currency doc = """ A matching pennies game framed in terms of terrorism """ class Constants(BaseConstants): name_in_url = 'terrorism' players_per_group = 2 num_rounds = 60 matcher_role = 'Matcher' mismatcher_role = 'Mismatcher' class Subsession(BaseSubsession): man_payoff = models.IntegerField(initial=10) woman_payoff = models.IntegerField(initial=50) class Group(BaseGroup): pass class Player(BasePlayer): choice = models.StringField( choices=[['Man', 'Man'], ['Woman', 'Woman']], widget=widgets.RadioSelect, label="I choose:", ) is_winner = models.BooleanField() opponent_choice = models.StringField() opponent_payoff = models.CurrencyField() is_bot = models.BooleanField(initial=False) # FUNCTIONS def creating_session(subsession: Subsession): if subsession.round_number == 1: for player in subsession.get_players(): participant = player.participant participant.vars['is_dropout'] = False participant.vars['is_bot'] = False if subsession.round_number <= Constants.num_rounds / 3: subsession.man_payoff = 10 subsession.woman_payoff = 50 elif Constants.num_rounds / 3 < subsession.round_number <= 2 / 3 * Constants.num_rounds: subsession.man_payoff = 50 subsession.woman_payoff = 10 else: subsession.man_payoff = 30 subsession.woman_payoff = 30 def set_payoffs(group: Group): subsession = group.subsession p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p1.opponent_choice = p2.choice p2.opponent_choice = p1.choice stakes = subsession.man_payoff for p in [p1, p2]: if p.role == Constants.mismatcher_role and p.choice == 'Woman': stakes = subsession.woman_payoff break for p in [p1, p2]: is_matcher = p.role == Constants.matcher_role p.is_winner = (p1.choice == p2.choice) == is_matcher if p.is_winner: p.payoff = c(stakes) else: p.payoff = c(0) p1.opponent_payoff = p2.payoff p2.opponent_payoff = p1.payoff # PAGES class Instructions(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def get_timeout_seconds(player): return 120 class New_payoffs(Page): @staticmethod def is_displayed(player: Player): return player.round_number in [Constants.num_rounds/3 + 1, Constants.num_rounds * 2/3 + 1] @staticmethod def get_timeout_seconds(player): return 45 class Choice(Page): form_model = 'player' form_fields = ['choice'] @staticmethod def vars_for_template(player: Player): return dict(player_in_previous_rounds=player.in_previous_rounds()) @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.vars['is_dropout']: return 7 # instant timeout, 1 second else: return 60 @staticmethod def before_next_page(player, timeout_happened): subsession = player.subsession import random participant = player.participant if timeout_happened: participant.vars['is_dropout'] = True actions_list = ['Man', 'Woman'] player.is_bot = True if player.round_number <= Constants.num_rounds / 3: [player.choice] = random.choices(actions_list, weights=(34, 66), k=1) elif Constants.num_rounds / 3 < subsession.round_number <= 2 / 3 * Constants.num_rounds: [player.choice] = random.choices(actions_list, weights=(66, 34), k=1) else: [player.choice] = random.choices(actions_list, weights=(50, 50), k=1) else: participant.vars['is_dropout'] = False player.is_bot = False class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoffs class ResultsSummary(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds @staticmethod def vars_for_template(player: Player): session = player.session player_in_all_rounds = player.in_all_rounds() return dict( total_payoff=sum([p.payoff for p in player_in_all_rounds]), player_in_all_rounds=player_in_all_rounds, ) page_sequence = [Instructions, New_payoffs, Choice, ResultsWaitPage, ResultsSummary]