from otree.api import * c = cu doc = """ Comprehension test. If the user fails too many times, they exit. """ class C(BaseConstants): NAME_IN_URL = 'comprehension_test_complex' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): num_failed_attempts = models.IntegerField(initial=0) quiz1 = models.BooleanField( label='This study involves you logging into a video call (which will be recorded) and giving access to your camera and microphone.' ) quiz2 = models.BooleanField( label='You are allowed to talk to your partner during the individual phase as long as it is about the fruits.' ) quiz3 = models.BooleanField( label='In synchrony trials, PAC-MAN only moves if you and your partner press the same direction key within about one second.' ) quiz4 = models.BooleanField( label='Colors and values of fruits in the second phase (i.e., joint/parallel phase) correspond to those in the first phase (i.e., individual phase).' ) prolific_id = models.StringField(default=str(" ")) # PAGES class InstructionPage1(Page): timeout_seconds = 600 @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.participant.failed_too_many = True else: player.participant.failed_too_many = False @staticmethod def app_after_this_page(player: Player, upcoming_apps): if player.participant.failed_too_many: player.participant.vars["failed_comprehension"] = True return upcoming_apps[-1] # Redirects to the final app. class MyPage1(Page): timeout_seconds = 300 form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4'] @staticmethod def before_next_page(player: Player, timeout_happened): # timeout = fail if timeout_happened: player.num_failed_attempts += 1 player.participant.failed_too_many = False # first fail -> gets 2nd attempt return solutions = dict( quiz1=True, quiz2=False, quiz3=True, quiz4=True, ) got_all_correct = all(getattr(player, k) == v for k, v in solutions.items()) if got_all_correct: player.participant.failed_too_many = False else: # any mistake -> no correction opportunity, go straight to attempt 2 player.num_failed_attempts += 1 player.participant.failed_too_many = False # not "too many" yet class InstructionPage2(Page): timeout_seconds = 600 @staticmethod def is_displayed(player: Player): return player.num_failed_attempts > 0 @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.participant.failed_too_many = True @staticmethod def app_after_this_page(player: Player, upcoming_apps): if player.participant.failed_too_many: return upcoming_apps[-1] # Redirects to the final app. class MyPage2(Page): timeout_seconds = 300 form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4'] @staticmethod def is_displayed(player: Player): return player.num_failed_attempts > 0 @staticmethod def before_next_page(player: Player, timeout_happened): # timeout on second attempt = fail too many if timeout_happened: player.num_failed_attempts += 1 player.participant.failed_too_many = True player.participant.vars["failed_comprehension"] = True return solutions = dict( quiz1=True, quiz2=False, quiz3=True, quiz4=True, ) got_all_correct = all(getattr(player, k) == v for k, v in solutions.items()) if got_all_correct: player.participant.failed_too_many = False else: player.num_failed_attempts += 1 player.participant.failed_too_many = True player.participant.vars["failed_comprehension"] = True @staticmethod def app_after_this_page(player: Player, upcoming_apps): if player.participant.failed_too_many: return upcoming_apps[-1] class Results(Page): @staticmethod def before_next_page(player: Player, timeout_happened): player.prolific_id = player.participant.label import time player.participant.grouping_timeout = time.time() + 600 # give a participant 10 minutes to be grouped - after that they are removed # progress to the end if timed out on instructions if timeout_happened: player.participant.failed_too_many = True @staticmethod def app_after_this_page(player: Player, upcoming_apps): # progress to the end if failed too many if player.participant.failed_too_many is True: return upcoming_apps[-1] page_sequence = [InstructionPage1, MyPage1, InstructionPage2, MyPage2, Results] # page_sequence = [Results]