from otree.api import *
import random
doc = """
no conflict resolution mechanism with positive externality (0.5). with social preference test at the end.
"""
class Constants(BaseConstants):
name_in_url = 'no_mechanism_positive'
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_total = 10
p.payoff_money = 0
else:
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 = 8.55 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 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
]