import random from otree.api import * """ Sim for Ultimatum/Two-Stage Bargaining Game """ class Constants(BaseConstants): name_in_url = 'ultimatum' players_per_group = 2 num_rounds = 4 instructions_template = 'ultimatum/instructions.html' endowment = cu(100) proposer_role = 'Proposer' responder_role = 'Responder' class Subsession(BaseSubsession): pass class Group(BaseGroup): offer = models.CurrencyField(min=0, max=Constants.endowment, label='') responder_choice = models.BooleanField( widget=widgets.RadioSelect, choices=[[True, 'Accept'], [False, 'Reject']], label='', ) counter = models.CurrencyField(min=0, max=25, label='') proposer_choice = models.BooleanField( widget=widgets.RadioSelect, choices=[[True, 'Accept'], [False, 'Reject']], label='', ) class Player(BasePlayer): pass # FUNCTIONS def creating_session(subsession: Subsession): subsession.group_randomly() def other_player(player: Player): return player.get_others_in_group()[0] def set_payoff(player: Player): group = player.group responder = group.get_player_by_role(Constants.responder_role) proposer = group.get_player_by_role(Constants.proposer_role) if group.responder_choice: responder.payoff = group.offer proposer.payoff = Constants.endowment - group.offer else: if player.round_number > 2 and group.proposer_choice: proposer.payoff = group.counter responder.payoff = 25 - group.counter else: player.payoff = 0 other_player(player).payoff = 0 # PAGES class Introduction(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 or player.round_number == 3 class ProposerOffer(Page): form_model = 'group' form_fields = ['offer'] @staticmethod def is_displayed(player: Player): return player.role == Constants.proposer_role class ResponderWaitPage(WaitPage): title_text = ' ' body_text = 'For this game, you are the responder. Please wait for the proposer to make their offer.' @staticmethod def is_displayed(player: Player): return player.role == Constants.responder_role class ResponderChoice(Page): form_model = 'group' form_fields = ['responder_choice'] @staticmethod def is_displayed(player: Player): return player.role == Constants.responder_role class ResponderCounter(Page): form_model = 'group' form_fields = ['counter'] @staticmethod def is_displayed(player: Player): group = player.group return ( not group.responder_choice and player.round_number > 2 and player.role == Constants.responder_role ) class ProposerWaitPage(WaitPage): title_text = ' ' body_text = 'Please wait for the responder to make their decision.' @staticmethod def is_displayed(player: Player): group = player.group return ( not group.responder_choice and player.round_number > 2 and player.role == Constants.proposer_role ) class ProposerChoice(Page): form_model = 'group' form_fields = ['proposer_choice'] @staticmethod def is_displayed(player: Player): group = player.group return ( not group.responder_choice and player.round_number > 2 and player.role == Constants.proposer_role ) class ResultsWaitPage(WaitPage): title_text = ' ' body_text = 'Please wait for the other player to make their decision.' @staticmethod def after_all_players_arrive(group: Group): for p in group.get_players(): set_payoff(p) class Results(Page): @staticmethod def vars_for_template(player: Player): group = player.group opponent = other_player(player) choice = 'accept' if group.responder_choice else 'reject' counter = 'accept' if group.proposer_choice else 'reject' return {'opponent': opponent, 'choice': choice, 'counter': counter} page_sequence = [ Introduction, ProposerOffer, ResponderWaitPage, ResponderChoice, ResponderCounter, ProposerWaitPage, ProposerChoice, ResultsWaitPage, Results, ]