from otree.api import * import re doc = """ Your app description """ # import data (currently doubled for loop to work, a large dat set does not need this) timer_var = 1 def analyticalq(): import csv f = open('_static/verbQ2.csv', encoding='utf-8-sig') rows = list(csv.DictReader(f)) return rows def numericalq(): import csv f = open('_static/numQ2.csv', encoding='utf-8-sig') rows = list(csv.DictReader(f)) return rows def spatialq(): import csv f = open('_static/spaQ2.csv', encoding='utf-8-sig') rows = list(csv.DictReader(f)) return rows # define constants, the csv with the questions and setting for the task: rounds roles ppl per group etc class C(BaseConstants): NAME_IN_URL = 'Ind_Prolific' ## FIRST indidvual task round M1Q1 = numericalq() M2Q1 = analyticalq() M3Q1 = spatialq() ## the fails containing all the questions lenM1 = len(M1Q1) lenM2 = len(M2Q1) lenM3 = len(M3Q1) ## the length of the fails containing all the questions NUM_ROUNDS = 80 PLAYERS_PER_GROUP = None TIMER_TEXT = "Time to complete questions:" class Subsession(BaseSubsession): pass class Group(BaseGroup): pass # not needed class Player(BasePlayer): # input ID & CID EM = models.StringField(label="Input your Email") EM_2 = models.StringField(label="Confirm your Email") CID = models.IntegerField(label="Input your Computer ID") CID_2 = models.IntegerField(label="Confirm your Computer ID") ID1 = models.StringField(label="Please verify your participant ID below") IDP = models.StringField(label="Please input your Prolific ID number below") IDP_2 = models.StringField(label="Please confirm your Prolific ID number below") ran = models.IntegerField(label="Input the code given by the instructor:") # individual and group task var. _a = analytical, _s = spatial and _n =numerical question_a = models.StringField() solution_a = models.StringField() question_n = models.StringField() solution_n = models.StringField() graphics_name = models.CharField() solution_s = models.StringField() key_s = models.StringField() # analytical and numerical chocies field , empty, defined futher down choicea1_1 = models.StringField(widget=widgets.RadioSelect, label='', blank=True) choicen1 = models.StringField(widget=widgets.RadioSelect, label='', blank=True) # variable to count if answer is correct is_correct = models.BooleanField() # spatial choice field spa_1 = models.StringField( widget=widgets.RadioSelectHorizontal, choices=['A', 'B', 'C', 'D', 'E'], label='', blank=True) spa_2 = models.StringField( widget=widgets.RadioSelectHorizontal, choices=['A', 'B', 'C', 'D'], label='', blank=True) # count q_ID in mods last_click = models.IntegerField() # check attention question q1 = models.IntegerField(label='What will be the team score?') ## chocie field def choicen1_choices(player: Player): current_question1 = current_m1(player) return [ ['A', current_question1['optionA']], ['B', current_question1['optionB']], ['C', current_question1['optionC']], ['D', current_question1['optionD']], ['E', current_question1['optionE']], ] def choicea1_1_choices(player: Player): current_question2 = current_m2(player) return [ ['A', current_question2['optionA']], ['B', current_question2['optionB']], ['C', current_question2['optionC']], ['D', current_question2['optionD']], ['E', current_question2['optionE']], ] #subsession creation: this app as 3, this is the first, anything defined here will remian in all following sessions def creating_session(subsession: Subsession): import random test = subsession.session.config['testing'] for p in subsession.get_players(): if test: p.participant.EM = "test" p.participant.EM_2 = "test" p.participant.CID_2 = 0 with open('_rooms/labels2.txt') as f: labels = f.read().splitlines() for p, label in zip(subsession.get_players(), labels): p.participant.label = label p.participant.ID_label = label p.participant.P_label = label p.participant.CID = label p.participant.correct_n = 0 p.participant.correct_a = 0 p.participant.correct_s = 0 p.participant.correct_n_all = 0 p.participant.correct_a_all = 0 p.participant.correct_s_all = 0 p.participant.m1_current_q_ID = 0 p.participant.m2_current_q_ID = 0 p.participant.m3_current_q_ID = 0 p.participant.pre_score1 = 0 p.participant.pre_score2 = 0 p.participant.pre_score3 = 0 p.participant.score = 0 p.participant.questions_mod1 = True p.participant.questions_mod2 = False p.participant.questions_mod3 = False p.participant.time_out = False p.participant.intro2 = False p.participant.intro3 = False p.participant.p_m1_page2 = 0 p.participant.p_m2_page2 = 0 p.participant.p_m3_page2 = 0 p.participant.timer = int(subsession.session.config['timer']) def current_m1(player: Player): ID1 = player.participant.m1_current_q_ID return C.M1Q1[ID1] def current_m2(player: Player): ID2 = player.participant.m2_current_q_ID return C.M2Q1[ID2] def current_m3(player: Player): ID3 = player.participant.m3_current_q_ID return C.M3Q1[ID3] class count_answers(ExtraModel): player = models.Link(Player) module = models.StringField() number_answered = models.IntegerField() def vars_for_template1(player: Player): qd1 = current_m1(player) player.question_n = qd1['question'] player.solution_n = qd1['solution'] qd2 = current_m2(player) player.question_a = qd2['question'] player.solution_a = qd2['solution'] qd3 = current_m3(player) player.graphics_name = qd3['graphic_name'] graphics_name = player.graphics_name print("Graphics Name", graphics_name) player.solution_s = qd3['solution'] print("Graph sol", player.solution_s) return dict( image_path='{}.jpg'.format(graphics_name), question_a=player.question_a, question_n=player.question_n ) # timer def get_timeout_seconds1(player: Player): participant = player.participant import time return participant.expiry - time.time() def get_timeout_seconds12(player: Player): participant = player.participant import time return participant.expiry2 - time.time() def get_timeout_seconds13(player: Player): participant = player.participant import time return participant.expiry3 - time.time() # timer for group task + more group task var # PAGES class ID_input(Page): form_model = 'player' form_fields = ['ID1'] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.ID_label = str(player.ID1) @staticmethod def error_message(player: Player, values): print('t', player.participant.label) try: label = player.participant.label ID_true = values['ID1'] == label except TypeError: ID_true = True if player.participant.label is None: ID_true = True if not ID_true: return "Your input does not match the ID label, please enter again" class IDProlific_input(Page): form_model = 'player' form_fields = ['IDP', 'IDP_2'] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.P_label = str(player.IDP) @staticmethod def error_message(player: Player, values): print('no', values) if values['IDP'] != values['IDP_2']: return "Your inputs does not match, please enter again" class EM_input(Page): form_model = 'player' form_fields = ['EM', 'EM_2'] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.EM = player.EM class CID_input(Page): form_model = 'player' form_fields = ['CID', 'CID_2'] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.CID = player.CID @staticmethod def error_message(player: Player, values): print('no', values) if values['CID'] != values['CID_2']: return "Your inputs does not match, please enter again" class WaitPage_ind(WaitPage): wait_for_all_groups = True body_text = "Waiting for all players to arrive" @staticmethod def is_displayed(player): return player.round_number == 1 class Ind_Instruction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Ind_Instruction1(Page): form_model = "player" @staticmethod def is_displayed(player): return player.round_number == 1 class Ind_b1(Page): form_model = "player" @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant import time sec = participant.timer participant.expiry = time.time() + (int(sec)/2) * 80 player.participant.p_m1_page = time.time() class Ind_module1(Page): form_model = 'player' form_fields = ['choicen1'] get_timeout_seconds = get_timeout_seconds1 timer_text = C.TIMER_TEXT vars_for_template = vars_for_template1 @staticmethod def is_displayed(player): return get_timeout_seconds1(player) > 0 and player.participant.questions_mod1 @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant if timeout_happened: print('timeout', timeout_happened) player.participant.questions_mod1 = False player.participant.questions_mod2 = True player.participant.intro2 = True mod = 'mod1' num = player.participant.m1_current_q_ID count_answers.create(player=player, module=str(mod), number_answered=int(num)) try: is_correct = player.choicen1 == player.solution_n except TypeError: is_correct = None if is_correct is not None: if is_correct: player.participant.correct_n += 1 player.participant.correct_n_all += 1 print('is correct', player.participant.correct_n) print('is correct all', participant.correct_n_all) if not is_correct: participant.correct_n += -0.5 import time player.participant.p_m1_page2 += time.time() - player.participant.p_m1_page player.participant.p_m1_page = time.time() player.participant.m1_current_q_ID += 1 print('m1 qID', player.participant.m1_current_q_ID) print('point', player.participant.correct_n) @staticmethod def error_message(player: Player, values): if values['choicen1'] is None: return "Select an answer" class Ind_Instruction2(Page): form_model = "player" @staticmethod def is_displayed(player): return player.participant.questions_mod2 and player.participant.intro2 class Ind_b2(Page): form_model = "player" @staticmethod def is_displayed(player): responses = count_answers.filter(player=player, module='mod1') print("responses:", responses) return player.participant.questions_mod2 and player.participant.intro2 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.intro2 = False participant = player.participant import time sec = participant.timer participant.expiry2 = time.time() + (int(sec) / 2) * 80 player.participant.p_m2_page = time.time() class Ind_module2(Page): form_model = 'player' form_fields = ['choicea1_1'] get_timeout_seconds = get_timeout_seconds12 timer_text = C.TIMER_TEXT vars_for_template = vars_for_template1 @staticmethod def is_displayed(player): return player.participant.questions_mod2 and get_timeout_seconds12(player) > 0 @staticmethod def before_next_page(player: Player, timeout_happened): ## try except is used to avoid type error when field is none participant = player.participant if timeout_happened: print('timeout', timeout_happened) player.participant.questions_mod2 = False player.participant.questions_mod3 = True player.participant.intro3 = True mod = 'mod2' num = player.participant.m2_current_q_ID count_answers.create(player=player, module=str(mod), number_answered=int(num)) try: is_correct = player.choicea1_1 == player.solution_a except TypeError: is_correct = None if is_correct is not None: player.is_correct = player.choicea1_1 == player.solution_a participant.correct_a += int(player.is_correct) participant.correct_a_all += int(player.is_correct) print('is correct', player.is_correct) print('answer', player.solution_a) print('choice', player.choicea1_1) if not player.is_correct: participant.correct_a += -0.5 import time player.participant.p_m2_page2 += time.time() - player.participant.p_m2_page player.participant.p_m2_page = time.time() player.participant.m2_current_q_ID += 1 print('m2 qID', player.participant.m2_current_q_ID) @staticmethod def error_message(player: Player, values): print('no', values) if values['choicea1_1'] is None: return "Select an answer" class Ind_Instruction3(Page): form_model = "player" @staticmethod def is_displayed(player): return player.participant.questions_mod3 and player.participant.intro3 class Ind_b3(Page): form_model = "player" @staticmethod def is_displayed(player): return player.participant.questions_mod3 and player.participant.intro3 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.intro3 = False participant = player.participant import time sec = participant.timer participant.expiry3 = time.time() + (int(sec) / 2) * 80 player.participant.p_m3_page = time.time() class Ind_module3(Page): form_model = 'player' get_timeout_seconds = get_timeout_seconds13 timer_text = C.TIMER_TEXT vars_for_template = vars_for_template1 @staticmethod def is_displayed(player): return player.participant.questions_mod3 and get_timeout_seconds13(player) > 0 @staticmethod def get_form_fields(player): qd3 = current_m3(player) player.key_s = qd3['key'] if player.key_s == '5': return ['spa_1'] else: return ['spa_2'] @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant if timeout_happened: player.participant.questions_mod3 = False player.participant.time_out = True mod = 'mod3' num = player.participant.m3_current_q_ID count_answers.create(player=player, module=str(mod), number_answered=int(num)) if player.key_s == '5': try: is_correct = player.spa_1 == player.solution_s except TypeError: is_correct = None else: try: is_correct = player.spa_2 == player.solution_s except TypeError: is_correct = None if is_correct is not None: if is_correct: participant.correct_s += 1 participant.correct_s_all += 1 print('is correct', participant.correct_s) print('is correct all', participant.correct_s_all) if not is_correct: participant.correct_s += -0.5 import time player.participant.p_m3_page2 += time.time() - player.participant.p_m3_page player.participant.p_m3_page = time.time() player.participant.m3_current_q_ID += 1 print('m3 qID', player.participant.m3_current_q_ID) @staticmethod def error_message(player: Player, values): print('no', values) if player.key_s == '5' and values['spa_1'] is None: return "Select an answer" elif player.key_s == '4' and values['spa_2'] is None: return "select an answer" class Ind_Results(Page): @staticmethod def is_displayed(player: Player): return player.participant.time_out and player.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player: Player): participant = player.participant participant.pre_score1 = round(participant.correct_n, 2) participant.pre_score2 = round(participant.correct_a, 2) participant.pre_score3 = round(participant.correct_s, 2) participant.score = (participant.pre_score1 + participant.pre_score2 + participant.pre_score3)/3 print("score per minute", participant.pre_score1) print("score total", participant.score) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.time_out = False def custom_export(players): """For data export page""" yield ['Prolific_ID', 'id_in_session', 'round_number', 'score_mod1', 'score_mod2', 'score_mod3', 'score_avg', 'number_answered', 'module','correctN', 'correctA', 'correctS'] responses = count_answers.filter() for resp in responses: player = resp.player participant = player.participant yield [player.participant.P_label, participant.id_in_session, player.round_number, participant.pre_score1, participant.pre_score2, participant.pre_score3, participant.score, resp.number_answered, resp.module, participant.correct_n_all,participant.correct_a_all,participant.correct_s_all ] page_sequence = [IDProlific_input, Ind_Instruction, Ind_Instruction1, Ind_b1, Ind_module1, Ind_Instruction2, Ind_b2, Ind_module2, Ind_Instruction3, Ind_b3, Ind_module3, Ind_Results] # page_sequence = [ID_input, CID_input, WaitPage_ind, Ind_module1, Ind_module2, Ind_module3, Ind_Results]