from otree.api import * from django import forms from django.forms.widgets import NumberInput from django.db import models as djmodels c = Currency # old name for currency; you can delete this. doc = """ experiment """ class Constants(BaseConstants): name_in_url = 'leader' players_per_group = 3 num_rounds = 2 instructions_template = 'leader/instructions.html' # """Amount allocated to each player""" endowment = cu(20) punish = 10 punmulti = 2 multiplier = 1.5 class Subsession(BaseSubsession): pass def creating_session(subsession): # randomize to treatments for player in subsession.get_players(): if (player.group.id_in_subsession % 2) == 0: player.treatment = 1 player.galera = "Player 1, Player 2 and Leader" else: player.treatment = 0 player.galera = "Player 1, Player 2 and Player 3" class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() class Player(BasePlayer): treatment = models.IntegerField() galera = models.StringField() def role(self): if self.id_in_group == 1: return 'Player 1' if self.id_in_group == 2: return 'Player 2' if self.id_in_group == 3: if self.treatment == 1: return 'Leader' if self.treatment == 0: return 'Player 3' contribution = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", widget=(), label="How much will you contribute to the project (from 0 to 20)?", ) pun1, pun2, pun3 = [models.IntegerField(blank=True, initial=0) for i in range(3)] # FUNCTIONS def vars_for_admin_report(subsession: Subsession): contributions = [p.contribution for p in subsession.get_players() if p.contribution != None] if contributions: return dict( avg_contribution=sum(contributions) / len(contributions), min_contribution=min(contributions), max_contribution=max(contributions), ) else: return dict( avg_contribution='(no data)', min_contribution='(no data)', max_contribution='(no data)', ) def set_payoffs(group: Group): group.total_contribution = sum([p.contribution for p in group.get_players()]) group.individual_share = ( group.total_contribution * Constants.multiplier / Constants.players_per_group ) for p in group.get_players(): p.payoff = (Constants.endowment - p.contribution) def set_payoffs2(group: Group): group.total_contribution = sum([p.contribution for p in group.get_players()]) group.individual_share = ( group.total_contribution * Constants.multiplier / Constants.players_per_group ) for p in group.get_players(): if p.id_in_group == 1: punishment = [j.pun1 for j in p.get_others_in_group() if j.pun1 is not None] give = sum(filter(None, [p.pun1, p.pun3])) if p.id_in_group == 2: punishment = [j.pun2 for j in p.get_others_in_group() if j.pun2 is not None] give = sum(filter(None, [p.pun1, p.pun3])) if p.id_in_group == 3: punishment = [j.pun3 for j in p.get_others_in_group() if j.pun3 is not None] give = sum(filter(None, [p.pun1, p.pun2])) total_punishment = sum(punishment) p.payoff = max(0, (Constants.endowment - p.contribution) + group.individual_share - give - 2 * total_punishment) # PAGES class Introduction(Page): """Description of the game: How to play and returns expected""" def is_displayed(self): return self.subsession.round_number == 1 class Contribute(Page): """Player: Choose how much to contribute""" form_model = 'player' form_fields = ['contribution'] class instructions(Page): def vars_for_template(player: Player): return dict(galera=player.galera, role=player.role) class Contributewaitpage(WaitPage): after_all_players_arrive = set_payoffs body_text = "Waiting for other participants to contribute." class Deduction(Page): """Players payoff: How much each has earned""" form_model = 'player' form_fields = ['pun1', 'pun2', 'pun3'] def vars_for_template(player: Player): group = player.group others = player.get_others_in_group() if player.id_in_group == 1: form = ['pun2', 'pun3'] if player.id_in_group == 2: form = ['pun1', 'pun3'] if player.id_in_group == 3: form = ['pun1', 'pun2'] data = zip(others, form) contribution = player.contribution return dict(total_earnings=group.total_contribution * Constants.multiplier, rol=player.role, data=data, contribution=contribution, ) def error_message(player, values): if player.id_in_group ==1: if int(values['pun2']) + int(values['pun3']) > 10: return 'You can allocate up to 10 points in punishment.' if player.id_in_group == 2: if int(values['pun1']) + int(values['pun3']) > 10: return 'You can allocate up to 10 points in punishment.' if player.id_in_group == 3: if int(values['pun1']) + int(values['pun2']) > 10: return 'You can allocate up to 10 points in punishment.' class PunishmentWaitPage(WaitPage): after_all_players_arrive = set_payoffs2 body_text = "Waiting for other participants to contribute." class Results(Page): def vars_for_template(player: Player): group = player.group others = player.get_others_in_group() if player.id_in_group == 1: form = [cu(player.pun2), cu(player.pun3)] form2 = [cu(g.pun1) * 2 for g in others] if player.id_in_group == 2: form = [cu(player.pun1), cu(player.pun3)] form2 = [cu(g.pun2)*2 for g in others] if player.id_in_group == 3: form = [cu(player.pun1), cu(player.pun2)] form2 = [cu(g.pun3)*2 for g in others] data = zip(others, form) data2= zip(others, form2) contribution = player.contribution pung=sum(form) punr=sum(form2) punishment=pung+punr return dict(total_earnings=group.total_contribution * Constants.multiplier, punishment=punishment, rol=player.role, data=data, data2=data2, pung=pung, punr=punr, contribution=contribution, ) page_sequence = [Introduction, Contribute, Contributewaitpage, Deduction, PunishmentWaitPage, Results]