from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants import random import time class Demographics(Page): form_model = 'player' form_fields = ['name', 'assignedID','perm','venmo'] def is_displayed(self): return self.subsession.round_number ==1 class ConsentForm(Page): # the general instructions/consent form def is_displayed(self): return self.subsession.round_number ==1 class MatchRound(Page): timeout_seconds = 0 def before_next_page(self): self.player.matchround_num() # execute the matchround_num() function self.player.chosen_rule() # execute the chosen_rule() function self.player.counterpart_decision() # get the robot's decision self.player.correct_action() # execute the correct_action() function # The instructions for AD class Instructions_1(Page): form_model = 'player' form_fields = ['quiz_1','quiz_2','quiz_3'] def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'die_threshold_plus_one': continuation_chance+1, } def quiz_1_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: Your counterpart is a robot and its decisions have been predetermined.)" def quiz_2_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The choices of the robot do not impact your earnings directly.)" def quiz_3_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The total number of rounds in the game is unknown to you ahead of time.)" def is_displayed(self): return self.player.match==1 and self.player.round_in_match==1 # Instructions for TFT class Instructions_2(Page): form_model = 'player' form_fields = ['quiz_TFT'] def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'die_threshold_plus_one': continuation_chance+1, } def quiz_TFT_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The rule in the next part of the experiment requires you to pay attention to only what the robot did last round.)" def is_displayed(self): return self.player.match==2 and self.player.round_in_match==1 # Instructions for TF3T class Instructions_3(Page): form_model = 'player' form_fields = ['quiz_TF3T'] def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'die_threshold_plus_one': continuation_chance+1, } def quiz_TF3T_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The rule in the next part of the experiment requires you to pay attention to what the robot has done in the past.)" def is_displayed(self): return self.player.match==3 and self.player.round_in_match==1 class Decision(Page): form_model = 'player' form_fields = ['decision'] def vars_for_template(self): me = self.player if me.round_in_match >1: start = Constants.first_rounds[me.match - 1] end = me.round_number-1 mylist = me.in_rounds(start, end) return { 'player_in_previous_rounds_reverse': mylist[::-1], 'AD_assigned': me.chosenrule=="S1", 'TFT_assigned': me.chosenrule=="S2", 'show_history': 1, } else: return { 'AD_assigned': me.chosenrule == "S1", 'TFT_assigned': me.chosenrule == "S2", 'show_history': 0,#not show history at the 1st round of a match } def before_next_page(self): self.player.check_action() # check if the chosen action follows the chosen rule in the round self.player.set_payoff() self.player.match_payoff() class MistakeAction(Page): def vars_for_template(self): me = self.player start=Constants.first_rounds[me.match-1] end=me.round_number mylist = me.in_rounds(start, end) return { 'player_up_to_now_reverse': mylist[::-1], 'AD_assigned': me.chosenrule=="S1", 'TFT_assigned': me.chosenrule == "S2", } def is_displayed(self): return self.player.checkaction == 0 # show if only making wrong choice in a round class EndBlock(Page): def vars_for_template(self): me=self.player #mylist=me.in_rounds(me.round_number-Constants.num_in_block+1, me.round_number) #if only show history of the current block start = Constants.first_rounds[me.match - 1] end = me.round_number mylist = me.in_rounds(start, end) return{ #'player_in_block_reverse': mylist[::-1], 'num_block': me.round_in_match // Constants.num_in_block, #since we only show the block # at the last round of a match, the calculation is quite easy 'player_up_to_now_reverse': mylist[::-1], 'end_in_block': me.round_in_match >= Constants.match_duration[me.match-1], 'num_paidround': Constants.match_duration[me.match-1], } def is_displayed(self): return self.subsession.round_number in Constants.last_rounds #def is_displayed(self): #return self.player.round_in_match % Constants.num_in_block ==0 class EndMatch(Page): #End of a game def vars_for_template(self): me=self.player start = Constants.first_rounds[me.match - 1] end = start+Constants.match_duration[me.match-1]-1#only show the history of paid rounds at EndMatch mylist=me.in_rounds(start, end) return{ 'no_mistake': me.nummistake==0, 'player_in_match_reverse': mylist[::-1], 'num_paidround': Constants.match_duration[me.match-1], 'mistake_deduct_sum': me.nummistake*20, 'AD_assigned': me.chosenrule == "S1", 'TFT_assigned': me.chosenrule == "S2", 'last_match': self.subsession.round_number == Constants.last_round, } def is_displayed(self): return self.subsession.round_number in Constants.last_rounds class End(Page): def is_displayed(self): return self.session.vars['alive'] == False or self.subsession.round_number == Constants.last_round # Part 2: Playing With Each Other class InstructionsP2_1s(Page): form_model = 'player' form_fields = ['quizP2_1_1s', 'quizP2_1_2s', 'quizP2_1_3s','quizP2_1_4s','quizP2_1_5'] def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'complex_treatment': self.session.config['complex_first'], } def quizP2_1_1s_error_message(self,value): if value !=50: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_2s_error_message(self,value): if value !=13: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_3s_error_message(self,value): if value !=13: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_4s_error_message(self,value): if value !=50: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_5_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The total number of rounds in the game is unknown to you ahead of time.)" def is_displayed(self): return self.subsession.round_number ==Constants.last_round and self.session.config['complex_first']==0 # Part 2: Playing With Each Other class InstructionsP2_1c(Page): form_model = 'player' form_fields = ['quizP2_1_1c', 'quizP2_1_2c', 'quizP2_1_3c','quizP2_1_4c','quizP2_1_5'] def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'complex_treatment': self.session.config['complex_first'], } def quizP2_1_1c_error_message(self,value): if value !=50: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_2c_error_message(self,value): if value !=23: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_3c_error_message(self,value): if value !=23: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_4c_error_message(self,value): if value !=50: return "You made a mistake. Please correct it before going on. (Hint: Your action determines the relevant row and your counterpart's action the relevant column for finding your earnings for the round. Your earnings are shown in the Payment Table in purple and your counterpart's earnings are shown in orange.)" def quizP2_1_5_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: The total number of rounds in the game is unknown to you ahead of time.)" def is_displayed(self): return self.subsession.round_number ==Constants.last_round and self.session.config['complex_first']==1 # Part 2: Choosing a Rule ## s first + no computation class InstructionsP2_2s(Page): form_model = 'player' form_fields = ['quizP2_2_1','quizP2_2_2s','quizP2_2_3s'] def vars_for_template(self): return { 'computation': self.session.config['computation'], 'implementation': self.session.config['implementation'], 'complex_treatment': self.session.config['complex_first'], 'salience': self.session.config['salience'], } def quizP2_2_1_error_message(self,value): if value !=4: return "You made a mistake. Please correct it before going on. (Hint: Your base payment will be determined by the rules you and your counterparts choose. The computer will apply the rules to millions of games with random lengths and pay you the average earnings over all of these games.)" def quizP2_2_2s_error_message(self,value): if value !=2: return "You made a mistake. Please correct it before going on. (Hint: There is a specific amount each rule combination will pay you and your counterpart. Your rule choice determines the relevant row and your counterpart's rule choice the relevant column for finding your earnings for the round. Your earnings are shown in the Rules Table in purple and your counterpart's earnings are shown in orange. )" def quizP2_2_3s_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: There is a specific amount each rule combination will pay you and your counterpart. Your rule choice determines the relevant row and your counterpart's rule choice the relevant column for finding your earnings for the round. Your earnings are shown in the Rules Table in purple and your counterpart's earnings are shown in orange. )" def is_displayed(self): return self.subsession.round_number ==Constants.last_round and self.session.config['complex_first']==0 and self.session.config['computation']==0 ## c first + no computation class InstructionsP2_2c(Page): form_model = 'player' form_fields = ['quizP2_2_1','quizP2_2_2c', 'quizP2_2_3c'] def vars_for_template(self): return { 'computation': self.session.config['computation'], 'implementation': self.session.config['implementation'], 'complex_treatment': self.session.config['complex_first'], 'salience': self.session.config['salience'], } def quizP2_2_1_error_message(self,value): if value !=4: return "You made a mistake. Please correct it before going on. (Hint: Your base payment will be determined by the rules you and your counterparts choose. The computer will apply the rules to millions of games with random lengths and pay you the average earnings over all of these games.)" def quizP2_2_2c_error_message(self, value): if value != 2: return "You made a mistake. Please correct it before going on. (Hint: There is a specific amount each rule combination will pay you and your counterpart. Your rule choice determines the relevant row and your counterpart's rule choice the relevant column for finding your earnings for the round. Your earnings are shown in the Rules Table in purple and your counterpart's earnings are shown in orange. )" def quizP2_2_3c_error_message(self, value): if value != 3: return "You made a mistake. Please correct it before going on. (Hint: There is a specific amount each rule combination will pay you and your counterpart. Your rule choice determines the relevant row and your counterpart's rule choice the relevant column for finding your earnings for the round. Your earnings are shown in the Rules Table in purple and your counterpart's earnings are shown in orange. )" def is_displayed(self): return self.subsession.round_number ==Constants.last_round and self.session.config['complex_first']==1 and self.session.config['computation']==0 ## computation class InstructionsP2_2comp(Page): form_model = 'player' form_fields = ['quizP2_2_1'] def vars_for_template(self): return { 'computation': self.session.config['computation'], 'implementation': self.session.config['implementation'], 'complex_treatment': self.session.config['complex_first'], 'salience': self.session.config['salience'], } def quizP2_2_1_error_message(self, value): if value != 4: return "You made a mistake. Please correct it before going on. (Hint: Your base payment will be determined by the rules you and your counterparts choose. The computer will apply the rules to millions of games with random lengths and pay you the average earnings over all of these games.)" def is_displayed(self): return self.subsession.round_number == Constants.last_round and self.session.config['computation'] == 1 # Part 2: Implementing your rule class InstructionsP2_3(Page): form_model = 'player' form_fields = ['quizP2_3'] def vars_for_template(self): return { 'complex_treatment': self.session.config['complex_first'], } def quizP2_3_error_message(self,value): if value !=3: return "You made a mistake. Please correct it before going on. (Hint: Your payments are determined both on the rule you select (determining your base payment) and this will be modified by the mistakes you make when implementing the rule.)" def is_displayed(self): return self.subsession.round_number ==Constants.last_round and self.session.config['implementation']==1 # Part 2: Summary class InstructionsP2_4(Page): def vars_for_template(self): continuation_chance = int(round(Constants.delta *100)) return { 'end_chance': 100-continuation_chance, 'continuation': continuation_chance, 'computation': self.session.config['computation'], 'implementation': self.session.config['implementation'], } def is_displayed(self): return self.subsession.round_number ==Constants.last_round page_sequence = [ Demographics, ConsentForm, MatchRound, Instructions_1, Instructions_2, Instructions_3, Decision, MistakeAction, EndBlock, EndMatch, End, InstructionsP2_1s, InstructionsP2_1c, InstructionsP2_2s, InstructionsP2_2c, InstructionsP2_2comp, InstructionsP2_3, InstructionsP2_4 ]