import random from otree.api import * doc = """ This is a pilot version of inference-Self in the Failures of Strategic Thinking project. """ class C(BaseConstants): NAME_IN_URL = 'inference' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 MIN_TIME = 7 # in minutes MAX_TIME = 15 # in minutes NUMBER_OF_MISTAKES = 1 RATE_OF_MISTAKES = 2 BONUS_PER_CORRECT_TASK_PART1 = cu(0.15) BONUS_PER_CORRECT_TASK_PART2 = cu(0.25) OUTSIDE_OPTION = cu(1.5) NUMBER_OF_TASKS_PART1 = 2 NUMBER_OF_TASKS_PART2 = 10 PART1_TEMPLATE = 'inference/part1.html' PART2_TEMPLATE = 'inference/part2.html' BONUS_TEMPLATE = 'inference/bonus.html' COMPUTER_TYPES = 'inference/computerTypes.html' REVIEW_INSTRUCTIONS = 'inference/reviewInstructions.html' class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): cq1 = models.IntegerField(blank=True, choices=[ [1, 'It does not do anything.'], [2, 'It solves math tasks that can be easy or hard.'], [3, 'It decides whether the math tasks are easy or hard.'] ], widget=widgets.RadioSelect, label='What does the Computer do?' ) cq2 = models.IntegerField(blank=True, choices=[ [1, 'Only one, which can be of the Good or the Bad type.'], [2, 'Two, one of the Good type and one of the Bad type.'], [3, 'There are many computers.'] ], widget=widgets.RadioSelect, label='How many Computers are there?' ) cq3 = models.IntegerField(blank=True, choices=[ [1, 'Yes, there is only one computer which solves tasks in both part 1 and part 2,' ' but the computer can be of a different type in parts 1 and part 2.'], [2, 'No, there are two computers, one for each part.'], [3, 'Yes, there is only one computer which solves tasks in both part 1 and part 2,' ' and the computer can only be of one type throughout the study.'] ], widget=widgets.RadioSelect, label='Is the Computer that solves tasks in part 1 the same as the one that solves tasks' ' in part 2 of this study?' ) cq4 = models.IntegerField(blank=True, choices=[ [1, 'It makes no mistakes in easy or hard tasks.'], [2, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistakes every ' + str(C.RATE_OF_MISTAKES) + ' easy tasks.'], [3, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistakes every ' + str(C.RATE_OF_MISTAKES) + ' hard tasks.'] ], widget=widgets.RadioSelect, label='How many mistakes does a computer make if it is of the Good type?' ) cq5 = models.IntegerField(blank=True, choices=[ [1, 'It makes no mistakes in easy or hard tasks.'], [2, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistakes every ' + str(C.RATE_OF_MISTAKES) + ' easy tasks.'], [3, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistakes every ' + str(C.RATE_OF_MISTAKES) + ' hard tasks.'] ], widget=widgets.RadioSelect, label='How many mistakes does a computer make if it is of the Bad type?' ) cq6 = models.IntegerField(blank=True, choices=[ [1, 'It faces ' + str(C.NUMBER_OF_MISTAKES) + ' easy and ' + str(C.NUMBER_OF_MISTAKES) + ' hard tasks, for a total of ' + str(C.NUMBER_OF_MISTAKES*2) + '.'], [2, 'It has not yet been decided. It is your task to decide it.'], [3, 'It faces ' + str(C.NUMBER_OF_TASKS_PART1) + ' hard tasks.'], ], widget=widgets.RadioSelect, label='In part 1, does the computer face ' + str(C.NUMBER_OF_TASKS_PART1) + ' easy or ' + str(C.NUMBER_OF_TASKS_PART1) + ' hard tasks?' ) cq7 = models.IntegerField(blank=True, choices=[ [1, 'It faces ' + str(C.NUMBER_OF_TASKS_PART2) + ' easy and ' + str(C.NUMBER_OF_TASKS_PART2) + ' hard tasks, for a total of ' + str(C.NUMBER_OF_TASKS_PART2 * 2) + '.'], [2, 'It has not yet been decided. It is your task to decide it.'], [3, 'It faces ' + str(C.NUMBER_OF_TASKS_PART2) + ' hard tasks.'] ], widget=widgets.RadioSelect, label='In part 2, does the computer face ' + str(C.NUMBER_OF_TASKS_PART2) + ' easy or ' + str(C.NUMBER_OF_TASKS_PART2) + ' hard tasks?' ) cq8 = models.IntegerField(blank=True, choices=[ [1, 'For each task that the computer solves correctly, you get ' + str(C.BONUS_PER_CORRECT_TASK_PART1) + '. This applies to both tasks.'], [2, 'For each task that the computer solves correctly in part 1, you get ' + str(C.BONUS_PER_CORRECT_TASK_PART1) + '. ' 'You can choose your bonus for part 2 to be ' + str(C.BONUS_PER_CORRECT_TASK_PART2) + ' for each correctly solved task, or a fixed bonus of ' + str(C.OUTSIDE_OPTION) + '.'], [3, 'For each task that the computer solves correctly, you get ' + str(C.BONUS_PER_CORRECT_TASK_PART1) + ' in part 1, and ' + str(C.BONUS_PER_CORRECT_TASK_PART2) + ' in part 2. ' 'This applies to both tasks, and you get ' + str(C.OUTSIDE_OPTION) + ' on top of it.'] ], widget=widgets.RadioSelect, label='How is your bonus determined?' ) cq9 = models.IntegerField(blank=True, choices=[ [1, 'Only one.'], [2, 'Two decisions.'], [3, 'I do not have to make any decisions.'] ], widget=widgets.RadioSelect, label='How many decisions will you make in this study?' ) mistakes = models.IntegerField(blank=True) payoffPart2 = models.CurrencyField(blank=True) taskDifficulty = models.IntegerField(choices=[ [1, 'Easy'], [2, 'Hard'] ], widget=widgets.RadioSelect, label='What type of task does the computer face in part 1?', blank=True) bonusChoice = models.IntegerField(blank=True, choices=[ [1, str(C.BONUS_PER_CORRECT_TASK_PART2) + ' for each task the computer ' 'solves correctly in this part.'], [2, str(C.OUTSIDE_OPTION) + ' independently of how many tasks the computer ' 'solves in this part.'] ], widget=widgets.RadioSelect, label='How do we determine your bonus for part 2?') feedback = models.LongStringField(label=None, blank=True) feedbackDifficulty = models.IntegerField(label="How difficult were the instructions? Please answer on a scale of 1 " "to 10 with 10 being the most difficult", blank=True, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], widget=widgets.RadioSelectHorizontal) feedbackUnderstanding = models.IntegerField(label="How well did you understand what you were asked to do?" " Please answer on a scale of 1 to 10 with 10 being the case when" " you understood perfectly", blank=True, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], widget=widgets.RadioSelectHorizontal) feedbackSatisfied = models.IntegerField(label="How satisfied are you with this study overall?" " Please answer on a scale of 1 to 10 with 10 being the most " "satisfied", blank=True, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], widget=widgets.RadioSelectHorizontal) feedbackPay = models.IntegerField(label="How appropriate do you think the payment for this study is relative to " "other ones on Prolific? Please answer on a scale of 1 to 10 with 10 being " "the most appropriate", blank=True, choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], widget=widgets.RadioSelectHorizontal) compType = models.FloatField() explain = models.LongStringField(label='When you chose, did you choose to have the computer face the easy ' 'or the hard tasks? Why?', blank=True) lottery = models.IntegerField(blank=True, choices=[ [1, '50% chance of getting ' + str(C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 * C.NUMBER_OF_MISTAKES / C.RATE_OF_MISTAKES + C.OUTSIDE_OPTION) + ' and 50% chance of getting ' + str(C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 + C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2) + '.'], [2, str(C.OUTSIDE_OPTION + C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1) + ' for sure.'] ], widget=widgets.RadioSelect, label='Given the chance, please choose which of the options below you would' ' prefer to receive:') advice = models.IntegerField(blank=True, choices=[ [1, 'Advice that the Computer faces easy tasks.'], [2, 'Advice that the Computer faces hard tasks.'] ], widget=widgets.RadioSelect, label='If you could advice another participant on their decision of whether ' 'the computer faces easy or hard tasks, which would you advise them to choose?' '') for j in range(1, 10): locals()['cq' + str(j) + '_mistakes'] = models.IntegerField(blank=True, initial=0) del j # FUNCTIONS # PAGES class Welcome(Page): pass class Consent(Page): pass class Instructions(Page): pass class Instructions1(Page): pass class CQ(Page): form_model = 'player' form_fields = ['cq1', 'cq2', 'cq3', 'cq4', 'cq5', 'cq6', 'cq7', 'cq8', 'cq9'] @staticmethod def error_message(player, values): if not player.session.config['development']: solutions = dict( cq1=2, cq2=1, cq3=3, cq4=1, cq5=3, cq6=2, cq7=3, cq8=2, cq9=2 ) error_messages = dict() for field_name in solutions: if values[field_name] is None: error_messages[field_name] = 'Please, answer the question.' elif values[field_name] != solutions[field_name]: error_messages[field_name] = 'Please, correct your answers!' name = 'player.' + str(field_name) + '_mistakes' exec("%s += 1" % name) return error_messages class Instructions2(Page): pass class EnvironmentStage(Page): form_model = 'player' form_fields = ['taskDifficulty'] @staticmethod def error_message(player, values): if not player.session.config['development'] and values['taskDifficulty'] is None: return 'Please, answer the question.' @staticmethod def before_next_page(player, timeout_happened): taskDifficultyMaybeNone = player.field_maybe_none('taskDifficulty') if player.session.config['development'] and taskDifficultyMaybeNone is None: player.taskDifficulty = 1 class PostDifficultyChoice(Page): @staticmethod def before_next_page(player, timeout_happened): player.compType = random.choice([0, 1]) # print('compType:', player.compType, 'TaskDifficulty:', player.taskDifficulty) if player.taskDifficulty == 1: player.mistakes = 0 else: if player.compType < 0.5: # print('MISTAKES') player.mistakes = int(C.NUMBER_OF_MISTAKES*C.NUMBER_OF_TASKS_PART1/C.RATE_OF_MISTAKES) else: player.mistakes = 0 player.payoff = C.BONUS_PER_CORRECT_TASK_PART1 * (C.NUMBER_OF_TASKS_PART1 - player.mistakes) class ObserveMistakes(Page): pass class BonusChoice(Page): form_model = 'player' form_fields = ['bonusChoice'] @staticmethod def before_next_page(player, timeout_happened): if player.bonusChoice == 1: if player.compType < 0.5: player.mistakes = int(C.NUMBER_OF_MISTAKES*C.NUMBER_OF_TASKS_PART2/C.RATE_OF_MISTAKES) else: player.mistakes = 0 player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes) else: player.payoffPart2 = C.OUTSIDE_OPTION player.payoff += player.payoffPart2 @staticmethod def error_message(player, values): if not player.session.config['development'] and values['bonusChoice'] is None: return 'Please, answer the question.' class PostBonusChoice(Page): @staticmethod def vars_for_template(player): return dict( payoffPart2=player.payoffPart2 ) class Hypothetical(Page): form_model = 'player' form_fields = ['advice', 'lottery', 'explain'] @staticmethod def error_message(player, values): if not player.session.config['development'] and (values['lottery'] is None or values['advice'] is None or not values['explain']): return 'Please, answer the questions.' class End(Page): form_model = 'player' form_fields = ['feedback', 'feedbackDifficulty', 'feedbackUnderstanding', 'feedbackSatisfied', 'feedbackPay'] @staticmethod def before_next_page(player, timeout_happened): player.participant.finished = True class Redirect(Page): pass page_sequence = [ Welcome, Consent, Instructions, Instructions1, CQ, Instructions2, EnvironmentStage, PostDifficultyChoice, ObserveMistakes, BonusChoice, PostBonusChoice, Hypothetical, End, Redirect ]