from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import csv import random from django import forms from django.core.validators import MinLengthValidator from django.core.validators import RegexValidator from django.utils.safestring import mark_safe author = 'Alexander Coutts, Boon Han Koh, Zahra Murad' doc = """ Feedback/Gender Experiment: Workers Part 2 (Feedback and Competition Choice) """ class Constants(BaseConstants): name_in_url = 'fg_w_2_feedback' players_per_group = None num_rounds = 1 # Time limit for IQ task time_limit = 4 # Tournament rate tournament_rate = 0.2 # Piece rate piece_rate = 0.05 # Payment for beliefs belief_payment = 0.20 # Payment for belief about manager's signal type belief_signal_payment = 0.20 # Import manager.csv file here with open('data/manager_mock_compfirst_200816-formatted.csv', encoding='utf-8') as managerfilecompfirst: managerlistcompfirst = list(csv.DictReader(managerfilecompfirst)) with open('data/manager_mock_compsecond_200816-formatted.csv', encoding='utf-8') as managerfilecompsecond: managerlistcompsecond = list(csv.DictReader(managerfilecompsecond)) class Subsession(BaseSubsession): def creating_session(self): # extract treatments and matched worker for player in self.get_players(): player.treatcompfirst = self.session.config['treatcompfirst'] print('treatment compfirst:', player.treatcompfirst) # extract managers data based on treatment if player.treatcompfirst: self.session.vars['managerlist'] = Constants.managerlistcompfirst.copy() else: self.session.vars['managerlist'] = Constants.managerlistcompsecond.copy() ## control questions # question 1 # correct answer is 1 choices_q1 = [ [1, "IQ Task"], [2, "Picture Recall Task"], [3, "Anagram Task"], [4, "Number Multiplication Task"], [5, "Number Finding Task"], ] # question 2 # correct answer is 3 choices_q2 = [ [1, "Add a series of 2-digit numbers."], [2, "Count the number of lines in a pattern."], [3, "Select one element that best complete a pattern."], [4, "Solve anagrams with numbers."], ] # question 3 version 1 (to be used in Part 1) # correct answer is 1 # choices_q3 = [ # [1, 'True'], # [2, 'False'], # ] # question 3 version 2 (to be used in Part 2) # correct answer is 2 choices_q3 = [ [1, mark_safe("I will earn £" + "{:.2f}".format(Constants.tournament_rate) + " for each correct answer regardless of my performance.")], [2, mark_safe( "I will earn £" + "{:.2f}".format(Constants.tournament_rate) + " for each correct answer only if I am ranked in quartile 1 (scoring in the top 5 out of 20 participants), and £0 otherwise.")], [3, mark_safe( "I will earn £" + "{:.2f}".format(Constants.tournament_rate) + " for each correct answer only if I am ranked in quartile 1 or 2 (scoring in the top 10 out of 20 participants), and £0 otherwise.")], ] # randomize order of questions for each player for p in self.get_players(): choices_q1_shuffled = choices_q1.copy() choices_q2_shuffled = choices_q2.copy() choices_q3_shuffled = choices_q3.copy() random.shuffle(choices_q1_shuffled) random.shuffle(choices_q2_shuffled) random.shuffle(choices_q3_shuffled) p.participant.vars['choices_q1_shuffled'] = choices_q1_shuffled p.participant.vars['choices_q2_shuffled'] = choices_q2_shuffled p.participant.vars['choices_q3_shuffled'] = choices_q3_shuffled class Group(BaseGroup): pass class Player(BasePlayer): prolificID = models.StringField( label="Paste your Prolific ID here:", max_length=24, validators=[RegexValidator(regex='^.{24}$', message='Your Prolific ID must contain exactly 24 characters.', code='nomatch')], ) # treatment variable (determined at session level but should be the same as the one managers faced) treatcompfirst = models.BooleanField() # variable as checker for whether ID matches matchedID = models.BooleanField(initial=False) # create variables for manager's decisions managerID = models.StringField() managercompfirst = models.BooleanField() workerrank = models.IntegerField() workertophalf = models.BooleanField() managersignaltype = models.IntegerField() managerfeedbacktype = models.IntegerField() managerfeedbackprecise = models.BooleanField(initial=False) managerfeedbackvague = models.BooleanField(initial=False) managerfeedbacknone = models.BooleanField(initial=False) ## create varaibles for worker's decisions # competition decisions compchoice1 = models.BooleanField() compchoice2 = models.BooleanField() # posterior beliefs posterior1 = models.IntegerField() posterior2 = models.IntegerField() posterior3 = models.IntegerField() posterior4 = models.IntegerField() # belief about manager's signal type (3=Precise,2=Vague,1=None) beliefsignaltype = models.IntegerField( widget=widgets.RadioSelect, label="I believe my Manager was told:", choices=[ [3, 'of my exact Part 1 quartile rank.'], [2, 'whether my Part 1 quartile rank was in the top half or bottom half.'], [1, 'that my Part 1 quartile rank was between 1 and 4.'], ] ) # extract manager's decisions def extractmanager(self): for x in self.session.vars['managerlist']: if self.prolificID in x["fg_m_feedback.1.player.workerID"]: self.matchedID = True if self.matchedID: manager_data = [x for x in self.session.vars['managerlist'] if x["fg_m_feedback.1.player.workerID"] == self.prolificID] # manager's prolific ID self.managerID = manager_data[0]['fg_all_intro.1.player.prolificID'] # treatment compfirst versus compsecond if int(manager_data[0]['fg_m_feedback.1.player.treatcompfirst']) == 1: self.managercompfirst = True elif int(manager_data[0]['fg_m_feedback.1.player.treatcompfirst']) == 0: self.managercompfirst = False # worker's part 1 rank self.workerrank = int(manager_data[0]['fg_m_feedback.1.player.workerrank']) # whether worker is in the top half if int(manager_data[0]['fg_m_feedback.1.player.workertophalf']) == 1: self.workertophalf = True elif int(manager_data[0]['fg_m_feedback.1.player.workertophalf']) == 0: self.workertophalf = False # manager's signal type (3=Precise,2=Vague,1=None) self.managersignaltype = int(manager_data[0]['fg_m_feedback.1.player.signaltype']) # manager's feedback type (3=Precise,2=Vague,1=None) self.managerfeedbacktype = int(manager_data[0]['fg_m_feedback.1.player.feedbacktype']) # convert feedback type into boolean fields if self.managerfeedbacktype == 1: self.managerfeedbacknone = True if self.managerfeedbacktype == 2: self.managerfeedbackvague = True if self.managerfeedbacktype == 3: self.managerfeedbackprecise = True # control questions ctrl_errors_part1_count = models.IntegerField( initial=0 ) # question 1 # correct answer is 1 part1ctrl1 = models.StringField( label="What task did you complete in Part 1?", widget=widgets.RadioSelect, ) def part1ctrl1_choices(self): choices = self.participant.vars['choices_q1_shuffled'] return choices # question 2 # correct answer is 3 part1ctrl2 = models.StringField( label="What did you have to do in the task to get the correct answer?", widget=widgets.RadioSelect, ) def part1ctrl2_choices(self): choices = self.participant.vars['choices_q2_shuffled'] return choices # question 3 version 1 (to be used in Part 1) # correct answer is 1 # part1ctrl3 = models.StringField( # label="Your bonus payment in Part 1 is expected to be higher the better your performance is.", # widget=widgets.RadioSelect, # ) # def part1ctrl3_choices(self): # choices = self.participant.vars['choices_q3_shuffled'] # return choices # question 3 version 2 (to be used in Part 2) # correct answer is 2 part1ctrl3 = models.StringField( label="How was your bonus payment in Part 1 determined based on your performance?", widget=widgets.RadioSelect, ) def part1ctrl3_choices(self): choices = self.participant.vars['choices_q3_shuffled'] return choices def error_message(self, value): correct_answers = { "part1ctrl1": '1', "part1ctrl2": '3', "part1ctrl3": '2', } list_answers = list(value.items())[0:] list_correct_answers = list(correct_answers.items()) list_ctrl_errors_count = [0] * len(correct_answers) if list_answers != list_correct_answers: self.ctrl_errors_part1_count = self.ctrl_errors_part1_count + 1 indices = list(range(len(list_correct_answers))) for i in range(len(indices)): if list_answers[i] != list_correct_answers[i]: indices[i] = i + 1 list_ctrl_errors_count[i] = list_ctrl_errors_count[i] + 1 else: indices[i] = None self.participant.vars['error_questions'] = indices return 'Please check your answers.'