from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import numpy as np import random import numpy.random as npr author = 'jacopo.bregolin@gmail.com' doc = """ Game: In period 1, advisor(s) suggest and agent has to make a choice. In the second period the agent has to purchase advise and make a choice. """ class Constants(BaseConstants): name_in_url = 'Game' players_per_group = None ''' num_rounds = Total numer of rounds played (0.6 or 0.7) # number of rounds with different purchase system --> MINUS 1! # (so that total - this number = first of the special) # e.g. if num_lastRounds = 4, then the last 5 rounds have the special behavior num_lastRounds = number of rounds minus 1 played with the bidding rule ''' ######################################### # RUNNING ALL EXPERIMENT print('full mode') num_rounds = 15 num_lastRounds = 4 #(this is 1 less than the true number of last rounds) ######################################## last_rounds = [i for i in range(num_rounds-num_lastRounds,num_rounds+1)] # robots ids listRobots = [i for i in range(20)] class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: self.session.vars['num_lastRounds'] = Constants.num_lastRounds self.session.vars['total_number_rounds_game'] = Constants.num_rounds self.session.vars['number_last_rounds_game'] = Constants.num_lastRounds + 1 for p in self.get_players(): # round considered for payment in first treatment p.participant.vars['paid_round'] = random.randint(1,Constants.num_rounds) print('payment is based on round:',p.participant.vars['paid_round']) # allocate list of robots for 1st/2nd advisor robotlist1 = Constants.listRobots.copy() robotlist2 = Constants.listRobots.copy() npr.shuffle(robotlist1) npr.shuffle(robotlist2) p.participant.vars['robotlist1'] = robotlist1 p.participant.vars['robotlist2'] = robotlist2 p.participant.vars['advice_purchases'] = [] ''' advice_purchases will contain the purchase decisions''' for p in self.get_players(): # create pool of balls if p.participant.vars['treatment'] in ['1A','2A']: p.numGreen = 6 p.numBlue = 4 elif p.participant.vars['treatment'] in ['1B','2B']: p.numGreen = 7 p.numBlue = 3 else: raise ValueError("Participant treatment value is not recognised") p.truecolor_period1 = npr.choice(['Bleu','Vert'], p=[p.numBlue/(p.numBlue+p.numGreen), p.numGreen/(p.numBlue+p.numGreen)]) p.truecolor_period2 = npr.choice(['Bleu','Vert'], p=[p.numBlue/(p.numBlue+p.numGreen), p.numGreen/(p.numBlue+p.numGreen)]) if p.truecolor_period1 == 'Vert': p.falsecolor_period1 = 'Bleu' elif p.truecolor_period1 == 'Bleu': p.falsecolor_period1 = 'Vert' if p.truecolor_period2 == 'Vert': p.falsecolor_period2 = 'Bleu' elif p.truecolor_period2 == 'Bleu': p.falsecolor_period2 = 'Vert' p.advisor1 = npr.choice(['Parfait','Défectueux']) p.advisor2 = npr.choice(['Parfait','Défectueux']) p.coin_period1 = npr.choice(['head','tail']) p.coin_period2 = npr.choice(['head','tail']) print('in round', self.round_number,'the color in period 1 is', p.truecolor_period1, 'and in period 2 is', p.truecolor_period2) print('advisors are:', p.advisor1, p.advisor2) print('the coins are:', p.coin_period1, p.coin_period2) # allocate robots to rounds p.robot = p.participant.vars['robotlist1'][self.round_number-1] p.robot2 = p.participant.vars['robotlist2'][self.round_number-1] # random threshold in second price auction if self.round_number in Constants.last_rounds: p.dice_single = int(npr.choice(np.arange(self.session.vars['max_bid_single_drawn']+1))) # bid from 0 to max, max is included p.dice_bundle = int(npr.choice(np.arange(self.session.vars['max_bid_bundle_drawn']+1))) p.in_last_rounds = p.is_in_last_rounds() class Group(BaseGroup): pass class Player(BasePlayer): in_last_rounds = models.BooleanField() numGreen = models.IntegerField() numBlue = models.IntegerField() truecolor_period1 = models.StringField() truecolor_period2 = models.StringField() falsecolor_period1 = models.StringField() falsecolor_period2 = models.StringField() advisor1 = models.StringField() advisor2 = models.StringField() coin_period1 = models.StringField() coin_period2 = models.StringField() guess_period1 = models.StringField( choices=['Vert','Bleu'], widget=widgets.RadioSelectHorizontal) guess_period2 = models.StringField( choices=['Vert','Bleu'], widget=widgets.RadioSelectHorizontal) requested_advice = models.StringField(widget=widgets.RadioSelect) payoff_period1 = models.IntegerField() payoff_period2 = models.IntegerField() round_payoff = models.IntegerField() robot = models.IntegerField() robot2 = models.IntegerField() bid_price = models.IntegerField(min=0) dice_single = models.IntegerField() dice_bundle = models.IntegerField() # QUESTIONS LAST ROUNDS # questions treatment 1A1B Q1 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si le prix seuil X que nous avons programmé est inférieur à B, vous recevez du conseil et vous payez B points.") Q2 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si le prix seuil X que nous avons programmé est inférieur à B, vous recevez du conseil et vous payez X points.") Q3 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si le prix seuil X que nous avons programmé est supérieur à B, vous recevez du conseil et vous payez X points.") Q4 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si le prix seuil X que nous avons programmé est supérieur à B, vous ne recevez pas de conseil.") # questions on last rounds - treatment 2A2B version 1 Q5 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B>X, vous recevez du conseil et vous payez B points.") Q6 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B>X, vous recevez du conseil et vous payez X points.") Q7 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si X/2<B<X, vous recevez seulement un conseil.") # replace "," with < to have right display Q8 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B<X, vous ne recevez pas de conseil.") # replace "," with < to have right display # questions on last rounds - treatment 2A2B version 2 Q9 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B>X, vous recevez du conseil et vous payez B points.") Q10 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B>X, vous recevez du conseil et vous payez X points.") Q11 = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['Oui','No'], label="Si B<X, vous ne recevez pas du conseil.") # replace "," with < to have right display def bid_price_max(self): if self.requested_advice in ['Yes','3','1','2']: return self.session.vars['max_bid_single'] elif self.requested_advice in ['12']: return self.session.vars['max_bid_bundle'] else: return 0 def is_in_last_rounds(self): if self.round_number in Constants.last_rounds: return True else: return False def requested_advice_choices(self): if self.participant.vars['treatment'] in ['1A','1B']: choices=[['Yes','Je veux acheter du conseil'], ['No', "Je ne veux pas acheter de conseil"]] elif self.participant.vars['treatment'] in ['2A','2B'] and self.participant.vars['treatment_2advisors_lastrounds'] == 'version2' and self.round_number in Constants.last_rounds: choices = [ ['3',"Je veux acheter un conseil supplémentaire au conseiller à droite de mon écran"], ['0', "Je ne veux pas acheter du conseil supplémentaire"]] else: choices=[ ['12', "Je veux acheter du conseil par les deux conseillers"], ['1', 'Je veux acheter du conseil au conseiller à gauche de mon écran'], ['2', "Je veux acheter du conseil au conseiller à droite de mon écran"], ['0', "Je ne veux pas acheter de conseil"]] return choices #def bid_price_max(self): # if self.requested_advice == '12': # return self.session.vars['max_bid_bundle'] # else: # return self.session.vars['max_bid_single'] # def Q1_error_message(self, value): # if value != 'No': # return 'Veuillez relire les instructions' # def Q2_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' # def Q3_error_message(self, value): # if value != 'No': # return 'Veuillez relire les instructions' # def Q4_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' # def Q5_error_message(self, value): # if value != 'No': # return 'Veuillez relire les instructions' # def Q6_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' # def Q7_error_message(self, value): # if value != 'No': # return 'Veuillez relire les instructions' # def Q8_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' # def Q9_error_message(self, value): # if value != 'No': # return 'Veuillez relire les instructions' # def Q10_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' # def Q11_error_message(self, value): # if value != 'Oui': # return 'Veuillez relire les instructions' def points_gained_P1(self): if self.guess_period1==self.truecolor_period1: return self.session.vars['payoff_answer_correct'] else: return 0 def points_gained_P2(self): if self.guess_period2==self.truecolor_period2: outcome = self.session.vars['payoff_answer_correct'] else: outcome = 0 if self.in_last_rounds == False: if self.participant.vars['treatment'] in ['1A','1B']: if self.requested_advice == 'Yes': payoff = outcome - 5 elif self.requested_advice == 'No': payoff = outcome elif self.participant.vars['treatment'] in ['2A','2B']: if self.requested_advice in ['1','2']: payoff = outcome - 5 elif self.requested_advice == '12': payoff = outcome - 10 elif self.requested_advice == '0': payoff = outcome elif self.in_last_rounds == True: if self.participant.vars['treatment'] in ['1A','1B']: if self.requested_advice == 'Yes' and self.bid_price > self.dice_single: payoff = outcome - self.dice_single else: payoff = outcome elif self.participant.vars['treatment'] in ['2A','2B']: if self.requested_advice in ['1','2','3'] and self.bid_price > self.dice_single: payoff = outcome - self.dice_single elif self.requested_advice == '12' and self.bid_price > self.dice_bundle: payoff = outcome - self.dice_bundle else: payoff = outcome return payoff def points_gained(self): return self.points_gained_P1() + self.points_gained_P2()