from otree.api import * '''( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, )''' import random author = 'Xiao Hanyu' doc = """ Instruction and quizzes for Endogenous College Ranking """ class Constants(BaseConstants): name_in_url = 'clock_auction_and_jump_bidding_instruction' players_per_group = None num_rounds = 4 Roles = ['S', 'TR', 'FR'] pract_rounds = 3 class Subsession(BaseSubsession): typeO_prob = models.FloatField(initial=0.2) conflict = models.IntegerField(initial=6) num_FR = models.IntegerField(initial=1) local_seed = models.IntegerField(initial=-1) sender_Mistake = models.FloatField(initial=0) def creating_session(self): self.typeO_prob = self.session.config['typeO_prob'] self.conflict = self.session.config['conflict'] self.num_FR = self.session.config['num_FR'] self.sender_Mistake = self.session.config['SM_numerator'] / self.session.config['SM_denominator'] self.local_seed = random.randint(0, 999) # to check whether (num_participants - num_FR) is even or not players = self.get_players() if (len(players) - self.num_FR) % 2 != 0: print("The remaining subjects can not be partitioned into pairs," "numeber of false R is decreased by one") self.num_FR = self.num_FR - 1 if self.round_number < Constants.num_rounds: # local_random = random.Random(self.local_seed) local_random = random.Random(99) local_random.shuffle(players) num_pairs = int((len(players) - self.num_FR) / 2) to_shuffle = players[:self.num_FR] + players[self.num_FR + num_pairs:] random.Random(self.local_seed + self.round_number).shuffle(to_shuffle) players = to_shuffle[:self.num_FR] + players[self.num_FR:self.num_FR + num_pairs] + to_shuffle[self.num_FR:] # The first num_FR players and last num_pairs players are shuffled btw roles of TR and FR for index in range(0, len(players)): if index < self.num_FR: # for the first num_FR players, they are assigned FR players[index].roles = Constants.Roles[2] players[index].pseudo_group = index + 1 local_random = random.Random(self.local_seed + players[index].pseudo_group) draw = local_random.random() if draw <= self.typeO_prob: players[index].type = 0 else: players[index].type = 1 else: # The rest (n-num_FR) players are assigned S or TR if index < self.num_FR + num_pairs: # for those whose index is btw num_FR and (num_FR + # num_pairs), they are assigned S players[index].roles = Constants.Roles[0] players[index].pseudo_group = index + 1 local_random = random.Random(self.local_seed + players[index].pseudo_group) draw = local_random.random() if draw <= self.typeO_prob: players[index].type = 0 else: players[index].type = 1 else: # for the remaining, they are assigned to be TR, and is paired with one whose index is theirs - num_pairs players[index].roles = Constants.Roles[1] players[index].pseudo_group = index - num_pairs + 1 players[index].type = players[index - num_pairs].type else: for player in players: player.roles = Constants.Roles[1] local_random = random.Random(self.local_seed + player.id_in_group) draw = local_random.random() if draw <= self.typeO_prob: player.type = 0 else: player.type = 1 class Group(BaseGroup): pass class Player(BasePlayer): roles = models.StringField() type = models.IntegerField(initial=-1, min=0, max=1) message_sent = models.IntegerField(initial=-1) action = models.IntegerField(initial=-1, min=0, max=10) message_received = models.IntegerField(initial=-1, min=0, max=1) pseudo_group = models.IntegerField() cutOff = models.IntegerField(initial = 0) def live_instruct(self, data): if data['read'] == 1: if self.read == -1: self.read = 1 return {self.id_in_group: {'read': self.read}} read = models.IntegerField(initial=-1) q1 = models.IntegerField(choices=[ [1, "I will have a chance to play the role of students later."], [2, 'Other participants are randomly assigned in each round to play the role of College ○.'], [3, 'In each round, I will be randomly assigned to play the role of College ∆ and the role of College ○.'], [4, 'My role is fixed throughout the entire experiment and thus I will only play the role of College ∆.'] #[5, #'When I see that my money prize value is 63 in Round 1, it implies that my money ' + #'prize value in all other rounds will be exactly 63.' #] ], widget=widgets.RadioSelect, label='Suppose that at the beginning of Round 1,' ' you are assigned to play the role of College ∆. Which of the following statements is true?') q2 = models.IntegerField(choices=[ [1, 'In the next round, the admission cutoff is automatically set to be 65.'], [2, 'In the next round, you are allowed to choose a new admission cutoff strictly larger than 65.'], [3, 'In the next round, you are allowed to choose a new admission cutoff strictly smaller than 65.'], [4, 'In the next round, you are allowed to choose a new admission cutoff, any value between 0 and 100.'] ], widget=widgets.RadioSelect, label='Suppose that you are assigned to play the role of College ○. In a round' ', the admission cutoff you chose is 65. Which of the following statements is true?') q3 = models.IntegerField(choices=[ [1, 'In the next round, your exam score will be exactly 85 and you are not allowed to apply to College ○.' ], [2, 'In the next round, your exam score will be independent of the exam score in the current round and you are not allowed to apply to College ○.'], [3, 'In the next round, your exam score will be independent of the exam score in the current round and you are allowed to apply to any college you want.'] #[4, '-15 tokens'] ], widget=widgets.RadioSelect, label='Suppose that you are assigned to play the role of a student. In a round, your exam score is 85 and you decide to apply to College ∆' '. Which of the following statements is true?') q4 = models.IntegerField(choices=[ [1, '70×(81+96+57)/3'], [2, '70×(70+81+96+57)/3 '], [3, '70×(70+81+96+57)/4'], [4, '70×(70+81+96+57)/(4×50)'] ], widget=widgets.RadioSelect, label='Suppose that you applied to one of the colleges and there are four students including yourself who are admitted by the college. Your exam' ' score is 70 and the exam scores of the other three students are 81, 96, and 57. What is your earning?') q5 = models.IntegerField(choices=[ [1, '450/5'], [2, '(450 + 61)/5 '], [3, '(450 + 61×2)/5'], [4, '(450 + 77×2)/5'] ], widget=widgets.RadioSelect, label='Suppose that you are College ○. The average exam score of students admitted by you is 61, and the sum of their earnings is 450' '. It turns out that the average exam score of students admitted by College ∆ is 77. What is your earning?') def set_error_message(self, value): if self.subsession.num_FR > 0: correct_answers = {"q1": 4, "q2": 4, "q3": 3, "q4": 4, "q5":1 } else: if self.subsession.sender_Mistake == 0: correct_answers = {"q1": 4, "q2": 4, "q3": 3, "q4": 4, "q5":1 } else: correct_answers = {"q1": 4, "q2": 4, "q3": 3, "q4": 4, "q5":1 } list_answers = list(value.items())[0:] list_correct_answers = list(correct_answers.items()) if list_answers != list_correct_answers: Text = 'Some of your answers are incorrect. It indicates that your understanding may not be fully accurate. ' \ 'Please try it again. You can always go back to the experimental instructions if you find anything unclear.' return Text