from otree.api import models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, \ Currency as c, currency_range import numpy as np class Constants(BaseConstants): name_in_url = 'public_goods_klevans' players_per_group = 8 #consider being flexible with number of subjects endowment = 5 * (players_per_group - 1) * players_per_group #set to ensure no bankruptcy num_rounds = min(15, np.random.geometric(p=0.1)) multiplier = 1 instructions_template = 'klevans_public_goods/instructions.html' treatment = True def payoff_x(y): return Constants.endowment - 5 * (y ** 2 - y) class Subsession(BaseSubsession): #def creating_session(self): # self.group_randomly() pass #feedback was to use table instead of marginal analysis class Label(): max_contribution = Constants.players_per_group # inputs = [[y + 1, 'Spend ' + str(y + 1) + ' unit(s) on activity Y. (Payoff from X: ' # + str(Constants.payoff_x(y + 1)) + # ' points. Increasing amount spent on Y to ' + str(y + 2) + ' units would lower payoff from X by ' # + str(Constants.payoff_x(y + 1)-Constants.payoff_x(y + 2)) + # ' points, and increase payoff from Y to each participant by 10 points.)'] for y in range(max_contribution)] # inputs[-1][1] = ('Spend ' + str(max_contribution) + ' unit(s) on activity Y. You would then earn ' + # str(Constants.payoff_x(max_contribution)) + # ' points from activity X. This is the maximum you can spend on activity Y.') # inputs = [[y + 1, str(y + 1) + ' units(s). ' # + str(Constants.payoff_x(y + 1)) + # ' points. ' + str(Constants.payoff_x(y + 1)-Constants.payoff_x(y + 2)) + # ' points. 10 points.'] for y in range(max_contribution)] # inputs[-1][1] = (str(max_contribution) + ' unit(s). ' + # str(Constants.payoff_x(max_contribution)) + ' points. N/A') class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() def set_payoffs(self): players = self.get_players() contributions = [p.contribution for p in players] self.total_contribution = sum(contributions) self.individual_share = self.total_contribution * Constants.multiplier / Constants.players_per_group for p in players: p.payoff = Constants.endowment - 10 * (p.contribution**2 - p.contribution)/2 + 10 * self.total_contribution #p.stop = p.round_number + int(p.id_in_group <= p.round_number) class Player(BasePlayer): #contributions must be integers from 0 to n #contribution = models.IntegerField(min=0, max=Constants.endowment, widget=widgets.RadioSelect, choices=Label.inputs) contribution = models.IntegerField(min=0, max=Constants.players_per_group, label="How much do you want to contribute?") #stop = models.IntegerField() def contribution_error_message(player, value): if value == 0: return 'Must contribute at least 1 unit'