from otree.api import * doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'UG' players_per_group = 2 num_rounds = 2 # budget is the amount of money to be distributed between the two players budget = 100 class Subsession(BaseSubsession): pass # we randomly for groups every period, self.group.randomly() does that # the option fixed_id_in_group=True ensures that participant ID of a person will be the same in all groups # which means that roles do not change: if someone is a Proposer in one period, will be a Proposer in the next period too def creating_session(subsession: Subsession): subsession.group_randomly(fixed_id_in_group=True) class Group(BaseGroup): # we use group variables for the decisions of the Proposer and Responder # proposed is the amount proposed by Proposer to the Responder # accept is a binary variable capturing whether the Responder accepts the division or not # we use group variables and not individual variables because we want to show one person's decision to the other person # this is easier this way, # note that for each group there is only one proposed amount and one acceptance decision, so this doesn't create a problem proposed = models.IntegerField() accept = models.IntegerField( choices=[ [0, 'Reject'], [1, 'Accept'], ], widget=widgets.RadioSelect ) class Player(BasePlayer): pass class Welcome(Page): # we say that this page should appear only in period 1, # def is_displayed(player: Player): is a method to do this, # player.round_number == 1 is the condition that shows when the page should appear @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Proposal(Page): #this page is shown to the Proposer only, Proposer will have ID number=1 in the group, while ID=2 is the Responder, we use this consistently everywhere #the displaying condition self.player.id_in_group == 1 says that the page is shown to ID=1 only @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 #now the form_model is group, not player because we ask the person to fill in the value of a group level variable form_model = 'group' form_fields = ['proposed'] class WaitpageProposer(WaitPage): #while the Proposer decides, the Responder has to wait, so we put her in a waiting page, this is shown to ID 2 only @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 class Acceptance(Page): #once the first decision by the Proposer is made, the Responder (ID=2) decides, so this page is shown to her only @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 form_model = 'group' form_fields = ['accept'] #while the Responder decides, the proposer waits, we make another waiting page #once all players arrive to here, all decisions are made, so we can compute the payoffs # the function def after_all_players_arrive(self): is executed after all players arrive class ResultsWaitPage(WaitPage): @staticmethod def after_all_players_arrive(group: Group): #we get the two players by id number, by the command self.group.get_player_by_id(1) and self.group.get_player_by_id(2) p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) #Then payoffs depend on whether the proposal is accepted, rejection was coded as 0, then all players get zero if group.accept == 0: p1.payoff = 0 p2.payoff = 0 #otherwise, Proposer (P1) gets Budget-proposed amount, Responder the Proposed amount else: p1.payoff = Constants.budget-group.proposed p2.payoff = group.proposed class Results(Page): pass class FinalResult(Page): #this page should appear only in the last round, the condition self.round_number == Constants.num_rounds #self.round_number gives you the current round number, while Constants.num_rounds is the last round @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds #the method vars_for_template(self) list the variables that we want to show on this page (except if they are group or individual characteristics defined in models.py) @staticmethod def vars_for_template(player: Player): #the final payoff of the participant is the sum of payoffs from all rounds, # we can make a list of players from all rounds by self.player.in_all_rounds() #then we iterate through that list with for and get the payoff of each player p, then add it by sum() function finalpayoff = sum([p.payoff for p in player.in_all_rounds()]), #we list these variable to be shown in the HTML, we can refer to these variable names in the HTML return dict( finalpayoff=finalpayoff ) page_sequence = [Welcome, Proposal, WaitpageProposer, Acceptance, ResultsWaitPage, Results, FinalResult]