from otree.api import * import random import math import json import numpy as np import random import itertools doc = """Template""" class C(BaseConstants): NAME_IN_URL = 'Decision' PLAYERS_PER_GROUP = None # Rounds NUM_PRACTICE_ROUNDS = 2 NUM_PAYMENT_ROUNDS = 3 NUM_ROUNDS = NUM_PRACTICE_ROUNDS + NUM_PAYMENT_ROUNDS # Captchas max_captcha_time = 60 captcha_rounds = [1, 2, ] # The rounds in which captchas occur captcha_text = ["bonus", "payment", ] # The text the participants need to input (can use upper or lowercase) treatments_between_list = [0, 1] cost_list = [5, 15, 25, 35, 45, 55, 65, 75, 85, 95] value_list = [10, 30, 50, 70, 90] payoffs_list = [] for cost in cost_list: for value in value_list: payoffs_list.append([value, cost]) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): practice = models.IntegerField() player_round = models.IntegerField() decision = models.IntegerField() belief_1 = models.FloatField(min=0, max=100) # Between-Participant Treatment treatment_between = models.IntegerField() # Within-Participant Treatment treatment_index_within = models.IntegerField() value = models.FloatField() cost = models.FloatField() # Time fields time_spent = models.IntegerField() time_spent_instructions = models.IntegerField() # Captcha captcha_attempt_1 = models.StringField(label="", initial="") captcha_attempt_2 = models.StringField(label="", initial="") captcha_attempt_3 = models.StringField(label="", initial="") # Instructions incorrect_instruction_answers = models.StringField(blank=True) errors_quiz = models.IntegerField() instructions_clicked = models.BooleanField() prolific_id = models.StringField(default=str(" ")) # FUNCTIONS def creating_session(subsession: Subsession): # Between-participant treatment # Extend between treatment list * Total participants in session /2 /Nr Between treatments and shuffle total_number_participants = 10 # max([1,math.floor(len(player.session.get_participants())/2/len(C.treatments_between_list))]) between_treatment_list_shuffled = C.treatments_between_list * total_number_participants random.shuffle(between_treatment_list_shuffled) # Within-participant treatment reps = len(C.payoffs_list) // C.NUM_PAYMENT_ROUNDS remainder = len(C.payoffs_list) % C.NUM_PAYMENT_ROUNDS for player in subsession.get_players(): player.prolific_id = player.participant.label player.player_round = player.round_number player.participant.vars['failed_captcha'] = False # Between-participant treatment assignment player.treatment_between = between_treatment_list_shuffled[len(between_treatment_list_shuffled) % player.participant.id_in_session-1] if player.round_number == 1: # Within-participant treatment assignment treatments_indices_within = list(range(len(C.payoffs_list))) * reps remaining_treatments = list(range(len(C.payoffs_list))) random.shuffle(remaining_treatments) treatments_indices_within = treatments_indices_within + remaining_treatments[:remainder] random.shuffle(treatments_indices_within) for r in range(C.NUM_PAYMENT_ROUNDS): player.in_round(C.NUM_PRACTICE_ROUNDS+1+r).treatment_index_within = treatments_indices_within[r] if player.player_round <= C.NUM_PRACTICE_ROUNDS: player.practice = 1 player.value = random.choice(C.value_list) player.cost = np.round(random.choice(C.cost_list)+10*(random.random()-.5),1) if player.player_round > C.NUM_PRACTICE_ROUNDS: player.practice = 0 player.value = C.payoffs_list[player.treatment_index_within][0] player.cost = np.round(C.payoffs_list[player.treatment_index_within][1]+10*(random.random()-.5),1) # PAGES class Instructions(Page): form_model = 'player' form_fields = ['incorrect_instruction_answers', 'errors_quiz', 'time_spent_instructions',] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): return dict( participation_fee=player.session.config['participation_fee'], min_bonus_payment=player.session.config['min_bonus_payment'], max_bonus_payment=player.session.config['max_bonus_payment'], min_payment=player.session.config['min_payment'], max_payment=player.session.config['max_payment'], ) @staticmethod def before_next_page(player, timeout_happened): player.incorrect_instruction_answers = player.field_maybe_none('incorrect_instruction_answers') class TaskIntro(Page): @staticmethod def is_displayed(player): return ( player.round_number in [1,C.NUM_PRACTICE_ROUNDS+1] and not player.participant.vars.get('failed_captcha', False) ) class Task(Page): form_model = 'player' form_fields = ['decision','belief_1','time_spent',] @staticmethod def is_displayed(player): return ( not player.participant.vars.get('failed_captcha', False) ) @staticmethod def vars_for_template(player): return dict( payment_round_number = player.round_number-C.NUM_PRACTICE_ROUNDS, practice_round_number = player.round_number, round_number = player.round_number, ) class TaskFeedback(Page): @staticmethod def is_displayed(player): return ( player.round_number <= C.NUM_PRACTICE_ROUNDS and not player.participant.vars.get('failed_captcha', False) ) @staticmethod def vars_for_template(player): return dict( payment_round_number = player.round_number-C.NUM_PRACTICE_ROUNDS, practice_round_number = player.round_number, round_number = player.round_number, belief_A = player.belief_1, belief_B = 100-player.belief_1, paymentbelief_A = 2*player.belief_1-player.belief_1**2/100, paymentbelief_B = 100-player.belief_1**2/100, ) @staticmethod def js_vars(player): return dict( decision = player.decision, belief_1 = player.belief_1, ) class CaptchaFailed(Page): @staticmethod def is_displayed(player): return ( player.participant.vars.get('failed_captcha', True) ) class Captcha1(Page): template_name = 'Task1/Captcha.html' form_model = 'player' form_fields = ['captcha_attempt_1'] @staticmethod def is_displayed(player): if not ( player.round_number in C.captcha_rounds and not player.participant.vars.get('failed_captcha', False) and player.subsession.session.config['use_captchas'] == 1 ): return False else: return True @staticmethod def vars_for_template(player): max_captcha_time = C.max_captcha_time return { 'image_path': "images/captchas/captcha{}.png".format(C.captcha_rounds.index(player.round_number) + 1), 'attempt': 1, 'max_captcha_time': max_captcha_time, } class Captcha2(Page): template_name = 'Task1/Captcha.html' form_model = 'player' form_fields = ['captcha_attempt_2'] @staticmethod def is_displayed(player): if not ( player.round_number in C.captcha_rounds and not player.participant.vars.get('failed_captcha', False) and player.subsession.session.config['use_captchas'] == 1 ): return False else: return player.captcha_attempt_1.lower() != C.captcha_text[C.captcha_rounds.index(player.round_number)].lower() @staticmethod def vars_for_template(player): max_captcha_time = C.max_captcha_time return { 'image_path': "images/captchas/captcha{}.png".format(C.captcha_rounds.index(player.round_number) + 1), 'attempt': 2, 'max_captcha_time': max_captcha_time, } class Captcha3(Page): template_name = 'Task1/Captcha.html' form_model = 'player' form_fields = ['captcha_attempt_3'] @staticmethod def is_displayed(player): if not ( player.round_number in C.captcha_rounds and not player.participant.vars.get('failed_captcha', False) and player.subsession.session.config['use_captchas'] == 1 ): return False else: return ( player.captcha_attempt_1.lower() != C.captcha_text[ C.captcha_rounds.index(player.round_number) ].lower() and player.captcha_attempt_2.lower() != C.captcha_text[ C.captcha_rounds.index(player.round_number) ].lower() ) @staticmethod def vars_for_template(player): max_captcha_time = C.max_captcha_time return { 'image_path': "images/captchas/captcha{}.png".format(C.captcha_rounds.index(player.round_number) + 1), 'attempt': 3, 'max_captcha_time': max_captcha_time, } @staticmethod def before_next_page(player, timeout_happened): correct_text = C.captcha_text[C.captcha_rounds.index(player.round_number)].lower() if ( player.round_number in C.captcha_rounds and player.captcha_attempt_1.lower() != correct_text and player.captcha_attempt_2.lower() != correct_text and player.captcha_attempt_3.lower() != correct_text ): player.participant.vars['failed_captcha'] = True # Update page_sequence page_sequence = [ Instructions, Captcha1, Captcha2, Captcha3, CaptchaFailed, TaskIntro, Task, TaskFeedback, ]