import random from otree.api import * doc = """ Informational Cost of Interventions """ class C(BaseConstants): NAME_IN_URL = 'informational_cost' PLAYERS_PER_GROUP = None NUM_ROUNDS = 5 MIN_TIME = 15 # in minutes MAX_TIME = 25 # in minutes NUMBER_OF_MISTAKES = 1 RATE_OF_MISTAKES = 2 RATE_OF_MISTAKES2 = 1 BONUS_PER_CORRECT_TASK_PART1 = cu(0.15) BONUS_PER_CORRECT_TASK_PART2 = cu(0.25) OUTSIDE_OPTION = cu(1.5) OUTSIDE_OPTION2 = cu(1) NUMBER_OF_TASKS_PART1 = 2 NUMBER_OF_TASKS_PART2 = 10 PROBABILITY_OF_SWITCH = 0.25 PART1_MAX_BONUS = cu(BONUS_PER_CORRECT_TASK_PART1 * NUMBER_OF_TASKS_PART1) PART2_MAX_BONUS = cu(BONUS_PER_CORRECT_TASK_PART2 * NUMBER_OF_TASKS_PART2) PART1_TEMPLATE = 'informational_cost/part1.html' PART2_TEMPLATE = 'informational_cost/part2.html' BONUS_TEMPLATE = 'informational_cost/bonus.html' COMPUTER_TYPES = 'informational_cost/computerTypes.html' REVIEW_INSTRUCTIONS = 'informational_cost/reviewInstructions.html' PART12_TEMPLATE = 'informational_cost/part12.html' PART22_TEMPLATE = 'informational_cost/part22.html' BONUS2_TEMPLATE = 'informational_cost/bonus2.html' SOFTWARE_TYPES = 'informational_cost/softwareTypes.html' REVIEW_INSTRUCTIONS2 = 'informational_cost/reviewInstructions2.html' NUMBER_OF_STAGES = 6 # modify jointly with word below NUMBER_OF_STAGES_WORD = 'six' # modify jointly with number above class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): for p in subsession.get_players(): p.treatment = random.choices(['baseline', 'soph'], weights=subsession.session.config['weights'])[0] stages_list = [*range(1, C.NUMBER_OF_STAGES + 1)] p.stageCounts = random.choices(stages_list, weights=[1/C.NUMBER_OF_STAGES, 1/C.NUMBER_OF_STAGES, 1/C.NUMBER_OF_STAGES, 1/C.NUMBER_OF_STAGES, 1/C.NUMBER_OF_STAGES, 1/C.NUMBER_OF_STAGES])[0] # All stages given equal weight in line above. Modify there if we want different weights. if p.treatment == 'soph': p.soph = True else: p.baseline = True p.compType = random.choice([0, 1]) p.compType_stage2 = random.choice([0, 1]) p.compType2 = random.choice([0, 1]) p.compType2_stage2 = random.choice([0, 1]) # print(p.treatment, 'CompType: (0 is Bad)', p.compType) p.currentStage = 1 print(p.stageCounts) class Group(BaseGroup): pass class Player(BasePlayer): # treated = models.BooleanField(initial=False) baseline = models.BooleanField(initial=False) treatment = models.StringField() stageCounts = models.IntegerField() currentStage = models.IntegerField() 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 in this stage?' ) 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 in each stage which solves tasks in both part 1 ' 'and part 2, and the computer can only be of one type throughout the stage.'] ], 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 stage?' ) cq_stage2 = models.IntegerField(blank=True, choices=[ [1, 'Yes, this is the same computer, so it is of the same type.'], [2, 'No, this is a different computer which is unique to this stage. ' 'It can be of the same or a different type than the one in stage 1.'], [3, 'No, this is a different computer which is unique to this stage, but it is ' 'of the same type as the computer in stage 1.'] ], widget=widgets.RadioSelect, label='Is the Computer that solves tasks in this stage the same as the one that ' 'solves tasks in stage 1?' ) cq4 = models.IntegerField(blank=True, choices=[ [1, 'It makes no mistakes in easy or hard tasks.'], [2, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistake every ' + str(C.RATE_OF_MISTAKES) + ' easy tasks.'], [3, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistake 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) + ' mistake every ' + str(C.RATE_OF_MISTAKES) + ' easy tasks.'], [3, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistake 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?' ) cq5_stage2 = models.IntegerField(blank=True, choices=[ [1, 'It makes no mistakes in easy or hard tasks.'], [2, 'It makes mistakes in every hard task it faces.'], [3, 'It makes ' + str(C.NUMBER_OF_MISTAKES) + ' mistake 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, widget=widgets.RadioSelect, label='Does the computer face easy or 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 stage?' ) cq9_soph = models.IntegerField(blank=True, choices=[ [1, 'Two decisions, one decision about the task the computer faces in part 1, and one' ' decision on how the bonus is determined for part 2.'], [2, 'Only one decision about the task the computer faces in part 1.'], [3, 'Only one decision on how the bonus is determined for part 2.'], [4, 'I do not have to make any decisions.'] ], widget=widgets.RadioSelect, label='How many decisions will you make in this stage?' ) cq10 = models.IntegerField(blank=True, choices=[ [1, 'No, you will never learn exactly how many mistakes it made.'], [2, 'Yes, you will learn about it but only once the experiment ends and you get your' ' bonus payment.'], [3, 'Yes, you will learn about it before part 2.'], ], widget=widgets.RadioSelect, label='Will you learn the number of mistakes that the computer makes in part 1, if any?' ) for j in range(1, 11): locals()['cq' + str(j) + '_mistakes'] = models.IntegerField(blank=True, initial=0) del j cq9_soph_mistakes = models.IntegerField(blank=True, initial=0) cq5_stage2_mistakes = models.IntegerField(blank=True, initial=0) cq_stage2_mistakes = models.IntegerField(blank=True, initial=0) mistakes = models.IntegerField(blank=True) mistakes2 = models.IntegerField(blank=True) mistakes_stage2 = models.IntegerField(blank=True) mistakes2_stage2 = models.IntegerField(blank=True) payoffPart2 = models.CurrencyField(blank=True) payoffPart22 = models.CurrencyField(blank=True) payoffPart12 = models.CurrencyField(blank=True) taskDifficulty = models.IntegerField(choices=[ [1, 'Easy'], [2, 'Hard'] ], widget=widgets.RadioSelect, blank=True) taskDifficulty_stage2 = models.IntegerField(choices=[ [1, 'Easy'], [2, 'Hard'] ], widget=widgets.RadioSelect, blank=True) taskDifficulty2 = models.IntegerField(choices=[ [1, 'Landscapes'], [2, 'People'] ], widget=widgets.RadioSelect, blank=True) taskDifficulty2_stage2 = models.IntegerField(choices=[ [1, 'Landscapes'], [2, 'People'] ], widget=widgets.RadioSelect, 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?') bonusChoice_stage2 = 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?') bonusChoice2 = models.IntegerField(blank=True, choices=[ [1, 'subtract ' + str(C.BONUS_PER_CORRECT_TASK_PART2) + ' for each image the' ' software ' 'recognizes ' 'incorrectly in ' 'this part.'], [2, 'subtract ' + str(C.PART2_MAX_BONUS - C.OUTSIDE_OPTION) + ' independently of how many images the software recognizes correctly in ' 'this part.'] ], widget=widgets.RadioSelect, label='How do we determine the penalty in part 2 to be subtracted' ' from the maximum bonus of ' + str(C.PART2_MAX_BONUS) + '?') bonusChoice2_stage2 = models.IntegerField(blank=True, choices=[ [1, 'subtract ' + str(C.BONUS_PER_CORRECT_TASK_PART2) + ' for each image the software recognizes incorrectly in this part.'], [2, 'subtract ' + str(C.PART2_MAX_BONUS - C.OUTSIDE_OPTION) + ' independently of how many images the software recognizes correctly' ' in this part.'] ], widget=widgets.RadioSelect, label='How do we determine the penalty in part 2 to be subtracted' ' from the maximum bonus of ' + str(C.PART2_MAX_BONUS) + '?') feedback = models.LongStringField(label='Feedback:', 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) explain = models.LongStringField(label='When you chose, did you choose to have the computer face the easy ' 'or the hard tasks? Why?', blank=True) explain2 = models.LongStringField(label='When you chose, did you choose to have the software face the ' 'Landscape or the People images? Why?', blank=True) compType = models.FloatField() compType_stage2 = models.FloatField() compType2 = models.FloatField() compType2_stage2 = models.FloatField() lottery = models.IntegerField(blank=True, choices=[ [1, '50% chance of getting ' + str(C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 * (1 - 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:') lottery2 = models.IntegerField(blank=True, choices=[ [1, '50% chance of getting ' + str(C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 * (1 - C.NUMBER_OF_MISTAKES / C.RATE_OF_MISTAKES2) + 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, 'Advise that the computer faces easy tasks.'], [2, 'Advise that the computer faces hard tasks.'] ], widget=widgets.RadioSelect, label='If you could advise another participant on their decision of whether ' 'the computer faces easy or hard tasks, which would you advise them to choose?' '') advice2 = models.IntegerField(blank=True, choices=[ [1, 'Advise that the software faces Landscape images.'], [2, 'Advise that the software faces People images.'] ], widget=widgets.RadioSelect, label='If you could advise them on their decision of whether ' 'the software faces Landscape or People images, which would you advise them to ' 'choose?') probabilistic = models.FloatField() probabilistic2 = models.FloatField() probabilistic_stage2 = models.FloatField() probabilistic2_stage2 = models.FloatField() risky_part2 = models.BooleanField() # FUNCTIONS def cq10_error_message(player, value): if not player.session.config['development']: if value is None: return 'Please, answer the question.' elif value != 3: player.cq10_mistakes += 1 return 'Your answer is incorrect. You will learn how many mistakes the computer made, if any, before part' \ ' 2.' def cq6_choices(player): choices = [ [1, 'It has not yet been decided. It is randomly determined for both tasks, nothing you do can affect it.'], [2, 'For Part 1 it has not yet been decided; you will decide it, and there is a small chance that it is ' 'randomly determined instead. In Part 2 the computer faces ' + str(C.NUMBER_OF_TASKS_PART2) + ' hard tasks for sure.'], [3, 'It faces ' + str(C.NUMBER_OF_TASKS_PART1) + ' hard tasks in both parts.'] ] return choices # PAGES class Welcome(Page): pass class Consent(Page): pass class Instructions(Page): pass class IntroduceStages(Page): @staticmethod def is_displayed(player): return player.baseline or player.soph class Instructions1(Page): @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage, ) class Instructions12(Page): @staticmethod def is_displayed(player): return player.baseline or player.soph @staticmethod def vars_for_template(player): part22_outside_bonus_penalty = C.PART2_MAX_BONUS - C.OUTSIDE_OPTION return dict( part22_outside_bonus_penalty=part22_outside_bonus_penalty, currentStage=player.currentStage ) class CQ(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.currentStage == 1: questions = ['cq1', 'cq2', 'cq4', 'cq5', 'cq6'] if player.baseline: questions += ['cq9', 'cq3', 'cq7', 'cq8'] else: questions += ['cq9_soph', 'cq3', 'cq7', 'cq8'] else: # questions = ['cq4', 'cq5_stage2', 'cq6', 'cq9', 'cq_stage2', 'cq3', 'cq7'] questions = ['cq4', 'cq5_stage2', 'cq6', 'cq_stage2', 'cq3', 'cq7'] player.cq4 = None player.cq6 = None player.cq3 = None player.cq7 = None return questions @staticmethod def error_message(player, values): if not player.session.config['development']: if player.currentStage == 1: solutions = dict(baseline=dict(cq1=2, cq2=1, cq3=3, cq4=1, cq5=3, cq6=2, cq7=3, cq8=2, cq9=2), soph=dict(cq1=2, cq2=1, cq3=3, cq4=1, cq5=3, cq6=2, cq7=3, cq8=2, cq9_soph=1) ) else: solutions = dict(baseline=dict(cq4=1, cq5_stage2=2, cq6=2, cq7=3, cq3=3, # cq9=2, cq_stage2=2), soph=dict(cq4=1, cq5_stage2=2, cq6=2, cq7=3, cq3=3, cq_stage2=2), ) error_messages = dict() for field_name in solutions[player.treatment]: if values[field_name] is None: error_messages[field_name] = 'Please, answer the question.' elif values[field_name] != solutions[player.treatment][field_name]: error_messages[field_name] = 'Please, correct your answer!' name = 'player.' + str(field_name) + '_mistakes' exec("%s += 1" % name) return error_messages @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage, # nextStage=player.currentStage + 1 ) class Instructions2(Page): @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage, ) class EnvironmentStage(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.currentStage == 1: fields = ['taskDifficulty'] else: fields = ['taskDifficulty_stage2'] return fields @staticmethod def error_message(player, values): if not player.session.config['development']: if (player.currentStage == 1 and values['taskDifficulty'] is None) or \ (player.currentStage == 2 and values['taskDifficulty_stage2'] is None) or \ (player.currentStage == 3 and values['taskDifficulty2'] is None) or \ (player.currentStage == 4 and values['taskDifficulty2_stage2'] is None): return 'Please, answer the question.' @staticmethod def before_next_page(player, timeout_happened): if player.currentStage == 1: taskDifficultyMaybeNone = player.field_maybe_none('taskDifficulty') if player.session.config['development'] and taskDifficultyMaybeNone is None: player.taskDifficulty = 1 player.probabilistic = random.random() if player.probabilistic < C.PROBABILITY_OF_SWITCH: if player.taskDifficulty == 2: player.taskDifficulty = 1 else: player.taskDifficulty = 2 # print('PROBABILISTIC SWITCH TRIGGERED') else: taskDifficulty_stage2_MaybeNone = player.field_maybe_none('taskDifficulty_stage2') if player.session.config['development'] and taskDifficulty_stage2_MaybeNone is None: player.taskDifficulty_stage2 = 1 player.probabilistic_stage2 = random.random() # print(player.probabilistic_stage2) if player.probabilistic_stage2 < C.PROBABILITY_OF_SWITCH: if player.taskDifficulty_stage2 == 2: player.taskDifficulty_stage2 = 1 else: player.taskDifficulty_stage2 = 2 # print('PROBABILISTIC SWITCH TRIGGERED') @staticmethod def vars_for_template(player): label = 'What type of task does the computer face in part 1?' return dict( taskDifficulty_label=label, currentStage=player.currentStage ) class PostDifficultyChoice(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.currentStage == 1 and player.baseline: fields = ['cq10'] else: fields = [] return fields @staticmethod def before_next_page(player, timeout_happened): if player.currentStage == 1: if player.taskDifficulty == 1: player.mistakes = 0 else: if player.compType < 0.5: 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) else: if player.taskDifficulty_stage2 == 1: player.mistakes_stage2 = 0 else: if player.compType_stage2 < 0.5: player.mistakes_stage2 = int(C.NUMBER_OF_TASKS_PART1) else: player.mistakes_stage2 = 0 if player.stageCounts == 2: player.payoff = C.BONUS_PER_CORRECT_TASK_PART1 * (C.NUMBER_OF_TASKS_PART1 - player.mistakes_stage2) @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage, ) class ObserveMistakes(Page): @staticmethod def before_next_page(player, timeout_happened): if player.soph: # I think there are mistakes in both hard and easy parts of this if player.currentStage == 1: taskDifficulty = player.field_maybe_none('taskDifficulty') if taskDifficulty == 2: # if task is hard if player.compType > 0.5: if player.bonusChoiceHardGood == 1: player.risky_part2 = True player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION else: if player.bonusChoiceHardBad == 1: player.risky_part2 = True player.mistakes = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes) else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION else: # if task is easy if player.bonusChoiceEasy == 1: player.risky_part2 = True if player.compType <= 0.5: # if task is easy and comp is bad player.mistakes = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes) else: # if task is easy and comp is good player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION if player.stageCounts == 1: player.payoff += player.payoffPart2 else: taskDifficulty = player.field_maybe_none('taskDifficulty_stage2') if taskDifficulty == 2: # if task is hard if player.compType_stage2 > 0.5: # if task is hard and comp is good if player.bonusChoiceHardGood_stage2 == 1: player.risky_part2 = True player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION else: # if task is hard and comp is bad if player.bonusChoiceHardBad_stage2 == 1: player.risky_part2 = True player.mistakes_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes_stage2) else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION else: # if task is easy if player.bonusChoiceEasy_stage2 == 1: player.risky_part2 = True if player.compType_stage2 <= 0.5: # if task is easy and comp is bad player.mistakes_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES2) player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes_stage2) else: # if task is easy and comp is good player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart2 = C.OUTSIDE_OPTION if player.stageCounts == 2: player.payoff += player.payoffPart2 @staticmethod def vars_for_template(player): if player.currentStage == 2: return dict( currentStage=player.currentStage, payoffStage2=C.BONUS_PER_CORRECT_TASK_PART1 * (C.NUMBER_OF_TASKS_PART1 - player.mistakes_stage2) ) else: return dict( currentStage=player.currentStage ) class BonusChoice(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.baseline and player.currentStage == 1: fields = ['bonusChoice'] elif player.baseline and player.currentStage == 2: fields = ['bonusChoice_stage2'] else: fields = [] return fields @staticmethod def before_next_page(player, timeout_happened): if player.baseline: if player.currentStage == 1: bonusChoiceMaybeNone = player.field_maybe_none('bonusChoice') if bonusChoiceMaybeNone == 1: player.risky_part2 = True 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.risky_part2 = False player.bonusChoice = 2 player.payoffPart2 = C.OUTSIDE_OPTION if player.stageCounts == 1: player.payoff += player.payoffPart2 else: bonusChoice_stage2MaybeNone = player.field_maybe_none('bonusChoice_stage2') if bonusChoice_stage2MaybeNone == 1: player.risky_part2 = True if player.compType_stage2 < 0.5: player.mistakes_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES2) else: player.mistakes_stage2 = 0 player.payoffPart2 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes_stage2) else: player.risky_part2 = False player.bonusChoice_stage2 = 2 player.payoffPart2 = C.OUTSIDE_OPTION if player.stageCounts == 2: player.payoff += player.payoffPart2 @staticmethod def error_message(player, values): if player.baseline and not player.session.config['development']: if player.currentStage == 1 and values['bonusChoice'] is None: return 'Please, answer the question.' elif player.currentStage == 2 and values['bonusChoice_stage2'] is None: return 'Please, answer the question.' @staticmethod def vars_for_template(player): if player.currentStage == 1: taskDiff_stageless = player.taskDifficulty mistakes_stageless = player.mistakes if player.compType < 0.5: compType_stageless = 'Bad' else: compType_stageless = 'Good' else: taskDiff_stageless = player.taskDifficulty_stage2 mistakes_stageless = player.mistakes_stage2 if player.compType_stage2 < 0.5: compType_stageless = 'Bad' else: compType_stageless = 'Good' return dict( currentStage=player.currentStage, taskDiff_stageless=taskDiff_stageless, compType_stageless=compType_stageless, mistakes_stageless=mistakes_stageless ) class PostBonusChoice(Page): @staticmethod def is_displayed(player): return player.baseline @staticmethod def vars_for_template(player): return dict( payoffPart2=player.payoffPart2, currentStage=player.currentStage ) class PostBonusChoiceSoph(Page): @staticmethod def is_displayed(player): return player.soph @staticmethod def vars_for_template(player): part22_outside_bonus_penalty = C.PART2_MAX_BONUS - C.OUTSIDE_OPTION return dict( part22_outside_bonus_penalty=part22_outside_bonus_penalty, currentStage=player.currentStage ) ############################################################# class Transition(Page): @staticmethod def before_next_page(player, timeout_happened): player.currentStage += 1 @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage, nextStage=player.currentStage+1 ) ################### Second stage of the study ########### ################### THIRD STAGE ########################## # class Instructions22(Page): # pass class EnvironmentStage2(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.currentStage == 3: fields = ['taskDifficulty2'] else: fields = ['taskDifficulty2_stage2'] return fields @staticmethod def error_message(player, values): if not player.session.config['development']: if (player.currentStage == 3 and values['taskDifficulty2'] is None) or \ (player.currentStage == 4 and values['taskDifficulty2_stage2'] is None): return 'Please, answer the question.' @staticmethod def before_next_page(player, timeout_happened): if player.currentStage == 3: taskDifficultyMaybeNone2 = player.field_maybe_none('taskDifficulty2') if player.session.config['development'] and taskDifficultyMaybeNone2 is None: player.taskDifficulty2 = 1 player.probabilistic2 = random.random() # print(player.probabilistic) if player.probabilistic2 < C.PROBABILITY_OF_SWITCH: if player.taskDifficulty2 == 2: player.taskDifficulty2 = 1 else: player.taskDifficulty2 = 2 # print('PROBABILISTIC SWITCH TRIGGERED') else: taskDifficulty_stage2MaybeNone2 = player.field_maybe_none('taskDifficulty2_stage2') if player.session.config['development'] and taskDifficulty_stage2MaybeNone2 is None: player.taskDifficulty2_stage2 = 1 player.probabilistic2_stage2 = random.random() # print(player.probabilistic) if player.probabilistic2_stage2 < C.PROBABILITY_OF_SWITCH: if player.taskDifficulty2_stage2 == 2: player.taskDifficulty2_stage2 = 1 else: player.taskDifficulty2_stage2 = 2 # print('PROBABILISTIC SWITCH TRIGGERED') @staticmethod def vars_for_template(player): part22_outside_bonus_penalty = C.PART2_MAX_BONUS - C.OUTSIDE_OPTION label = 'What type of images does the software face in part 1?' return dict( taskDifficulty2_label=label, part22_outside_bonus_penalty=part22_outside_bonus_penalty, currentStage=player.currentStage ) class PostDifficultyChoice2(Page): form_model = 'player' @staticmethod def before_next_page(player, timeout_happened): if player.currentStage == 3: if player.taskDifficulty2 == 1: player.mistakes2 = 0 else: if player.compType2 < 0.5: player.mistakes2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART1 / C.RATE_OF_MISTAKES) else: player.mistakes2 = 0 player.payoffPart12 = C.BONUS_PER_CORRECT_TASK_PART1 * (C.NUMBER_OF_TASKS_PART1 - player.mistakes2) else: if player.taskDifficulty2_stage2 == 1: player.mistakes2_stage2 = 0 else: if player.compType2_stage2 < 0.5: player.mistakes2_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART1 / C.RATE_OF_MISTAKES2) else: player.mistakes2_stage2 = 0 player.payoffPart12 = C.BONUS_PER_CORRECT_TASK_PART1 * (C.NUMBER_OF_TASKS_PART1 - player.mistakes2_stage2) @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage ) class ObserveMistakes2(Page): @staticmethod def before_next_page(player, timeout_happened): if player.soph: if player.currentStage == 3: taskDifficulty = player.field_maybe_none('taskDifficulty2') if taskDifficulty == 2: # if task is hard if player.compType2 > 0.5: # if task is hard and comp is good if player.bonusChoiceHardGood2 == 1: player.risky_part2 = True player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION else: # if task is hard and comp is bad if player.bonusChoiceHardBad2 == 1: player.risky_part2 = True player.mistakes2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2) else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION else: # if task is easy if player.bonusChoiceEasy2 == 1: player.risky_part2 = True if player.compType2 <= 0.5: # if task is easy and comp is bad player.mistakes2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2) else: # if task is easy and comp is good player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION if player.stageCounts == 3: player.payoff = player.payoffPart12 + player.payoffPart22 else: taskDifficulty = player.field_maybe_none('taskDifficulty2_stage2') if taskDifficulty == 2: # if task is hard if player.compType2_stage2 > 0.5: # if task is hard and comp is good if player.bonusChoiceHardGood2_stage2 == 1: player.risky_part2 = True player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION else: # if task is hard and comp is bad if player.bonusChoiceHardBad2_stage2 == 1: player.risky_part2 = True player.mistakes2_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES2) player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2_stage2) else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION else: # if task is easy if player.bonusChoiceEasy2_stage2 == 1: player.risky_part2 = True if player.compType2_stage2 <= 0.5: # if task is easy and comp is bad player.mistakes2_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES2) player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2_stage2) else: # if task is easy and comp is good player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2 else: player.risky_part2 = False player.payoffPart22 = C.OUTSIDE_OPTION if player.stageCounts == 4: player.payoff = player.payoffPart12 + player.payoffPart22 @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage ) class BonusChoice2(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.baseline and player.currentStage == 3: fields = ['bonusChoice2'] elif player.baseline and player.currentStage == 4: fields = ['bonusChoice2_stage2'] else: fields = [] return fields @staticmethod def is_displayed(player): return player.baseline or player.soph @staticmethod def before_next_page(player, timeout_happened): if player.baseline: if player.currentStage == 3: bonusChoiceMaybeNone2 = player.field_maybe_none('bonusChoice2') if bonusChoiceMaybeNone2 == 1: player.risky_part2 = True if player.compType2 < 0.5: player.mistakes2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES) else: player.mistakes2 = 0 player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2) else: player.risky_part2 = False player.bonusChoice2 = 2 player.payoffPart22 = C.OUTSIDE_OPTION if player.stageCounts == 3: player.payoff = player.payoffPart12 + player.payoffPart22 else: bonusChoice_stage2MaybeNone2 = player.field_maybe_none('bonusChoice2_stage2') if bonusChoice_stage2MaybeNone2 == 1: player.risky_part2 = True if player.compType2_stage2 < 0.5: player.mistakes2_stage2 = int(C.NUMBER_OF_MISTAKES * C.NUMBER_OF_TASKS_PART2 / C.RATE_OF_MISTAKES2) else: player.mistakes2_stage2 = 0 player.payoffPart22 = C.BONUS_PER_CORRECT_TASK_PART2 * (C.NUMBER_OF_TASKS_PART2 - player.mistakes2_stage2) else: player.risky_part2 = False player.bonusChoice2_stage2 = 2 player.payoffPart22 = C.OUTSIDE_OPTION if player.stageCounts == 4: player.payoff = player.payoffPart12 + player.payoffPart22 @staticmethod def error_message(player, values): if player.baseline and not player.session.config['development']: if player.currentStage == 3 and values['bonusChoice2'] is None: return 'Please, answer the question.' elif player.currentStage == 4 and values['bonusChoice2_stage2'] is None: return 'Please, answer the question.' @staticmethod def vars_for_template(player): part22_outside_bonus_penalty = C.PART2_MAX_BONUS - C.OUTSIDE_OPTION if player.currentStage == 3: taskDiff_stageless = player.taskDifficulty2 mistakes_stageless = player.mistakes2 if player.compType2 < 0.5: compType_stageless = 'Bad' else: compType_stageless = 'Good' else: taskDiff_stageless = player.taskDifficulty2_stage2 mistakes_stageless = player.mistakes2_stage2 if player.compType2_stage2 < 0.5: compType_stageless = 'Bad' else: compType_stageless = 'Good' return dict( currentStage=player.currentStage, taskDiff_stageless=taskDiff_stageless, compType_stageless=compType_stageless, mistakes_stageless=mistakes_stageless, part22_outside_bonus_penalty=part22_outside_bonus_penalty, ) class PostBonusChoice2(Page): @staticmethod def is_displayed(player): return player.baseline @staticmethod def vars_for_template(player): part22_outside_bonus_penalty = C.PART2_MAX_BONUS - C.OUTSIDE_OPTION return dict( payoffPart22=player.payoffPart22, part22_outside_bonus_penalty=part22_outside_bonus_penalty, currentStage=player.currentStage ) class Lottery(Page): form_model = 'player' form_fields = ['lottery'] @staticmethod def before_next_page(player, timeout_happened): lotteryMaybeNone = player.field_maybe_none('lottery') if player.session.config['development'] and lotteryMaybeNone is None: player.lottery = 1 if player.stageCounts == 5: if player.lottery == 2: player.payoff = C.OUTSIDE_OPTION + C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 else: player.payoff = random.choices([C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 * (1 - C.NUMBER_OF_MISTAKES / C.RATE_OF_MISTAKES) + C.OUTSIDE_OPTION, C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 + C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2], weights=[0.5, 0.5])[0] @staticmethod def error_message(player, values): if not player.session.config['development'] and values['lottery'] is None: return 'Please, answer the question.' @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage ) class Lottery2(Page): form_model = 'player' form_fields = ['lottery2'] @staticmethod def before_next_page(player, timeout_happened): lottery2MaybeNone = player.field_maybe_none('lottery2') if player.session.config['development'] and lottery2MaybeNone is None: player.lottery2 = 1 if player.stageCounts == 6: if player.lottery2 == 2: player.payoff = C.OUTSIDE_OPTION + C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 else: player.payoff = random.choices([C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 * (1 - C.NUMBER_OF_MISTAKES / C.RATE_OF_MISTAKES2) + C.OUTSIDE_OPTION, C.BONUS_PER_CORRECT_TASK_PART1 * C.NUMBER_OF_TASKS_PART1 + C.BONUS_PER_CORRECT_TASK_PART2 * C.NUMBER_OF_TASKS_PART2], weights=[0.5, 0.5])[0] @staticmethod def error_message(player, values): if not player.session.config['development'] and values['lottery2'] is None: return 'Please, answer the question.' @staticmethod def vars_for_template(player): return dict( currentStage=player.currentStage ) class Hypothetical(Page): form_model = 'player' form_fields = ['advice', 'advice2', 'explain', 'explain2'] @staticmethod def error_message(player, values): if not player.session.config['development'] and (values['advice'] is None or not values['explain'] or not values['explain'] or values['advice2'] is None): 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, IntroduceStages, # 3 PARTS, MAYBE ONLY PAY ONE. Instructions1, # INSTRUCTIONS 1, ADAPT TO NEW FRAMEWORK CQ, Instructions2, PostBonusChoiceSoph, EnvironmentStage, PostDifficultyChoice, ObserveMistakes, BonusChoice, PostBonusChoice, Transition, Instructions1, CQ, Instructions2, PostBonusChoiceSoph, EnvironmentStage, PostDifficultyChoice, ObserveMistakes, BonusChoice, PostBonusChoice, Transition, Instructions12, Instructions2, PostBonusChoiceSoph, EnvironmentStage2, PostDifficultyChoice2, ObserveMistakes2, BonusChoice2, PostBonusChoice2, Transition, Instructions12, Instructions2, PostBonusChoiceSoph, EnvironmentStage2, PostDifficultyChoice2, ObserveMistakes2, BonusChoice2, PostBonusChoice2, Transition, Lottery, Transition, Lottery2, Hypothetical, End, Redirect ]