from otree.api import * import random doc = """ no conflict resolution mechanism with negative externality (-0.5). with social preference test at the end. """ class Constants(BaseConstants): name_in_url = 'no_mechanism_negative' players_per_group = 2 num_rounds = 35 #will change to 35 in real game #table_template = __name__ + '/table.html' class Subsession(BaseSubsession): endowment = models.FloatField( initial=10.0 ) # the value of endowment w externality = models.FloatField( initial= -0.5 ) class Group(BaseGroup): #total_private_claim = models.FloatField(initial=0.0) total_private_claim = models.IntegerField(initial=0.0) #total_public_claim = models.FloatField(initial=0.0) #public_claim = models.FloatField(initial=0.0) class Player(BasePlayer): #private = models.FloatField( # min=0.0, # label ='', #) private = models.IntegerField( min=0.0, label='', ) attack = models.BooleanField( initial=False, doc="""Indicates whether the player invest into the private claim""" ) total_payoff = models.FloatField(initial=0.0) total_payoff_externality = models.FloatField(initial=0.0) remaining_endowment = models.FloatField(initial=0.0) #available_for_private = models.FloatField(initial=0.0) # randomly select 1 out of 30 rounds for final payment payoff_money = models.FloatField( initial=0, ) payoff_final = models.FloatField( initial=0, ) round_to_pay = models.IntegerField( initial=0 ) payoff_money_total = models.FloatField( initial=0, ) quiz1 = models.StringField( choices=['1 point', '10 points', '20 points'], label='1. What is your endowment in each round?', widget=widgets.RadioSelect) quiz2 = models.StringField( choices=['10+10 = 20 points', '(10-5) + (10-4) = 11 points', '10 points'], label='2. What is the prize? ' 'Hint: See page 2 for the exact formula for the prize.', widget=widgets.RadioSelect) quiz3 = models.StringField( choices=['5/(5+4)*16 = 8.88 points', '5/(5+4)*11 = 6.11 points', '4/(5+4)*11 = 4.88 points'], label='3. What are your earnings? Hint: See CASE 2 on page 3 for the exact formula for your earnings.', widget=widgets.RadioSelect) quiz4 = models.StringField( choices=['5/(5+4)*16 = 8.88 points', '5/(5+4)*11 = 6.11 points', '4/(5+4)*11 = 4.88 points'], label='4. What are your group member’s earnings? Hint: See CASE 2 on page 3 for the exact formula for your group member’s earnings.', widget=widgets.RadioSelect) quiz5 = models.StringField( choices=['6.11-0.5*4.88 = 3.67 points', '6.11+0.5*4.88 = 8.55 points', '6.11 points'], label='5. What is your payoff? Hint: See CASE 2 on page 3 for the exact formula for your payoff.', widget=widgets.RadioSelect) quiz6 = models.StringField( choices=['10+10 = 20 points', '(10-4) + (10-0) = 16 points', '10 points'], label='6. What is the prize? ' 'Hint: See page 2 for the exact formula for the prize.', widget=widgets.RadioSelect) quiz7 = models.StringField( choices=['0/(4+0)*16 = 0 points', '4/(4+0)*16 = 16 points', '4/(4+0)*20 = 20 points'], label='7. What are your earnings? Hint: See CASE 2 on page 3 for the exact formula for your earnings. ', widget=widgets.RadioSelect) quiz8 = models.StringField( choices=['0/(4+0)*16 = 0 points', '4/(4+0)*16 = 16 points', '4/(4+0)*20 = 20 points'], label='8. What are your group member’s earnings? Hint: See CASE 2 on page 3 for the exact formula for your group member’s earnings.', widget=widgets.RadioSelect) quiz9 = models.StringField( choices=['0 points', '16-0.5*0 = 16 points', '0-0.5*16 = -8 points'], label='9. What is your payoff? Hint: See CASE 2 on page 3 for the exact formula for your payoff. ', widget=widgets.RadioSelect) ## social preference test social_1 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $2.5 to other'], ], label='Question 1', widget=widgets.RadioSelectHorizontal ) social_2 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $2.0 to other'], ], label='Question 2', widget=widgets.RadioSelectHorizontal ) social_3 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $1.5 to other'], ], label='Question 3', widget=widgets.RadioSelectHorizontal ) social_4 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $2.5 to you, $2.0 to other'], ], label='Question 4', widget=widgets.RadioSelectHorizontal ) social_5 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $2.5 to you, $1.5 to other'], ], label='Question 5', widget=widgets.RadioSelectHorizontal ) social_6 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $2.5 to you, $1.0 to other'], ], label='Question 6', widget=widgets.RadioSelectHorizontal ) social_7 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $3.5 to other'], ], label='Question 7', widget=widgets.RadioSelectHorizontal ) social_8 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $4.0 to other'], ], label='Question 8', widget=widgets.RadioSelectHorizontal ) social_9 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.0 to you, $4.5 to other'], ], label='Question 9', widget=widgets.RadioSelectHorizontal ) social_10 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.5 to you, $4.0 to other'], ], label='Question 10', widget=widgets.RadioSelectHorizontal ) social_11 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.5 to you, $4.5 to other'], ], label='Question 11', widget=widgets.RadioSelectHorizontal ) social_12 = models.IntegerField( choices=[ [1, 'A: $3.0 to you, $3.0 to other'], [2, 'B: $3.5 to you, $5.0 to other'], ], label='Question 12', widget=widgets.RadioSelectHorizontal ) social_payoff = models.FloatField( initial=0, ) social_selected_round = models.IntegerField( initial=0, ) # Functions def creating_session(subsession: Subsession): # Random matching subsession.group_randomly() # Decide round to pay players = subsession.get_players() # Decide the random round to pay round_to_pay = random.randint(6, 35) social_selected_round = random.randint(1, 12) for p in players: if p.round_number == 1: p.round_to_pay = round_to_pay p.social_selected_round = social_selected_round else: last_p = p.in_round(p.round_number - 1) p.round_to_pay = last_p.round_to_pay p.social_selected_round = last_p.social_selected_round #def set_public_claim(group: Group): #p1 = group.get_player_by_id(1) #p2 = group.get_player_by_id(2) #if p1.public == "0.0": # group.public_claim = 0 #elif p2.public == "0.0": # group.public_claim = 0 #else: # group.public_claim = 1 #group.public_claim = min([p.public for p in players]) #group.total_public_claim = 2 * group.public_claim #for p in [p1,p2]: # p.available_for_private = 10 - group.public_claim def set_payoff(group:Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) for p in [p1, p2]: p.remaining_endowment = 20 - p1.private - p2.private if p.private > 0: p.attack = True if p1.attack == True and p2.attack == True: p1.total_payoff = p1.private / (p1.private + p2.private) * p1.remaining_endowment p2.total_payoff = p2.private / (p1.private + p2.private) * p2.remaining_endowment elif p1.attack == True and p2.attack == False: p1.total_payoff = p1.remaining_endowment p2.total_payoff = 0 elif p1.attack == False and p2.attack == True: p1.total_payoff = 0 p2.total_payoff = p2.remaining_endowment else: for p in [p1, p2]: p.total_payoff = 10.0 p1.total_payoff_externality = p1.total_payoff - 0.5 * p2.total_payoff p2.total_payoff_externality = p2.total_payoff - 0.5 * p1.total_payoff # Store the earnings of this round at the total for p in [p1,p2]: if p.round_number == p.round_to_pay: p.payoff_final = p.total_payoff_externality p.payoff_money = 1*p.total_payoff_externality if p.payoff_money < 0: p.payoff_money = 0 p.payoff_money_total = 10 else: #p.payoff_money=p.payoff_money p.payoff_money_total = 10 + 1 * p.total_payoff_externality #p.payoff_money_total = 10+1.5 * p.total_payoff_externality else: if p.round_number > 1: last_p = p.in_round(p.round_number - 1) p.payoff_final = last_p.payoff_final p.payoff_money = last_p.payoff_money p.payoff_money_total = last_p.payoff_money_total ## set the payoff for social efficiency test results def set_social_payoff(group: Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) for p in [p1,p2]: if p.social_selected_round ==1 and p1.social_1 == 2: p1.social_payoff = 3 p2.social_payoff = 2.5 elif p.social_selected_round ==2 and p1.social_2 == 2: p1.social_payoff = 3 p2.social_payoff = 2.5 elif p.social_selected_round ==3 and p1.social_3 == 2: p1.social_payoff = 3 p2.social_payoff = 1.5 elif p.social_selected_round ==4 and p1.social_4 == 2: p1.social_payoff = 2.5 p2.social_payoff = 2 elif p.social_selected_round ==5 and p1.social_5==2: p1.social_payoff = 2.5 p2.social_payoff = 1.5 elif p.social_selected_round ==6 and p1.social_6==2: p1.social_payoff = 2.5 p2.social_payoff = 1 elif p.social_selected_round ==7 and p1.social_7 ==2: p1.social_payoff = 3 p2.social_payoff = 3.5 elif p.social_selected_round ==8 and p1.social_8 == 2: p1.social_payoff = 3 p2.social_payoff = 4 elif p.social_selected_round ==9 and p1.social_9 == 2: p1.social_payoff = 3 p2.social_payoff = 4.5 elif p.social_selected_round ==10 and p1.social_10 == 2: p1.social_payoff = 3.5 p2.social_payoff = 4 elif p.social_selected_round ==11 and p1.social_11 == 2: p1.social_payoff = 3.5 p2.social_payoff = 4.5 elif p.social_selected_round ==12 and p1.social_12 == 2: p1.social_payoff = 3.5 p2.social_payoff = 5 else: p1.social_payoff=3 p2.social_payoff=3 # PAGES class Welcome(Page): def is_displayed(self): return self.round_number == 1 after_all_players_arrive = creating_session #class before_Stage1(Page): #communication notification # @staticmethod # def vars_for_template(player: Player): # other = player.get_others_in_group()[0] # return dict( # round_shown=player.round_number, # total_shown=Constants.num_rounds, # other=other, # ) #class Stage1(Page): #communication stage # timer_text = 'Time left to end the conversation:' # timeout_seconds = 90 # @staticmethod # def vars_for_template(player: Player): # other = player.get_others_in_group()[0] # return dict( # round_shown=player.round_number, # total_shown=Constants.num_rounds, # other=other, # ) class Stage2(Page): form_model = 'player' form_fields = ['private'] @staticmethod def vars_for_template(player: Player): #public_claim = player.group.public_claim #total_public_claim = player.group.total_public_claim other = player.get_others_in_group()[0] return dict( #public_claim=public_claim, #payoff1=10 - public_claim, #payoff2=20 - total_public_claim, #total_public_claim=total_public_claim, other=other, round_shown=player.round_number-5, total_shown=Constants.num_rounds-5 ) def error_message(player, values): #public_claim = player.group.public_claim if values['private'] > 10: return 'You cannot invest into the private claims more than 10 points.' #def private_error_message(player, value): # print('value is', value) #if value + player.public > 10.0: # return 'You cannot invest into the private claim more than your remaining budget' class Result(Page): def vars_for_template(player: Player): #public_claim = player.group.public_claim #total_public_claim = player.group.total_public_claim other = player.get_others_in_group()[0] return dict( #public_claim=public_claim, #total_public_claim=total_public_claim, other=other, round_shown=player.round_number-5, total_shown=Constants.num_rounds-5 ) class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoff #class Stage1WaitPage(WaitPage): # pass #class Beforestage1WaitPage(WaitPage): # pass class Quiz(Page): def is_displayed(self): return self.round_number == 1 form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4', 'quiz5', 'quiz6', 'quiz7', 'quiz8', 'quiz9', ] @staticmethod def error_message(player, values): solutions = dict( quiz1='10 points', quiz2='(10-5) + (10-4) = 11 points', quiz3='5/(5+4)*11 = 6.11 points', quiz4='4/(5+4)*11 = 4.88 points', quiz5='6.11-0.5*4.88 = 3.67 points', quiz6='(10-4) + (10-0) = 16 points', quiz7='4/(4+0)*16 = 16 points', quiz8='0/(4+0)*16 = 0 points', quiz9='16-0.5*0 = 16 points', ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name]: error_messages[field_name] = 'Wrong answer' return error_messages class Part1_end(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant # in settings.py need to add 'payoff_money' to PARTICIPANT_FIELDS. participant.payoff_money = player.payoff_money participant.round_to_pay = player.round_to_pay participant.payoff_final = player.payoff_final participant.social_payoff = player.social_payoff participant.social_selected_round = player.social_selected_round class Practiceround_instruction(Page): def is_displayed(self): return self.round_number == 1 class Practiceround_summary (Page): def is_displayed(self): return self.round_number == 5 class Practiceround_summary (Page): def is_displayed(self): return self.round_number == 5 class Social_efficiency (Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds form_model = 'player' form_fields = ['social_1', 'social_2', 'social_3', 'social_4', 'social_5', 'social_6', 'social_7', 'social_8', 'social_9', 'social_10', 'social_11', 'social_12', ] class SocialWaitPage(WaitPage): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds after_all_players_arrive = set_social_payoff class Social_efficiency_results(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds page_sequence = [Welcome, Quiz, Practiceround_instruction, Stage2, ResultsWaitPage, Result, Practiceround_summary, Social_efficiency, SocialWaitPage, Social_efficiency_results, Part1_end ]