from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import numpy as np import random import string author = 'William Brown' doc = """ Public Goods Game for groups of 3 with threshold """ class Constants(BaseConstants): name_in_url = 'contribution_game' players_per_group = 3 num_rounds = 60 treatment = 1 # adjust this to set whether this treatment is the simultaneous (1) or sequential (2) treatment history_template = 'contribution_game/History.html' priv_sig = 70 group_1 = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(10)]) group_2 = ''.join([random.choice(string.ascii_letters + string.digits) for r in range(10)]) class Subsession(BaseSubsession): treatment = models.IntegerField(initial=1) # adjust this to set whether this treatment is the simultaneous (1) or sequential (2) treatment treatment_round = models.IntegerField(initial=1) #used for updating the history table def creating_session(self): if self.round_number == 1: paying_round = random.randint(1, Constants.num_rounds) self.session.vars['paying_round'] = paying_round self.group_randomly() players = self.get_players() if self.round_number > 40: self.treatment = 1 else: self.treatment = 2 if self.round_number > 1: if self.treatment != self.in_round(self.round_number-1).treatment: self.treatment_round = self.round_number else: self.treatment_round = self.in_round((self.round_number-1)).treatment_round else: pass for p in players: p.pub_good = np.random.randint(0, 100) # get random uniform signal about public good p.priv_good_sig = Constants.priv_sig # can be adjusted for treatment, private good signal p.signal_1 = np.random.randint(0, 100) p.signal_2 = np.random.randint(0, 100) p.priv_good_value = p.priv_good_sig + p.signal_1 + p.signal_2 # value of players' private goods are their signal plus two random uniform draws p.treatment = self.treatment A_players = [p for p in players if p.participant.id_in_session <= 12] B_players = [p for p in players if p.participant.id_in_session > 12] random.shuffle(A_players) random.shuffle(B_players) matrix = [A_players[0:3], A_players[3:6], A_players[6:9], A_players[9:12], B_players[0:3], B_players[3:6], B_players[6:9], B_players[9:12]] self.set_group_matrix(matrix) for p in players: if p.participant.id_in_session <= 12: p.subgroup = Constants.group_1 else: p.subgroup = Constants.group_2 class Group(BaseGroup): num_contr = models.IntegerField(initial=0) pub_good_value = models.IntegerField(initial=0) period_1_contr = models.IntegerField(initial=0) period_2_contr = models.IntegerField(initial=0) period_3_contr = models.IntegerField(initial=0) def get_pub_good_value(self): players = self.get_players() for p in players: self.pub_good_value += p.pub_good for p in players: p.pub_good_value = self.pub_good_value def get_round_contribution(self): # records number of players funding the public good in each round players = self.get_players() for p in players: if p.contr_period == 1: self.period_1_contr += 1 elif p.contr_period == 2: self.period_2_contr += 1 elif p.contr_period == 3: self.period_3_contr += 1 else: pass class Player(BasePlayer): subgroup = models.StringField() pub_good = models.IntegerField() priv_good_sig = models.IntegerField() priv_good_value = models.IntegerField() pub_good_value = models.IntegerField() signal_1 = models.IntegerField() signal_2 = models.IntegerField() contribute = models.BooleanField() contr_period = models.IntegerField(initial=0) treatment = models.IntegerField() sub_period = models.IntegerField(initial=0) project = models.StringField() voting_decision = models.StringField() other1_act = models.StringField() other2_act = models.StringField() other1_cont = models.IntegerField(initial=0) other2_cont = models.IntegerField(initial=0) round_payoff = models.IntegerField()