from otree.api import * import time class C(BaseConstants): NAME_IN_URL = 'Quiz' PLAYERS_PER_GROUP = None NUM_ROUNDS = 4 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # We record if the participant can move on to the experiment proceed = models.BooleanField( doc="""This variable is equal to true if the participant can proceed to the experiment""", initial=False, ) # We need to record which questions are shown to the participant in the round questions_shown = models.StringField( doc="""This variable records the questions shown to the participant in the round""", initial='' ) # We need to record if the participant answered the questions correctly in the quiz question_one = models.IntegerField( doc="""This question asks about the nderlying dynamics of public good games and our experiment""", widget=widgets.RadioSelect, choices=[ [1, 'Participants of Type A contribute 45 Points; Participant B takes out 15 Points.'], [2, 'Participants of Type A contribute 19 Points; Participant B contributes 11 Points.'], [3, 'Participants of Type A contribute 26 Points; Participant B contributes 4 Points.'], [4, 'Participants of Type A contribute 35 Points; Participant B takes out 4 Points.'], ] ) question_one_correct = models.BooleanField( doc="""Was the players answer on the understanding of private vs group account correct?""", initial=False, ) question_two = models.IntegerField( doc="""This question asks about which the given combinations of transfer decision can explain the group account""", label="", widget=widgets.RadioSelectHorizontal, choices=[ [1, 'Combination 1.'], [2, 'Combination 2.'], [3, 'Combination 3.'], [4, 'Combination 4.'], ] ) question_two_correct = models.BooleanField( doc="""Was the players answer about the given combinations of transfer decision can explain the group account correct?""", initial=False, ) # Recording the randomisation for QUESTION TWO question_two_size = models.IntegerField( doc="""This determines (randomly) the final size of the group account""", min=0, max=50, ) question_two_correct_choice = models.IntegerField( doc="""This determines (randomly) which answer choice will be correct""", min=1, max=4, ) question_two_c1a = models.IntegerField( doc="""This determines (randomly) participant A contribution for choice 1""", min=0, max=40, ) question_two_c1b = models.IntegerField( doc="""This determines (randomly) Participant B contribution for choice 1""", max=10, ) question_two_c2a = models.IntegerField( doc="""This determines (randomly) participant A contribution for choice 2""", min=0, max=40, ) question_two_c2b = models.IntegerField( doc="""This determines (randomly) Participant B contribution for choice 2""", max=10, ) question_two_c3a = models.IntegerField( doc="""This determines (randomly) participant A contribution for choice 3""", min=0, max=40, ) question_two_c3b = models.IntegerField( doc="""This determines (randomly) Participant B contribution for choice 3""", max=10, ) question_two_c4a = models.IntegerField( doc="""This determines (randomly) participant A contribution for choice 4""", min=0, max=40, ) question_two_c4b = models.IntegerField( doc="""This determines (randomly) Participant B contribution for choice 4""", max=10, ) question_three = models.CurrencyField( doc="""This question asks about the number of Points in the group account for a combination of transfers""", label="", min=cu(0), ) question_three_correct = models.BooleanField( doc="""Was the players answer for a given combination of private and group account correct?""", initial=False, ) # Recording the randomisation for QUESTION THREE q3_tot_contr = models.CurrencyField() q3_dic_action = models.CurrencyField() # Variables recording the progression progress_to_game = models.BooleanField(initial=False) quiz_failure = models.BooleanField(initial=False) # ------------------------------------------------------------------------------------------- # # FUNCTIONS # # ------------------------------------------------------------------------------------------- # def question_two_c1b_min(player): return -player.question_two_c1a def question_two_c2b_min(player): return -player.question_two_c2a def question_two_c3b_min(player): return -player.question_two_c3a def question_two_c4b_min(player): return -player.question_two_c4a # FUNCTIONS RELEVANT FOR CREATION AND CHECKING OF QUESTIONS # ----------------------------------------------------------------- # Randomisation of Number for Questions Two and Three: def randomisation_q_two(player: Player): import random player.question_two_size = random.randrange(10, 41) correct_answer = random.randrange(1, 5) player.question_two_correct_choice = correct_answer # correct answer is always shifted down # Randomly choose contribution values contribution = list(range(10, 41)) random.shuffle(contribution) contribution_a = contribution[:4] # Adjust contribution_b based on correct_answer contribution_b = [] for i, c_a in enumerate(contribution_a): if i + 1 == correct_answer: c_b = player.question_two_size - c_a else: valid_range = list(range(-c_a, 11)) if player.question_two_size - c_a in valid_range: valid_range.remove(player.question_two_size - c_a) # to make sure we don't have two correct answers c_b = random.choice(valid_range) contribution_b.append(c_b) player.question_two_c1a, player.question_two_c1b = contribution_a[0], contribution_b[0] player.question_two_c2a, player.question_two_c2b = contribution_a[1], contribution_b[1] player.question_two_c3a, player.question_two_c3b = contribution_a[2], contribution_b[2] player.question_two_c4a, player.question_two_c4b = contribution_a[3], contribution_b[3] def randomisation_q_three(player: Player): contribution = [i for i in range(18, 41)] action = [i for i in range(-18, 11)] import random if player.round_number == 1: player.q3_tot_contr = random.choice(contribution) player.q3_dic_action = random.choice(action) if player.round_number > 1: last_round = player.round_number - 1 previous_contribution = player.in_round(last_round).q3_tot_contr previous_action = player.in_round(last_round).q3_dic_action available_contr = [num for num in contribution if num not in {previous_contribution}] available_action = [num for num in action if num not in {previous_action}] player.q3_tot_contr = random.choice(available_contr) player.q3_dic_action = random.choice(available_action) # Checking that the answers are correct: def check_question_one(player: Player): if player.round_number == 1 and player.question_one == 1: print("Answer to Question 1 is correct") player.question_one_correct = True elif player.round_number == 2 and player.question_one == 2: print("Answer to Question 1 is correct") player.question_one_correct = True elif player.round_number == 3 and player.question_one == 1: print("Answer to Question 1 is correct") player.question_one_correct = True else: print("Answer to Question 1 is incorrect") player.question_one_correct = False def check_question_two(player: Player): if player.question_two == player.question_two_correct_choice: player.question_two_correct = True print("Answer to Question 2 is correct") else: player.question_two_correct = False print("Answer to Question 2 is incorrect") def check_question_three(player: Player): if player.question_three == (player.q3_tot_contr + player.q3_dic_action): print("Answer to Question 3 is correct") player.question_three_correct = True else: print("Answer to Question 3 is incorrect") player.question_three_correct = False # FUNCTIONS RELEVANT DETERMINING PROGRESSION # ----------------------------------------------------------------- def calculating_questions_shown_next_round(player: Player): # if player.round_number < C.NUM_ROUNDS: next_round = player.round_number + 1 questions_shown_next_round = [] if "1" in player.questions_shown: if player.question_one_correct is False: questions_shown_next_round.append("1") if "2" in player.questions_shown: if player.question_two_correct is False: questions_shown_next_round.append("2") if "3" in player.questions_shown: if player.question_three_correct is False: questions_shown_next_round.append("3") string = "" for elem in questions_shown_next_round: string += elem relevant_player = player.in_round(next_round) relevant_player.questions_shown = string # else: # print("The agent is in the final round.") def quiz_success(player: Player): calculating_questions_shown_next_round(player) next_round = player.round_number + 1 relevant_player = player.in_round(next_round) # is this problematic in last round?? if len(relevant_player.questions_shown) == 0: player.progress_to_game = True def quiz_failure(player: Player): if player.round_number == C.NUM_ROUNDS: calculating_questions_shown_next_round(player) next_round = player.round_number + 1 relevant_player = player.in_round(next_round) if len(relevant_player.questions_shown) != 0: player.quiz_failure = True player.participant.progress = 6 # ------------------------------------------------------------------------------------------- # # PAGES # # ------------------------------------------------------------------------------------------- # class Introduction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player, timeout_happened): player.questions_shown = "123" relevant_player = player.in_round(1) randomisation_q_two(relevant_player) randomisation_q_three(relevant_player) class Questions(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.round_number == 1 or player.questions_shown == "123": return ['question_one', 'question_two', 'question_three'] elif player.questions_shown == "12": return ['question_one', 'question_two'] elif player.questions_shown == '13': return ['question_one', 'question_three'] elif player.questions_shown == '23': return ['question_two', 'question_three'] elif player.questions_shown == '1': return ['question_one'] elif player.questions_shown == '2': return ['question_two'] elif player.questions_shown == '3': return ['question_three'] @staticmethod def vars_for_template(player: Player): if player.round_number == 1 or player.questions_shown in ["123", "13", "23", "3"]: return dict( embezzle=cu(abs(int(player.q3_dic_action))) ) @staticmethod def before_next_page(player, timeout_happened): player.participant.progress = 4 if player.round_number == 1 or player.questions_shown in ["123", "12", "13", "1"]: check_question_one(player) if player.round_number == 1 or player.questions_shown in ["123", "12", "23", "2"]: check_question_two(player) if player.round_number == 1 or player.questions_shown in ["123", "13", "23", "3"]: check_question_three(player) calculating_questions_shown_next_round(player) quiz_success(player) quiz_failure(player) class Success(Page): @staticmethod def is_displayed(player: Player): return player.progress_to_game is True @staticmethod def before_next_page(player, timeout_happened): participant = player.participant participant.progress = 5 # Record time in participant field for waitpage on grouping_waitpage app participant.wait_page_arrival = time.time() print(participant.wait_page_arrival) @staticmethod def app_after_this_page(player: Player, upcoming_apps): return upcoming_apps[0] class Explanation(Page): @staticmethod def is_displayed(player: Player): return player.round_number > 1 and player.progress_to_game is not True @staticmethod def vars_for_template(player: Player): last_round = player.in_round(player.round_number - 1) # Recording info on question 1 if player.questions_shown in ["123", "12", "13", "1"]: q1_input = last_round.question_one # Recording info on question 2 if player.questions_shown in ["123", "12", "23", "2"]: q2_size = last_round.question_two_size q2_inputs = [last_round.question_two_c1a, last_round.question_two_c2a, last_round.question_two_c3a, last_round.question_two_c4a] q2_outputs = [last_round.question_two_c1b, last_round.question_two_c2b, last_round.question_two_c3b, last_round.question_two_c4b] q2_answer = last_round.question_two_correct_choice q2_answer_A = q2_inputs[q2_answer - 1] q2_answer_B = q2_outputs[q2_answer - 1] q2_input = last_round.question_two q2_input_A = q2_inputs[q2_input - 1] q2_input_B = q2_outputs[q2_input - 1] # Recording info on question 3 if player.round_number == 1 or player.questions_shown in ["123", "13", "23", "3"]: q3_contr = last_round.q3_tot_contr q3_action = last_round.q3_dic_action q3_input = last_round.question_three print(q3_contr) print(q3_action) # q3_contr = step_q3_contr[0] # q3_action = step_q3_action[0] if player.questions_shown in ['123']: return dict( q1_input=q1_input, q2_size=q2_size, q2_answer=q2_answer, q2_input=q2_input, q2_answer_A=q2_answer_A, q2_answer_B=q2_answer_B, q2_input_A=q2_input_A, q2_input_B=q2_input_B, q3_contr=q3_contr, q3_action=q3_action, embezzle=abs(int(q3_action)), q3_answer=q3_contr + q3_action, q3_input=q3_input, ) elif player.questions_shown in ['12']: return dict( q1_input=q1_input, q2_size=q2_size, q2_answer=q2_answer, q2_input=q2_input, q2_answer_A=q2_answer_A, q2_answer_B=q2_answer_B, q2_input_A=q2_input_A, q2_input_B=q2_input_B, ) elif player.questions_shown in ['13']: return dict( q1_input=q1_input, q3_contr=q3_contr, q3_action=q3_action, embezzle=abs(int(q3_action)), q3_answer=q3_contr + q3_action, q3_input=q3_input, ) elif player.questions_shown in ['23']: return dict( q2_size=q2_size, q2_answer=q2_answer, q2_input=q2_input, q2_answer_A=q2_answer_A, q2_answer_B=q2_answer_B, q2_input_A=q2_input_A, q2_input_B=q2_input_B, q3_contr=q3_contr, q3_action=q3_action, embezzle=abs(int(q3_action)), q3_answer=q3_contr + q3_action, q3_input=q3_input, ) elif player.questions_shown in ['1']: return dict( q1_input=q1_input, ) elif player.questions_shown in ['2']: return dict( q2_size=q2_size, q2_answer=q2_answer, q2_input=q2_input, q2_answer_A=q2_answer_A, q2_answer_B=q2_answer_B, q2_input_A=q2_input_A, q2_input_B=q2_input_B, ) elif player.questions_shown in ['3']: return dict( q3_contr=q3_contr, q3_action=q3_action, embezzle=abs(int(q3_action)), q3_answer=q3_contr + q3_action, q3_input=q3_input, ) @staticmethod def before_next_page(player, timeout_happened): randomisation_q_two(player) randomisation_q_three(player) class Failure(Page): @staticmethod def is_displayed(player): return player.round_number == 4 # ------------------------------------------------------------------------------------------- # # SEQUENCE # # ------------------------------------------------------------------------------------------- # page_sequence = [ Failure, Introduction, Explanation, Questions, Success]