from otree.api import *
import random
import numpy as np
from datetime import datetime
doc = """
Player A decides how to divide a certain amount between himself and two other
players.
"""
# CLASSES
class C(BaseConstants):
NAME_IN_URL = 'idp'
PLAYERS_PER_GROUP = None
NUM_ROUNDS = 3
INSTRUCTIONS_TEMPLATE = 'dictator_randomized/Instructions.html'
INSTRUCTIONS_TEMPLATE_SEQ = 'dictator_randomized/Instructions_seq.html'
INITIAL = cu(0)
MAXITER = 100
PROB_SELECTED = 0.2
class Subsession(BaseSubsession):
pass
class Group(BaseGroup):
pass
class Player(BasePlayer):
ENDOWMENT = models.CurrencyField()
sent_amount_B = models.CurrencyField()
sent_amount_C = models.CurrencyField()
redo = models.BooleanField(initial=True)
redo_seq = models.BooleanField(initial=True)
selected = models.BooleanField()
selected_round = models.IntegerField()
error_count = models.IntegerField(initial=0)
BC_error_count = models.IntegerField(initial=0)
consent = models.BooleanField()
# Comprehension Question Fields (SIM)
comp_sim = models.IntegerField(widget=widgets.RadioSelectHorizontal,
label="1. As Person A, you",
choices=[[1,
"can decide how much money to keep for yourself, but not for Person B and Person C."],
[2,
"can decide how much money to keep for yourself, and how much money Person B and Person C would each receive."],
[3,
"can decide how much money to keep for yourself, and how much money Person B would receive, but not how much money Person C would receive."],
# [4,
# "cannot decide how much money to keep for yourself and should wait for the decision of Person B."]
])
comp_BCreal = models.IntegerField(widget=widgets.RadioSelectHorizontal,
label="2. There are Person B and Person C in the scenario. Who are these people?",
choices=[[1,
"They are real people who are recruited on MTurk just like you."],
[2,
"They are imaginary people."]])
# Comprehension Question Fields (SEQ)
comp_seq = models.IntegerField(widget=widgets.RadioSelectHorizontal,
label="As Person A, you get to decide how much to keep for yourself and pass on to Person B. What happens to the amount of money that you pass on to Person B?
",
choices=[
[1,
"Person B receives the money and does not have to make any decision."],
# [2,
# "Person B receives the money and has to pass on a fixed amount to Person C."],
[2,
"Person B receives the money and has to decide how much to keep for themselves and pass on to Person C."],
[3,
"Person B does not receive the money."]])
# FUNCTIONS
# Error Messages for incorrect user inputs
def comp_sim_error_message(player, value):
if value != 2:
player.error_count += 1
return('Incorrect response, please try again.')
def comp_BCreal_error_message(player, value):
if value != 1:
player.BC_error_count += 1
return('Incorrect response, please try again.')
def comp_seq_error_message(player, value):
if value != 2:
player.error_count += 1
return 'Incorrect response, please try again.'
# PAGES
class Consent(Page):
form_model = 'player'
form_fields = ['consent']
@staticmethod
def is_displayed(group):
return group.round_number==1
class Welcome(Page):
@staticmethod
def is_displayed(group):
return group.round_number==1
# Randomize players to SIM/SEQ respectively
@staticmethod
def before_next_page(player, timeout_happened):
participant = player.participant
# Randomize odd/even players to SIM/SEQ:
participant.sim = bool(player.id_in_group % 2)
# seed = int(datetime.now().timestamp())
# rng = np.random.default_rng(seed)
# participant.sim = bool(rng.binomial(n=1, p=0.5))
class Introduction(Page):
@staticmethod
def is_displayed(player):
participant = player.participant
return player.round_number==1 & participant.sim
@staticmethod
def before_next_page(player, timeout_happened):
# Randomize for each session: bernoulli draw
seed = int(datetime.now().timestamp())
rng = np.random.default_rng(seed)
selected = bool(rng.binomial(n=1, p=C.PROB_SELECTED))
selected_round = int(rng.integers(1, 3, endpoint=True))
print("Selected for Payment:", selected)
if selected: print("Selected Round:", selected_round)
participant = player.participant
participant.selected = selected
participant.selected_round = selected_round
class Introduction_seq(Page):
@staticmethod
def is_displayed(player):
participant = player.participant
return player.round_number==1 & ~participant.sim
@staticmethod
def before_next_page(player, timeout_happened):
# Randomize for each session: bernoulli draw
seed = int(datetime.now().timestamp())
rng = np.random.default_rng(seed)
selected = bool(rng.binomial(n=1, p=C.PROB_SELECTED))
selected_round = int(rng.integers(1, 3, endpoint=True))
print("Selected for Payment:", selected)
if selected: print("Selected Round:", selected_round)
participant = player.participant
participant.selected = selected
participant.selected_round = selected_round
class Comprehension(Page):
form_model = 'player'
form_fields = ['comp_sim','comp_BCreal']
@staticmethod
def is_displayed(player):
participant = player.participant
return player.round_number==1 & participant.sim
# Randomize the state between rounds
def js_vars(player):
participant = player.participant
# Store selected round information
player.selected = participant.selected
player.selected_round = participant.selected_round
# Shuffle the states
if player.round_number==1:
statesList = [10, 20, 30]
seed = datetime.now().timestamp()
random.seed(seed)
random.shuffle(statesList)
print("Shuffled states:", statesList)
participant.state_1 = cu(statesList[0])
participant.state_2 = cu(statesList[1])
participant.state_3 = cu(statesList[2])
return dict()
class Comprehension_seq(Page):
form_model = 'player'
form_fields = ['comp_seq','comp_BCreal']
@staticmethod
def is_displayed(player):
participant = player.participant
return player.round_number == 1 & ~participant.sim
# Randomize the state between rounds
def js_vars(player):
participant = player.participant
# Store selected round information
player.selected = participant.selected
player.selected_round = participant.selected_round
# Shuffle the states
if player.round_number==1:
statesList = [10, 20, 30]
seed = datetime.now().timestamp()
random.seed(seed)
random.shuffle(statesList)
print("Shuffled states:", statesList)
participant.state_1 = cu(statesList[0])
participant.state_2 = cu(statesList[1])
participant.state_3 = cu(statesList[2])
return dict()
# FOR Person A
class Send(Page):
form_model = 'player'
form_fields = ['sent_amount_B', 'sent_amount_C']
# Passing data from Python to JavaScript
def js_vars(player):
participant = player.participant
if player.round_number==1:
player.ENDOWMENT = participant.state_1
elif player.round_number==2:
player.ENDOWMENT = participant.state_2
else:
player.ENDOWMENT = participant.state_3
return dict(
endowment = player.ENDOWMENT
)
# Validating multiple fields together - transferred amount must not exceed C.ENDOWMENT
@staticmethod
def error_message(player, values):
print('values are', values)
if values['sent_amount_B'] + values['sent_amount_C'] > player.ENDOWMENT:
return 'You cannot transfer more than {} to Person B and Person C in total.'.format(player.ENDOWMENT)
# Pass variables to the template
@staticmethod
def vars_for_template(player):
pass
@staticmethod
def is_displayed(player):
participant = player.participant
return player.redo & participant.sim
class Results(Page):
# Passing data from Python to JavaScript
def js_vars(player):
group = player.group
return dict(
payoff_A = player.ENDOWMENT - player.sent_amount_B - player.sent_amount_C,
payoff_B = player.sent_amount_B,
payoff_C = player.sent_amount_C,
endowment = player.ENDOWMENT
)
form_model = 'player'
form_fields = ['redo']
@staticmethod
def is_displayed(player):
participant = player.participant
return player.redo & participant.sim
@staticmethod
def before_next_page(player, timeout_happened):
participant = player.participant
if participant.selected==True and player.round_number==participant.selected_round:
# Calculate payoffs
participant.payoff = player.ENDOWMENT - player.sent_amount_B - player.sent_amount_C
class Send_seq(Page):
form_model = 'player'
form_fields = ['sent_amount_B']
# Passing data from Python to JavaScript
def js_vars(player):
participant = player.participant
if player.round_number==1:
player.ENDOWMENT = participant.state_1
elif player.round_number==2:
player.ENDOWMENT = participant.state_2
else:
player.ENDOWMENT = participant.state_3
return dict(
endowment = player.ENDOWMENT
)
# Pass variables to the template
@staticmethod
def vars_for_template(player):
pass
@staticmethod
def is_displayed(player):
participant = player.participant
return player.redo_seq & ~participant.sim
class Results_seq(Page):
# Passing data from Python to JavaScript
def js_vars(player):
return dict(
payoff_A = player.ENDOWMENT - player.sent_amount_B,
payoff_B = player.sent_amount_B,
endowment = player.ENDOWMENT
)
form_model = 'player'
form_fields = ['redo_seq']
@staticmethod
def is_displayed(player):
participant = player.participant
return player.redo_seq & ~participant.sim
@staticmethod
def before_next_page(player, timeout_happened):
participant = player.participant
if participant.selected==True and player.round_number==participant.selected_round:
# Calculate payoffs
participant.payoff = player.ENDOWMENT - player.sent_amount_B
class Transition(Page):
@staticmethod
def is_displayed(group):
return group.round_number==3
page_sequence = [Consent, Welcome, Introduction, Introduction_seq, Comprehension, Comprehension_seq,]
for _ in range(C.MAXITER):
page_sequence = page_sequence + [Send, Results,]
for _ in range(C.MAXITER):
page_sequence = page_sequence + [Send_seq, Results_seq,]
page_sequence = page_sequence + [Transition,]