from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import statistics from random import * doc = """ This is a one-period public goods game with 5 players. """ class Constants(BaseConstants): name_in_url = 'public_goods' players_per_group = 5 num_rounds = 1 instructions_template = 'public_goods/instructions.html' # """Amount allocated to each player""" endowment = c(20) multiplier = 0.05 catastrophe = c(26) endowment2 = c(25) class Subsession(BaseSubsession): def vars_for_admin_report(self): payoffs = sorted([p.payoff for p in self.get_players()]) return dict(payoffs=payoffs) class Group(BaseGroup): total_contribution1 = models.CurrencyField() total_contribution2 = models.CurrencyField() total_both_contributions = models.CurrencyField() individual_share = models.CurrencyField() total_pledge = models.CurrencyField() individual_share_pledge = models.CurrencyField() group_target = models.CurrencyField() threshold = models.CurrencyField() threshold_reached = models.IntegerField() no_of_club_members = models.IntegerField() no_of_non_members = models.IntegerField() no_of_punishers = models.IntegerField() no_of_non_punishers = models.IntegerField() dropout = models.LongStringField() mark1 = models.FloatField() mark2 = models.FloatField() mark3 = models.FloatField() mark4 = models.FloatField() mark5 = models.FloatField() def set_payoffs(self): self.total_contribution1 = sum([p.contribution1 for p in self.get_players()]) self.total_contribution2 = sum([p.contribution2 for p in self.get_players()]) self.total_both_contributions = (self.total_contribution1 + self.total_contribution2) self.individual_share = ( self.total_both_contributions * Constants.multiplier) for p in self.get_players(): p.contribution_sum = (p.contribution1 + p.contribution2) if self.total_both_contributions >= self.threshold: p.payoff = Constants.endowment + Constants.endowment2 - ( p.contribution1 + p.contribution2) + self.individual_share else: p.payoff = Constants.endowment + Constants.endowment2 - ( p.contribution1 + p.contribution2) + self.individual_share - Constants.catastrophe def count_no_of_members(self): self.no_of_club_members = sum(p.club for p in self.get_players()) self.no_of_non_members = Constants.players_per_group - self.no_of_club_members def count_no_of_punishers(self): self.no_of_punishers = sum(p.punish == True for p in self.get_players()) self.no_of_non_punishers = self.no_of_non_members - self.no_of_punishers def club_exists(self): return self.no_of_club_members > 1 def dropouts(self): for p in self.get_players(): str(self.participant.vars) def set_contribution_sum_club(self): for p in self.get_players(): if p.club == True and self.no_of_club_members > 1: p.contribution_sum = c(20) else: p.contribution_sum = (p.contribution1 + p.contribution2) def set_punish_amounts(self): for p in self.get_players(): p.receives_through_club = (self.no_of_non_members * c(1.5)) p.pays_to_punishers = - (self.no_of_punishers * c(1.0)) p.pays_to_club = - (self.no_of_club_members * c(2.0)) p.receives_through_punishment = (self.no_of_club_members * c(0.75)) def set_payoffs_club(self): self.total_both_contributions = sum([p.contribution_sum for p in self.get_players()]) self.individual_share = ( self.total_both_contributions * Constants.multiplier) print('group.total_both_contributions is', self.total_both_contributions) print('individual share:', self.individual_share) for p in self.get_players(): if self.total_both_contributions >= self.threshold and p.club == True and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share + ( self.no_of_punishers * c(0.5)) + (self.no_of_non_punishers * c(1.5)) elif self.total_both_contributions >= self.threshold and p.club == False and p.punish == True and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share - ( self.no_of_club_members * c(1.25)) elif self.total_both_contributions >= self.threshold and p.club == False and p.punish == False and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share - ( self.no_of_club_members * c(2)) elif self.total_both_contributions < self.threshold and p.club == True and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share + ( self.no_of_punishers * c(0.5)) + (self.no_of_non_punishers * c(1.5)) - Constants.catastrophe elif self.total_both_contributions < self.threshold and p.club == False and p.punish == True and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share - ( self.no_of_club_members * c(1.25)) - Constants.catastrophe elif self.total_both_contributions < self.threshold and p.club == False and p.punish == False and self.club_exists() == True: p.payoff = Constants.endowment + Constants.endowment2 - p.contribution_sum + self.individual_share - ( self.no_of_club_members * c(2)) - Constants.catastrophe elif self.total_both_contributions >= self.threshold and self.club_exists() == False: p.payoff = Constants.endowment + Constants.endowment2 - ( p.contribution1 + p.contribution2) + self.individual_share elif self.total_both_contributions < self.threshold and self.club_exists() == False: p.payoff = Constants.endowment + Constants.endowment2 - ( p.contribution1 + p.contribution2) + self.individual_share - Constants.catastrophe print('payoff:', p.payoff) def set_contribution1_payoff(self): self.total_contribution1 = sum([p.contribution1 for p in self.get_players()]) def set_real_payoff(self): for p in self.get_players(): p.real_payoff = round(float(p.payoff) * 0.25, 2) def is_reached(self): return self.total_both_contributions >= self.threshold def set_pledge_payoffs(self): self.total_pledge = sum([p.pledge for p in self.get_players()]) self.individual_share_pledge = (self.total_pledge * Constants.multiplier / Constants.players_per_group) def set_group_targets(self): self.group_target = statistics.median([p.target for p in self.get_players()]) def set_threshold(self): self.threshold = c(randint(50, 100)) def set_marks(self): self.mark1 = round(sum(p.mp1 for p in self.get_players()) / Constants.players_per_group, 2) self.mark2 = round(sum(p.mp2 for p in self.get_players()) / Constants.players_per_group, 2) self.mark3 = round(sum(p.mp3 for p in self.get_players()) / Constants.players_per_group, 2) self.mark4 = round(sum(p.mp4 for p in self.get_players()) / Constants.players_per_group, 2) self.mark5 = round(sum(p.mp5 for p in self.get_players()) / Constants.players_per_group, 2) class Player(BasePlayer): color = models.StringField() real_payoff = models.FloatField() contribution1 = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", label="Wie viel möchten Sie zum Projekt beitragen (0-20 Cashcoins)?" ) contribution_sum = models.CurrencyField() contribution_sum_club = models.CurrencyField() contribution2 = models.CurrencyField( min=0, label="Wie viel möchten Sie (zusätzlich zu Ihrem 1. Beitrag) zum Projekt beitragen?") def contribution2_max(self): return Group.contribution_limit pledge = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount pledged by the player""", label="Ihre Ankündigung (0-20 Cashcoins):" ) target = models.CurrencyField( min=0, max=Constants.endowment * Constants.players_per_group, doc="""Das angegebene Gruppenziel von jedem Spieler""", label="Was schlagen Sie als Gruppenziel vor (0-100 Cashcoins)?" ) email = models.StringField(blank=True, label="E-Mailadresse:") notes = models.LongStringField(blank=True, label="Haben Sie Anmerkungen zum Experiment? Dann hinterlassen Sie diese bitte hier:") receives_through_club = models.CurrencyField() pays_to_punishers = models.CurrencyField() pays_to_club = models.CurrencyField() receives_through_punishment = models.CurrencyField() def make_field(label): return models.IntegerField( choices=[1, 2, 3, 4, 5], label=label, widget=widgets.RadioSelect, ) q1 = make_field('Ich war im Allgemeinen zufrieden mit dem Endergebnis.') q2 = make_field('Ich wünsche mir, ich hätte einen anderen Beitrag beigesteuert.') q3 = make_field('Ich habe den Eindruck, dass die anderen Spieler:innen mein Vertrauen in sie missbraucht haben.') q4 = make_field('Ich habe den Eindruck, dass ich das Vertrauen der anderen Spieler:innen in mich missbraucht habe.') q5 = make_field('Das Gruppenziel war hilfreich.') q6 = make_field('Der Austausch der Ankündigungen war hilfreich.') q7 = make_field('Ich würde von mir behaupten, dass ich im Allgemeinen anderen Menschen vertraue.') q8c = make_field('Die Möglichkeit einer Clubgründung war hilfreich.') q8r = make_field('Die gegenseitige Bewertung war hilfreich.') def give_mark(label): return models.IntegerField( choices=[1, 2, 3, 4, 5, 6], label=label, widget=widgets.RadioSelectHorizontal, ) mp1 = give_mark('Welche Note vergeben Sie an Player 1') mp2 = give_mark('Welche Note vergeben Sie an Player 2') mp3 = give_mark('Welche Note vergeben Sie an Player 3') mp4 = give_mark('Welche Note vergeben Sie an Player 4') mp5 = give_mark('Welche Note vergeben Sie an Player 5') club = models.BooleanField( choices=[[True, 'Ja, ich trete bei und investiere automatisch alle meine verbliebenen Projektmittel. Ich ' 'bestrafe alle Nicht-Mitglieder. Diese müssen 2 Cashcoins pro Clubmitglied abgeben.' ' Bei mir kommen 1,50 Cashcoins von jedem Nicht-Mitglied an.' ' Wenn ein Nicht-Mitglied zurückstraft, muss ich gleichzeitig aber auch 1 Cashcoin' ' Basiskapital abgeben.'], [False, 'Nein, ich möchte dem Club nicht beitreten. Ich werde selbst ' 'entscheiden, wie viel ich noch zusätzlich zu meinem ersten Beitrag' ' investiere. Ich akzeptiere, ' 'dass ich, falls ein Club ohne mich ensteht, 2 Cashcoins an ' ' jedes Clubmitglied verliere.' ' Ich werde im nächsten Schritt entscheiden, ' ' ob ich zurückstrafe und damit jedes Clubmitglied 1 Cashcoin Strafe' ' zahlen lasse. Bei meiner Gegenstrafe erhalte ich 0,75 Cashcoins' ' pro Clubmitglied.']], label='Wollen Sie dem Club beitreten?', widget=widgets.RadioSelect, ) punish = models.BooleanField( choices=[[True, 'Ja, ich verhänge eine Gegenstrafe von 1 Cashcoin auf jedes Clubmitglied. Ich verliere zwar 2 Cashcoins an jedes Clubmitglied, aber ' ' erhalte durch meine Gegenstrafe auch 0,75 Cashcoins pro Club-Mitglied.'], [False, 'Nein, ich strafe nicht zurück. Ich verliere ' 'also 2 Cashcoins an jedes Clubmitglied.']], label='Sie treten dem Club nicht bei. Wollen Sie zurückstrafen?', widget=widgets.RadioSelect, ) def is_member(self): return self.club == True def is_punisher(self): return self.punish == True def is_non_punisher(self): return self.punish == False def is_non_member_and_non_punisher(self): return self.club == False and self.punish == False