from otree.api import * doc = """ This app presents instructions to the task. """ class C(BaseConstants): NAME_IN_URL = 'instruction' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 # Templates INSTRUCTIONS = 'instruction/instruction.html' COMPREHENSION_QUESTIONS = 'instruction/comprehension_questions.html' POOL_DESCRIPTION = 'instruction/pool_description.html' class Subsession(BaseSubsession): pass class Group(BaseGroup): pass # FUNCTIONS def comprehension_questions(): return { "q1": "Contribution to Pool A provides tokens for each member in your group.", "q2": "Contribution to Pool B provides tokens for each member in your group.", "q3": "Contribution to Pool C reduces tokens for members of the other group.", "q4": "Contribution to Pool D provides tokens for each member in your group.", "q5": "The more tokens I end up with, the larger the bonus I can receive." } def correct_answers(): return { "q1_1": False, "q2_1": True, "q3_1": True, "q4_1": False, "q5_1": True, "q1_2": False, "q2_2": True, "q3_2": True, "q4_2": False, "q5_2": True } def question_list_1st(): return { "n_ie": ["q1_1", "q2_1", "q3_1", "q5_1"], "y_ie": ["q1_1", "q2_1", "q3_1", "q4_1", "q5_1"] } def question_list_2nd(): return { "n_ie": ["q1_2", "q2_2", "q3_2", "q5_2"], "y_ie": ["q1_2", "q2_2", "q3_2", "q4_2", "q5_2"] } def creating_session(subsession: Subsession): import random import itertools treatments = itertools.cycle(itertools.product(["y_ie", "n_ie"], ["X", "Y"])) for p in subsession.get_players(): # Assign condition and subgroup in a balanced way treatment = next(treatments) p.participant.condition = treatment[0] p.participant.subgroup = treatment[1] if p.participant.subgroup == "X": p.participant.other_group = "Y" else: p.participant.other_group = "X" # Comprehension checks p.participant.first_check_errors = 0 p.participant.first_check_fail = False p.participant.second_check_errors = 0 p.participant.second_check_fail = False p.participant.over_time = False p.participant.completion_code = str(random.randint(10 ** 6, 10 ** 7 - 1)) p.participant.receive_bonus = False def make_binary_question(label): return models.BooleanField( label=label, choices=[[True, "True"], [False, "False"]], widget=widgets.RadioSelectHorizontal ) class Player(BasePlayer): prolific_id = models.StringField() q1_1 = make_binary_question(label=comprehension_questions()["q1"]) q2_1 = make_binary_question(label=comprehension_questions()["q2"]) q3_1 = make_binary_question(label=comprehension_questions()["q3"]) q4_1 = make_binary_question(label=comprehension_questions()["q4"]) q5_1 = make_binary_question(label=comprehension_questions()["q5"]) q1_2 = make_binary_question(label=comprehension_questions()["q1"]) q2_2 = make_binary_question(label=comprehension_questions()["q2"]) q3_2 = make_binary_question(label=comprehension_questions()["q3"]) q4_2 = make_binary_question(label=comprehension_questions()["q4"]) q5_2 = make_binary_question(label=comprehension_questions()["q5"]) def failed_first_test(player: Player): return player.participant.first_check_fail # PAGES class InstructionFirst(Page): @staticmethod def vars_for_template(player: Player): return dict(n_group_mates=player.session.subgroup_size - 1) class ComprehensionFirst(Page): form_model = 'player' @staticmethod def get_form_fields(player: Player): return question_list_1st()[player.participant.condition] @staticmethod def before_next_page(player: Player, timeout_happened): for q in question_list_1st()[player.participant.condition]: if getattr(player, q) != correct_answers()[q]: player.participant.first_check_errors += 1 player.participant.first_check_fail = (player.participant.first_check_errors > 0) class InstructionSecond(Page): is_displayed = failed_first_test @staticmethod def vars_for_template(player: Player): return dict(n_group_mates=player.session.subgroup_size - 1) class ComprehensionSecond(Page): is_displayed = failed_first_test form_model = 'player' @staticmethod def get_form_fields(player: Player): return question_list_2nd()[player.participant.condition] @staticmethod def before_next_page(player: Player, timeout_happened): for q in question_list_2nd()[player.participant.condition]: if getattr(player, q) != correct_answers()[q]: player.participant.second_check_errors += 1 player.participant.second_check_fail = (player.participant.second_check_errors > 0) class Failed(Page): @staticmethod def is_displayed(player: Player): return player.participant.second_check_fail class Passed(Page): @staticmethod def is_displayed(player: Player): return (not player.participant.first_check_fail) or (not player.participant.second_check_fail) @staticmethod def before_next_page(player: Player, timeout_happened): player.prolific_id = player.participant.label page_sequence = [InstructionFirst, ComprehensionFirst, InstructionSecond, ComprehensionSecond, Failed, Passed]