from otree.api import * import random import numpy as np from datetime import datetime doc = """ Player A decides how to divide a certain amount between himself and two other players. """ # CLASSES class C(BaseConstants): NAME_IN_URL = 'idp' PLAYERS_PER_GROUP = None NUM_ROUNDS = 3 INSTRUCTIONS_TEMPLATE = 'dictator_randomized/Instructions.html' INSTRUCTIONS_TEMPLATE_SEQ = 'dictator_randomized/Instructions_seq.html' INITIAL = cu(0) MAXITER = 100 PROB_SELECTED = 0.2 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): ENDOWMENT = models.CurrencyField() sent_amount_B = models.CurrencyField() sent_amount_C = models.CurrencyField() redo = models.BooleanField(initial=True) redo_seq = models.BooleanField(initial=True) selected = models.BooleanField() selected_round = models.IntegerField() error_count = models.IntegerField(initial=0) BC_error_count = models.IntegerField(initial=0) consent = models.BooleanField() # Comprehension Question Fields (SIM) comp_sim = models.IntegerField(widget=widgets.RadioSelectHorizontal, label="1. As Person A, you", choices=[[1, "can decide how much money to keep for yourself, but not for Person B and Person C."], [2, "can decide how much money to keep for yourself, and how much money Person B and Person C would each receive."], [3, "can decide how much money to keep for yourself, and how much money Person B would receive, but not how much money Person C would receive."], # [4, # "cannot decide how much money to keep for yourself and should wait for the decision of Person B."] ]) comp_BCreal = models.IntegerField(widget=widgets.RadioSelectHorizontal, label="2. There are Person B and Person C in the scenario. Who are these people?", choices=[[1, "They are real people who are recruited on MTurk just like you."], [2, "They are imaginary people."]]) # Comprehension Question Fields (SEQ) comp_seq = models.IntegerField(widget=widgets.RadioSelectHorizontal, label="As Person A, you get to decide how much to keep for yourself and pass on to Person B. What happens to the amount of money that you pass on to Person B?
", choices=[ [1, "Person B receives the money and does not have to make any decision."], # [2, # "Person B receives the money and has to pass on a fixed amount to Person C."], [2, "Person B receives the money and has to decide how much to keep for themselves and pass on to Person C."], [3, "Person B does not receive the money."]]) # FUNCTIONS # Error Messages for incorrect user inputs def comp_sim_error_message(player, value): if value != 2: player.error_count += 1 return('Incorrect response, please try again.') def comp_BCreal_error_message(player, value): if value != 1: player.BC_error_count += 1 return('Incorrect response, please try again.') def comp_seq_error_message(player, value): if value != 2: player.error_count += 1 return 'Incorrect response, please try again.' # PAGES class Consent(Page): form_model = 'player' form_fields = ['consent'] @staticmethod def is_displayed(group): return group.round_number==1 class Welcome(Page): @staticmethod def is_displayed(group): return group.round_number==1 # Randomize players to SIM/SEQ respectively @staticmethod def before_next_page(player, timeout_happened): participant = player.participant # Randomize odd/even players to SIM/SEQ: participant.sim = bool(player.id_in_group % 2) # seed = int(datetime.now().timestamp()) # rng = np.random.default_rng(seed) # participant.sim = bool(rng.binomial(n=1, p=0.5)) class Introduction(Page): @staticmethod def is_displayed(player): participant = player.participant return player.round_number==1 & participant.sim @staticmethod def before_next_page(player, timeout_happened): # Randomize for each session: bernoulli draw seed = int(datetime.now().timestamp()) rng = np.random.default_rng(seed) selected = bool(rng.binomial(n=1, p=C.PROB_SELECTED)) selected_round = int(rng.integers(1, 3, endpoint=True)) print("Selected for Payment:", selected) if selected: print("Selected Round:", selected_round) participant = player.participant participant.selected = selected participant.selected_round = selected_round class Introduction_seq(Page): @staticmethod def is_displayed(player): participant = player.participant return player.round_number==1 & ~participant.sim @staticmethod def before_next_page(player, timeout_happened): # Randomize for each session: bernoulli draw seed = int(datetime.now().timestamp()) rng = np.random.default_rng(seed) selected = bool(rng.binomial(n=1, p=C.PROB_SELECTED)) selected_round = int(rng.integers(1, 3, endpoint=True)) print("Selected for Payment:", selected) if selected: print("Selected Round:", selected_round) participant = player.participant participant.selected = selected participant.selected_round = selected_round class Comprehension(Page): form_model = 'player' form_fields = ['comp_sim','comp_BCreal'] @staticmethod def is_displayed(player): participant = player.participant return player.round_number==1 & participant.sim # Randomize the state between rounds def js_vars(player): participant = player.participant # Store selected round information player.selected = participant.selected player.selected_round = participant.selected_round # Shuffle the states if player.round_number==1: statesList = [10, 20, 30] seed = datetime.now().timestamp() random.seed(seed) random.shuffle(statesList) print("Shuffled states:", statesList) participant.state_1 = cu(statesList[0]) participant.state_2 = cu(statesList[1]) participant.state_3 = cu(statesList[2]) return dict() class Comprehension_seq(Page): form_model = 'player' form_fields = ['comp_seq','comp_BCreal'] @staticmethod def is_displayed(player): participant = player.participant return player.round_number == 1 & ~participant.sim # Randomize the state between rounds def js_vars(player): participant = player.participant # Store selected round information player.selected = participant.selected player.selected_round = participant.selected_round # Shuffle the states if player.round_number==1: statesList = [10, 20, 30] seed = datetime.now().timestamp() random.seed(seed) random.shuffle(statesList) print("Shuffled states:", statesList) participant.state_1 = cu(statesList[0]) participant.state_2 = cu(statesList[1]) participant.state_3 = cu(statesList[2]) return dict() # FOR Person A class Send(Page): form_model = 'player' form_fields = ['sent_amount_B', 'sent_amount_C'] # Passing data from Python to JavaScript def js_vars(player): participant = player.participant if player.round_number==1: player.ENDOWMENT = participant.state_1 elif player.round_number==2: player.ENDOWMENT = participant.state_2 else: player.ENDOWMENT = participant.state_3 return dict( endowment = player.ENDOWMENT ) # Validating multiple fields together - transferred amount must not exceed C.ENDOWMENT @staticmethod def error_message(player, values): print('values are', values) if values['sent_amount_B'] + values['sent_amount_C'] > player.ENDOWMENT: return 'You cannot transfer more than {} to Person B and Person C in total.'.format(player.ENDOWMENT) # Pass variables to the template @staticmethod def vars_for_template(player): pass @staticmethod def is_displayed(player): participant = player.participant return player.redo & participant.sim class Results(Page): # Passing data from Python to JavaScript def js_vars(player): group = player.group return dict( payoff_A = player.ENDOWMENT - player.sent_amount_B - player.sent_amount_C, payoff_B = player.sent_amount_B, payoff_C = player.sent_amount_C, endowment = player.ENDOWMENT ) form_model = 'player' form_fields = ['redo'] @staticmethod def is_displayed(player): participant = player.participant return player.redo & participant.sim @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if participant.selected==True and player.round_number==participant.selected_round: # Calculate payoffs participant.payoff = player.ENDOWMENT - player.sent_amount_B - player.sent_amount_C class Send_seq(Page): form_model = 'player' form_fields = ['sent_amount_B'] # Passing data from Python to JavaScript def js_vars(player): participant = player.participant if player.round_number==1: player.ENDOWMENT = participant.state_1 elif player.round_number==2: player.ENDOWMENT = participant.state_2 else: player.ENDOWMENT = participant.state_3 return dict( endowment = player.ENDOWMENT ) # Pass variables to the template @staticmethod def vars_for_template(player): pass @staticmethod def is_displayed(player): participant = player.participant return player.redo_seq & ~participant.sim class Results_seq(Page): # Passing data from Python to JavaScript def js_vars(player): return dict( payoff_A = player.ENDOWMENT - player.sent_amount_B, payoff_B = player.sent_amount_B, endowment = player.ENDOWMENT ) form_model = 'player' form_fields = ['redo_seq'] @staticmethod def is_displayed(player): participant = player.participant return player.redo_seq & ~participant.sim @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if participant.selected==True and player.round_number==participant.selected_round: # Calculate payoffs participant.payoff = player.ENDOWMENT - player.sent_amount_B class Transition(Page): @staticmethod def is_displayed(group): return group.round_number==3 page_sequence = [Consent, Welcome, Introduction, Introduction_seq, Comprehension, Comprehension_seq,] for _ in range(C.MAXITER): page_sequence = page_sequence + [Send, Results,] for _ in range(C.MAXITER): page_sequence = page_sequence + [Send_seq, Results_seq,] page_sequence = page_sequence + [Transition,]