from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) from django.db import models as djangomodels author = 'Your name here' doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'public_goods' players_per_group = 3 num_rounds = 10 multiplier = 0.5 payoff = models.CurrencyField(min=0) punishment_multiplier = 3 treatment = models.BooleanField() treatments = models.BooleanField() import itertools import ast class Subsession(BaseSubsession): treatment = models.BooleanField() endowment = models.CurrencyField( min=0 ) def creating_session(self): if self.round_number == 1: # randomize to treatments punishs = itertools.cycle(['Punishment', 'Normal']) for group in self.get_groups(): p1 = group.get_player_by_id(1) p1.participant.vars['treatment'] = next(punishs) for player in group.get_players(): player.participant.vars['endowment'] = c(100) player.participant.vars['id'] = player.id_in_group else: self.group_like_round(1) pun = [] for player in self.get_players(): for other in player.get_others_in_group(): pun.append(Punishment(sender=player, receiver=other, )) Punishment.objects.bulk_create(pun) def vars_for_admin_report(self): treatments = [] for g in self.get_groups(): p1 = g.get_player_by_id(1) g.treatment = p1.participant.vars['treatment'] treatments.append(g.treatment) return dict(treatments=treatments) class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() endowment = models.CurrencyField(min=0) treatment = models.CharField() def set_beforepun_payoffs(group): players = group.get_players() contributions = [p.contribution for p in players] group.total_contribution = sum(contributions) group.individual_share = group.total_contribution * Constants.multiplier for player in players: #player.beforepun_payoff = Constants.endowment - player.contribution + group.individual_share player.endowment = player.participant.vars['endowment'] player.beforepun_payoff = player.endowment - player.contribution + group.individual_share def set_punishments(self): for player in self.get_players(): player.set_punishment() player.set_payoff() class Player(BasePlayer): punish = models.BooleanField() endowment = models.CurrencyField(min=0) contribution = models.CurrencyField( min=0, max=100, label="How much will you contribute?" ) punishment_sent = models.IntegerField() punishment_received = models.IntegerField() beforepun_payoff = models.CurrencyField(min=0) def set_payoff(self): groups = self.subsession.get_groups() for group in groups: p1 = self.group.get_player_by_id(1) Treatment = p1.participant.vars['treatment'] if Treatment == 'Punishment': self.payoff = self.beforepun_payoff - self.punishment_sent - self.punishment_received if self.payoff < 0: self.payoff = 0 else: self.payoff = self.beforepun_payoff if self.payoff < 0: self.payoff = 0 def set_punishment(self): if None in [i.amount for i in self.punishments_sent.all()]: self.punishment_sent = 0 self.punishment_received = 0 else: self.punishment_sent = sum([i.amount for i in self.punishments_sent.all()]) self.punishment_received = sum( [i.amount for i in self.punishments_received.all()]) * Constants.punishment_multiplier class Punishment(djangomodels.Model): sender = djangomodels.ForeignKey(to=Player, related_name='punishments_sent', on_delete=djangomodels.CASCADE) receiver = djangomodels.ForeignKey(to=Player, related_name='punishments_received', on_delete=djangomodels.CASCADE) amount = models.IntegerField(min=0)