from random import shuffle from otree.api import ( Page, WaitPage, cu, models, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, ) from prisoner import NextGameWaitPage author = "Jon Wood" doc = """ Ultimatum game. One player offers to split an endowment between both participants. This can either be rejected or accepted. """ class Constants(BaseConstants): name_in_url = 'ult' players_per_group = 2 num_rounds = 2 endowment = cu(100) instructions_template = 'ultimatum/instructions.html' class Subsession(BaseSubsession): pass class Group(BaseGroup): amount_kept = models.CurrencyField( min=0, max=Constants.endowment, doc="Amount kept", label="I will keep", ) amount_offered = models.CurrencyField( min=0, max=Constants.endowment, doc="Amount offered", label="I will give", ) amount_requested = models.CurrencyField( min=0, max=Constants.endowment, doc="Amount requested", label="I would accept at least" ) class Player(BasePlayer): pass # FUNCTIONS def set_payoffs(group: Group): p1, p2 = group.get_players() accepted = group.amount_offered >= group.amount_requested p1.payoff = (Constants.endowment - group.amount_offered) * accepted p2.payoff = group.amount_offered * accepted def creating_session(subsession: Subsession): subsession.group_randomly(fixed_id_in_group=True) if subsession.round_number == 2: mat = subsession.get_group_matrix() for i in range(len(mat)): mat[i] = mat[i][::-1] # reverse the roles subsession.set_group_matrix(mat) # PAGES class Introduction(Page): timeout_seconds = 180 @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Offer(Page): timeout_seconds = 90 form_model = 'group' form_fields = ['amount_offered', 'amount_kept'] @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 @staticmethod def error_message(player: Player, values): if values['amount_kept'] + values['amount_offered'] != Constants.endowment: return f'The numbers must add up to {Constants.endowment}' class Request(Page): timeout_seconds = 90 form_model = 'group' form_fields = ['amount_requested'] @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoffs class Results(Page): timeout_seconds = 30 page_sequence = [Introduction, Offer, Request, ResultsWaitPage, Results, NextGameWaitPage]