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
]