from otree.api import * import random import itertools import time from random import choice doc = """ """ class C(BaseConstants): NAME_IN_URL = 'ignorance' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 1 low = 10 high = 30 multiplier = 0.75 pounds = 0.04 fixed = 1 reveal_cost = 0.2 class Subsession(BaseSubsession): pass def creating_session(subsession): # treatments for p in subsession.get_players(): p.Prolific_ID = p.participant.label if p.id_in_subsession: pressures = itertools.cycle([1,1,2,2,3,3,4,4]) for player in subsession.get_players(): player.code_treatment = next(pressures) if p.code_treatment == 1: p.treatment = "FT" elif p.code_treatment == 2: p.treatment = "OIF" elif p.code_treatment == 3: p.treatment = "OIC" elif p.code_treatment == 4: p.treatment = "FI" for player in subsession.get_players(): if player.id_in_group == 1: player.type = 'high' elif player.id_in_group == 2: player.type = 'low' for player in subsession.get_players(): if player.type == 'high': player.endowment = C.high else: player.endowment = C.low # treatment in player section class Group(BaseGroup): pass class Player(BasePlayer): code_treatment = models.IntegerField() treatment = models.StringField() type = models.StringField() belief_e = models.IntegerField( label="How many tokens do you estimate that the other group member you are matched with has been allocated?", min=0) belief_c = models.IntegerField( label="How many tokens do you estimate that the other group member you are matched with has contributed?", min=0) belief_c2 = models.IntegerField( label="How many tokens do you estimate that the other group member you are matched with has contributed?", min=0) contribution = models.IntegerField(label="Please now enter your contribution decision:", min=0) other_contribution = models.IntegerField() other_belief = models.IntegerField() endowment = models.IntegerField() belief_points = models.IntegerField() my_points = models.FloatField() bonus_earnings = models.FloatField() Prolific_ID = models.StringField( label="Prolific ID", ) control_question = models.StringField( choices=[ ['1', 'I agree to take part. Take me to the study.'], ['2', 'I do not agree to take part in this study. Take me back to Prolific.'], ], label="Do you agree to participate in this study?", widget=widgets.RadioSelect ) question1 = models.StringField(label='' ) question2 = models.StringField(label='') attempt = models.IntegerField(initial=0) reveal = models.StringField( choices=[ ['1', 'Reveal the other group member’s endowment.'], ['2', 'Continue without learning it.'], ], label='', widget=widgets.RadioSelect ) own_fair = models.IntegerField( min = 0, label = '' ) other_fair = models.IntegerField( min=0, label='' ) own_moral = models.IntegerField( min=0, label='' ) other_moral = models.IntegerField( min=0, label='' ) own_fair2 = models.IntegerField( min=0, label='' ) other_fair2 = models.IntegerField( min=0, label='' ) own_moral2 = models.IntegerField( min=0, label='' ) other_moral2 = models.IntegerField( min=0, label='' ) guilty = models.StringField( choices=[ ['0', ''], ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) guilty2 = models.StringField( choices=[ ['0', ''], ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) # Reveal = 1 (chose to reveal) rev_yes_fair = models.BooleanField(blank=True) rev_yes_curious = models.BooleanField(blank=True) rev_yes_important = models.BooleanField(blank=True) rev_yes_coordination = models.BooleanField(blank=True) rev_yes_other = models.BooleanField(blank=True) rev_yes_other_text = models.StringField(label='', blank=True) # Reveal = 2 (chose NOT to reveal) rev_no_guilty = models.BooleanField(blank=True) rev_no_unnecessary = models.BooleanField(blank=True) rev_no_comparisons = models.BooleanField(blank=True) rev_no_inappropriate = models.BooleanField(blank=True) rev_no_simple = models.BooleanField(blank=True) rev_no_expect_higher = models.BooleanField(blank=True) rev_no_expect_lower = models.BooleanField(blank=True) rev_no_other = models.BooleanField(blank=True) rev_no_other_text = models.StringField(label='', blank=True) gender = models.StringField( choices=[ ['1', 'Male'], ['2', 'Female'], ['3', 'Other'], ], label="1. What is your gender?", widget=widgets.RadioSelect ) age = models.IntegerField( label="2. What is your age?", min=0, max=120 ) language = models.StringField( choices=[ ['1', 'Yes'], ['2', 'No'], ], label="3. Is English your first language?", widget=widgets.RadioSelect ) max_income = models.StringField( choices=[ ['1', 'Very important'], ['2', 'Important'], ['3', 'Indifferent'], ['4', 'Not important'], ['5', 'Not important at all'], ], label="4. How important was it for you to maximise your own income during the experiment?", widget=widgets.RadioSelect ) trust = models.StringField( choices=[ ['1', 'Most people can be trusted'], ['2', 'You need to be very careful in dealing with people'], ], label="5. Generally speaking, would you say that most people can be trusted or that you need to be very " "careful in dealing with people?", widget=widgets.RadioSelect ) risk = models.StringField( choices=[ ['0', ''], ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) instructions = models.StringField( choices=[ ['1', 'Very difficult'], ['2', 'Difficult'], ['3', 'Neutral'], ['4', 'Easy'], ['5', 'Very easy'], ], label="13. How did you find the instructions?", widget=widgets.RadioSelect ) econ_exp = models.IntegerField( label="14. How many economics experiments have you participated in before this one? ", ) feedback = models.StringField( blank=True, label="15. Do you have any other comments or feedback regarding this experiment?", ) decisionavoid1 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="7. I postpone making decisions about my future financial situation." ) decisionavoid2 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="8. I avoid making decisions about my current financial situation." ) decisionavoid3 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="9. Making financial decisions is time-consuming and effortful so I often do not take active decisions." ) infoavoid1 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="10. I would rather not know how much I spent last month." ) infoavoid2 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="11. I would rather not know the status of my debts." ) infoavoid3 = models.IntegerField( choices=[[1, ""], [2, ""], [3, ""], [4, ""], [5, ""]], label="12. When it comes to managing my own finances, ignorance is bliss." ) def control_question_error_message(player,value): correct_answer = '1' if value != correct_answer: error_message = "If you do not agree to take part in this study, please close your browser tab." return error_message def contribution_error_message(player, value): maximum = player.endowment if value > maximum: error_message = "You cannot contribute more than the number of tokens you have been allocated. " \ "Please try again." return error_message def belief_c_error_message(player, value): if value > player.belief_e: return "Your estimate cannot exceed your stated belief about the other group member’s endowment. Please try again." def belief_c2_error_message(player, value): other = player.get_others_in_group()[0] if value > other.endowment: return "Your estimate cannot exceed the other group member’s endowment. Please try again." def own_fair_error_message(player, value): if value > player.endowment: return "You cannot contribute more than the number of tokens you have been allocated." def own_fair2_error_message(player, value): if value > player.endowment: return "You cannot contribute more than the number of tokens you have been allocated." def other_fair_error_message(player, value): if value > player.belief_e: return "The other group member cannot contribute more than the number of tokens they have been allocated." def other_fair2_error_message(player, value): other = player.get_others_in_group()[0] if value > other.endowment: return "The other group member cannot contribute more than the number of tokens they have been allocated." def own_moral_error_message(player, value): if value > player.endowment: return "You cannot contribute more than the number of tokens you have been allocated." def own_moral2_error_message(player, value): if value > player.endowment: return "You cannot contribute more than the number of tokens you have been allocated." def other_moral_error_message(player, value): if value > player.belief_e: return "The other group member cannot contribute more than the number of tokens they have been allocated." def other_moral2_error_message(player, value): other = player.get_others_in_group()[0] if value > other.endowment: return "The other group member cannot contribute more than the number of tokens they have been allocated." #def set_payoffs(group): players = group.get_players() total_contribution = sum(p.contribution for p in players) total_belief = sum(p.belief for p in players) for p in players: p.other_contribution = total_contribution - p.contribution if p.belief == p.other_contribution: p.belief_points = 10 else: p.belief_points = 0 p.other_belief = total_belief - p.belief # payoff in points (MPCR = 0.75) p.my_points = round((p.endowment - p.contribution) + C.multiplier * total_contribution + p.belief_points, 2) # convert points -> pounds and add fixed fee p.bonus_earnings = round(p.my_points * C.pounds, 2) # store total earnings in pounds in oTree's payoff field if p.treatment == 'OIC' and p.reveal == '1': p.payoff = round(C.fixed + p.bonus_earnings - C.reveal_cost, 2) else: p.payoff = round(C.fixed + p.bonus_earnings, 2) class Welcome(Page): form_model = 'player' form_fields = ['control_question'] class ProlificID(Page): form_model = 'player' form_fields = ['Prolific_ID'] class General_Instructions(Page): pass class Instructions(Page): pass class Questions(Page): form_model = 'player' form_fields = ['question1', 'question2'] @staticmethod def error_message(player, values): errors = {} q1 = (values.get('question1') or '').strip().replace(' ', '').lower() q2 = (values.get('question2') or '').strip().replace(' ', '').lower() if q1 != 'x': errors['question1'] = "Incorrect. Please enter again." if q2 != 'x+1': errors['question2'] = "Incorrect. Please enter again." # record EVERY click player.attempt += 1 return errors or None class Endowment(Page): form_model = 'player' def get_form_fields(player): if player.treatment == 'OIF' or player.treatment == 'OIC': return ['reveal'] else: return [] class Contribution(Page): form_model = 'player' form_fields = ['contribution' ] def vars_for_template(player): other = player.get_others_in_group()[0] return dict( my_endowment=player.endowment, other_endowment=other.endowment ) class Belief_e(Page): form_model = 'player' form_fields = ['belief_e' ] def vars_for_template(player): return dict( my_endowment=player.endowment, ) def is_displayed(player): return ( (player.treatment in ['OIF', 'OIC'] and player.reveal == '2') or (player.treatment == 'FI') ) class Belief_c(Page): form_model = 'player' form_fields = ['belief_c' ] def vars_for_template(player): return dict( my_endowment=player.endowment, other_endowment_belief=player.belief_e ) def is_displayed(player): return ( (player.treatment in ['OIF', 'OIC'] and player.reveal == '2') or (player.treatment == 'FI') ) class fairness(Page): form_model = 'player' form_fields = ['own_fair', 'other_fair', 'own_moral', 'other_moral' ] def vars_for_template(player): return dict( my_endowment=player.endowment, other_endowment_belief=player.belief_e ) def is_displayed(player): return ( (player.treatment in ['OIF', 'OIC'] and player.reveal == '2') or (player.treatment == 'FI') ) class guilty(Page): form_model = 'player' form_fields = ['guilty' ] def is_displayed(player): return ( (player.treatment in ['OIF', 'OIC'] and player.reveal == '2') or (player.treatment == 'FI') ) class reason(Page): form_model = 'player' def get_form_fields(player): if player.reveal == '1': return [ 'rev_yes_fair', 'rev_yes_curious', 'rev_yes_important', 'rev_yes_coordination', 'rev_yes_other', 'rev_yes_other_text', ] elif player.reveal == '2': return [ 'rev_no_guilty', 'rev_no_unnecessary', 'rev_no_comparisons', 'rev_no_inappropriate', 'rev_no_simple', 'rev_no_expect_higher', 'rev_no_expect_lower', 'rev_no_other', 'rev_no_other_text', ] @staticmethod def error_message(player, values): def any_ticked(fields): return any(values.get(f) for f in fields) if player.reveal == '1': yes_checks = [ 'rev_yes_fair', 'rev_yes_curious', 'rev_yes_important', 'rev_yes_coordination', 'rev_yes_other', ] if not any_ticked(yes_checks): return 'Please select at least one option.' if values.get('rev_yes_other'): other_text = (values.get('rev_yes_other_text') or '').strip() if not other_text: return 'You selected "Other". Please specify.' elif player.reveal == '2': no_checks = [ 'rev_no_guilty', 'rev_no_unnecessary', 'rev_no_comparisons', 'rev_no_inappropriate', 'rev_no_simple', 'rev_no_expect_higher', 'rev_no_expect_lower', 'rev_no_other', ] if not any_ticked(no_checks): return 'Please select at least one option.' if values.get('rev_no_other'): other_text = (values.get('rev_no_other_text') or '').strip() if not other_text: return 'You selected "Other". Please specify.' def is_displayed(player): return (player.treatment in ['OIF', 'OIC'] ) class Belief_c2(Page): form_model = 'player' form_fields = ['belief_c2' ] def vars_for_template(player): other = player.get_others_in_group()[0] return dict( my_endowment=player.endowment, other_endowment=other.endowment ) class fairness2(Page): form_model = 'player' form_fields = ['own_fair2', 'other_fair2', 'own_moral2', 'other_moral2' ] def vars_for_template(player): other = player.get_others_in_group()[0] return dict( my_endowment=player.endowment, other_endowment=other.endowment ) class guilty2(Page): form_model = 'player' form_fields = ['guilty2' ] def vars_for_template(player): other = player.get_others_in_group()[0] return dict( my_endowment=player.endowment, other_endowment=other.endowment ) class Questionnaire(Page): form_model = 'player' form_fields = ['gender', 'age', 'language', 'max_income', 'trust', 'risk', 'decisionavoid1', 'decisionavoid2', 'decisionavoid3', 'infoavoid1', 'infoavoid2', 'infoavoid3', 'instructions', 'econ_exp', 'feedback'] class Thanks(Page): pass page_sequence = [Welcome,ProlificID,General_Instructions,Instructions, Endowment,Contribution,Belief_e,Belief_c,fairness,guilty,reason, Belief_c2,fairness2,guilty2,Questionnaire, Thanks]