from otree.api import * import random import itertools doc = """ Part I: Players are assigned to groups and introduced to each other via a group quiz meant to improve group identification. Groups Play 8 rounds of Task I Group A plays Task II for IR, Group B waits for OE """ class C(BaseConstants): NAME_IN_URL = 'PartI' PLAYERS_PER_GROUP = None NUM_ROUNDS = 8 participation_fee = 10 class Subsession(BaseSubsession): pass class Group(BaseGroup): ques = models.StringField( label=''' Here are your choices: ''', widget=widgets.RadioSelectHorizontal, choices=['Option A', 'Option B', 'Option C', 'Option D'], blank=True, ) ans_submitted = models.BooleanField(initial=False) pass class Player(BasePlayer): name = models.LongStringField() assigned_group = models.LongStringField() answerer = models.IntegerField() part1_code = models.StringField(label='') rank1 = models.IntegerField(label="Your first nomination for the Top 2:") rank2 = models.IntegerField(label="Your second nomination for the Top 2:") part2_code = models.StringField(label='') def rank1_choices(player): choices = [] for others in player.get_others_in_group(): choices.append([int(others.id_in_group), str(others.name)]) random.shuffle(choices) return choices def rank2_choices(player): choices = [] for others in player.get_others_in_group(): choices.append([int(others.id_in_group), str(others.name)]) random.shuffle(choices) return choices def creating_session(subsession): if subsession.round_number == 1: subsession.session.seed_value = random.randint(1,15) group_names = itertools.cycle(['A_treat', 'A_cont','B_treat', 'B_cont']) #A_names = itertools.cycle(['Amsterdam', 'Abu Dhabi', 'Adelaide', 'Austin', 'Antwerp', 'Alexandria', 'Athens', 'Atlanta']) #B_names = itertools.cycle(['Barcelona', 'Berlin', 'Boston', 'Budapest', 'Bali', 'Beijing', 'Buenos Aires', 'Bangkok']) A_namesT = itertools.cycle(['Amsterdam', 'Adelaide', 'Austin', 'Athens']) B_namesT = itertools.cycle(['Barcelona', 'Berlin', 'Boston', 'Bali']) A_namesC = itertools.cycle(['Amsterdam', 'Adelaide', 'Austin', 'Athens']) B_namesC = itertools.cycle(['Barcelona', 'Berlin', 'Boston', 'Bali']) for player in subsession.get_players(): participant = player.participant participant.group_name = next(group_names) player.assigned_group = player.participant.group_name if participant.group_name in ['A_treat', 'B_treat']: participant.in_treatment = True else: participant.in_treatment = False if player.participant.group_name in ['A_treat', 'A_cont']: participant.in_GroupA = True if player.participant.group_name == "A_treat": participant.participant_name = next(A_namesT) else: participant.participant_name = next(A_namesC) else: participant.in_GroupA = False if player.participant.group_name == "B_treat": participant.participant_name = next(B_namesT) else: participant.participant_name = next(B_namesC) player.name = player.participant.participant_name player.participant.high_rep = 0 # Group Assigning Code rowAT = [] rowBT = [] rowAC = [] rowBC = [] for player in subsession.get_players(): if player.participant.group_name == 'A_treat': rowAT.append(player.id_in_subsession) elif player.participant.group_name == 'B_treat': rowBT.append(player.id_in_subsession) elif player.participant.group_name == 'A_cont': rowAC.append(player.id_in_subsession) elif player.participant.group_name == 'B_cont': rowBC.append(player.id_in_subsession) subsession.set_group_matrix([rowAT, rowBT, rowAC, rowBC]) # Defining ingroup and outgroups for player in subsession.get_players(): player.participant.in_group = [] player.participant.out_group = [] for other_player in subsession.get_players(): if other_player.participant.in_treatment == player.participant.in_treatment: if other_player.participant.in_GroupA == player.participant.in_GroupA: player.participant.in_group.append(other_player.participant.participant_name) else: player.participant.out_group.append(other_player.participant.participant_name) player.participant.quiz_score = 0 # PAGES class Welcome(Page): @staticmethod def is_displayed(player): return player.round_number == 1 pass class Group_Assignment(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Subject_Intro(Page): form_model = 'player' form_fields = ['part1_code'] @staticmethod def is_displayed(player): return player.round_number == 1 def error_message(player, values): if values['part1_code'] != 'K3PA': return 'Please enter a valid passcode.' def vars_for_template(player: Player): if player.participant.in_GroupA: GroupAList = player.participant.in_group GroupBList = player.participant.out_group else: GroupAList = player.participant.out_group GroupBList = player.participant.in_group for k in range(len(GroupAList), 4): GroupAList.append(' ') for k in range(len(GroupBList), 4): GroupBList.append(' ') Aname1 = GroupAList[0] Aname2 = GroupAList[1] Aname3 = GroupAList[2] Aname4 = GroupAList[3] Bname1 = GroupBList[0] Bname2 = GroupBList[1] Bname3 = GroupBList[2] Bname4 = GroupBList[3] return dict( Aname1 = Aname1, Aname2 = Aname2, Aname3 = Aname3, Aname4 = Aname4, Bname1 = Bname1, Bname2 = Bname2, Bname3 = Bname3, Bname4 = Bname4, ) pass class Part1_Instructions(Page): @staticmethod def is_displayed(player): return player.round_number == 1 def before_next_page(player, timeout_happened): for k in range(1,9): max_per_group = len(player.group.get_players()) random.seed(k + player.group.id_in_subsession) random_id = random.randint(1, max_per_group) if player.id_in_group == random_id: player.in_round(k).answerer = 1 else: player.in_round(k).answerer = 0 class Task1(Page): form_model = 'group' form_fields = ['ques'] @staticmethod def vars_for_template(player: Player): question_bank = ['Find the missing term for the series: BXM, EUP, HRS, ?', 'A Pen is to a Poet, as a Needle is to', 'J,P,R,X and Z are sitting in a row. Z is in the center. J and P are at the ends. R is sitting to the left of J. Who is to the right of Z?', 'In a class of 30 students, Zach’s rank from the top is 12th. Nicole is 8 ranks below Zach. What is Nicole’s rank from the bottom?', 'Identify the odd one out: Inch, Kilometer, Yard, Kilogram, Mile', 'A is the father of B. B is the only son of C. If C is the mother of D, then how is D related to B?', 'If it takes 5 men 5 minutes to change 5 bulbs, how long would it take 10 men to change 10 bulbs?', 'Which of the following is a scrambled version of the word MIGRATION' ] choice_bank = [['XZY','RPN','VTU','KOV'], ['Sewing', 'Tailor', 'Thread', 'Poem'], ['X', 'R', 'P', 'J'], ['11th', '10th', '20th', '21st'], ['Yard', 'Inch', 'Kilogram', 'Mile'], ['Wife', 'Sister', 'Husband', 'Brother'], ['10 minutes', '15 minutes', '5 minutes', '50 minutes'], ['MRITGOAIN', 'NGOITRMA', 'GMRANTION', 'TGMARNIO'], ] question_text = question_bank[player.round_number -1] OptionA = choice_bank[player.round_number -1][0] OptionB = choice_bank[player.round_number - 1][1] OptionC = choice_bank[player.round_number - 1][2] OptionD = choice_bank[player.round_number - 1][3] return dict( question_text = question_text, OptionA = OptionA, OptionB=OptionB, OptionC=OptionC, OptionD=OptionD, ) @staticmethod def error_message(player, values): if player.answerer == 1: if values['ques'] == None: return 'You are designated to submit the answer for this round. Please select an answer. Your group-mates will not be available to chat until you submit an answer.' @staticmethod def live_method(player: Player, data): if player.group.ans_submitted: return if data.get('submitted'): player.group.ans_submitted = True return {0:dict(finished=True)} #@staticmethod #def before_next_page(player, timeout_happened): # if player.answerer == 1: # player.group.ans_submitted = True class Quiz_WaitPage(WaitPage): @staticmethod def after_all_players_arrive(group: Group): for p in group.get_players(): answer_key = ['Option D', 'Option B', 'Option B', 'Option A', 'Option C', 'Option B', 'Option C', 'Option A'] if p.group.ques == answer_key[p.round_number-1]: p.participant.quiz_score += 1 class Task2_GroupA(Page): @staticmethod def is_displayed(player): return player.participant.in_GroupA == True and player.round_number == 8 pass class Task2_GroupA_Ranking(Page): form_model = 'player' @staticmethod def is_displayed(player): return player.participant.in_GroupA == True and player.round_number == 8 @staticmethod def get_form_fields(player): if player.participant.in_GroupA == True: return ['rank1', 'rank2'] else: return [] @staticmethod def error_message(player, values): if values['rank1'] == values['rank2']: return 'You cannot nominate the same person twice.' pass class Task2_WaitPage(WaitPage): @staticmethod def is_displayed(player): return player.participant.in_GroupA == True and player.round_number == 8 @staticmethod def after_all_players_arrive(group: Group): votes = [0]*len(group.get_players()) for p in group.get_players(): votes[p.rank1 - 1] = votes[p.rank1 - 1 ]+ 1 votes[p.rank2 - 1] = votes[p.rank2 - 1] + 1 top1 = [index + 1 for index, freq in enumerate(votes) if freq == max(votes)] if len(top1) > 1: random.seed(group.subsession.session.seed_value) top_ids = random.sample(top1,2) else: top2 = [index + 1 for index, freq in enumerate(votes) if freq in sorted(votes, reverse=True)[1:2]] random.seed(group.subsession.session.seed_value) top_ids = top1 + random.sample(top2,1) for p in group.get_players(): if p.id_in_group in top_ids: p.participant.high_rep = 1 class Task2_GroupA_Results(Page): form_model = 'player' form_fields = ['part2_code'] @staticmethod def is_displayed(player): return player.participant.in_GroupA == True and player.round_number == 8 @staticmethod def error_message(player, values): if values['part2_code'] != 'AGT2': return 'Please enter a valid passcode.' class Task2_GroupB(Page): form_model = 'player' form_fields = ['part2_code'] @staticmethod def is_displayed(player): return player.participant.in_GroupA == False and player.round_number == 8 @staticmethod def error_message(player, values): if values['part2_code'] != 'AGT2': return 'Please enter a valid passcode.' pass page_sequence = [Welcome, Group_Assignment, Subject_Intro, Part1_Instructions, Task1, Quiz_WaitPage, Task2_GroupA, Task2_GroupA_Ranking, Task2_WaitPage, Task2_GroupA_Results, Task2_GroupB ]