from typing import List from otree.api import * import numpy as np doc = """ Public Goods Leader/Picture """ class C(BaseConstants): NAME_IN_URL = 'PGLP' PLAYERS_PER_GROUP = 4 ENDOWMENT = 20 CONT_NUM = 78 EFF_FACTOR = 0.6 LEADER_PAY_FACTOR = 0.25 NUM_ROUNDS = 100 # instructions_template = 'public_goods/instructions.html' # """Amount allocated to each player""" class Subsession(BaseSubsession): End_Experiment = models.BooleanField(initial=False) def creating_session(subsession: Subsession): if subsession.round_number == 1: subsession.group_randomly() rand_rolls = np.random.randint(0, 101, 100) subsession.session.vars['rand_rolls'] = rand_rolls else: subsession.group_like_round(1) # def vars_for_admin_report(subsession: Subsession): # contributions = [ # p.contribution # for p in subsession.get_players() # if get_or_none(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)', # ) class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() total_vote_for_1 = models.IntegerField(initial=0) total_vote_for_2 = models.IntegerField(initial=0) total_vote_for_3 = models.IntegerField(initial=0) total_vote_for_4 = models.IntegerField(initial=0) new_order = list[int] punish_factor = models.FloatField(initial=0) group_punishment = models.IntegerField(initial=0) class Player(BasePlayer): contribution = models.CurrencyField( initial=0, max=Constants.endowment, doc="""The amount contributed by the player""", ) vote = models.IntegerField( label='Place your vote. You may not vote for yourself.', choices=[ [1, 'Player 1'], [2, 'Player 2'], [3, 'Player 3'], [4, 'Player 4'] ] ) vote_for_1 = models.IntegerField(initial=0) vote_for_2 = models.IntegerField(initial=0) vote_for_3 = models.IntegerField(initial=0) vote_for_4 = models.IntegerField(initial=0) # Beliefs about what P1 contributed cont_belief_p1_c0 = models.IntegerField() cont_belief_p1_c1 = models.IntegerField() cont_belief_p1_c2 = models.IntegerField() cont_belief_p1_c3 = models.IntegerField() cont_belief_p1_c4 = models.IntegerField() cont_belief_p1_c5 = models.IntegerField() cont_belief_p1_c6 = models.IntegerField() cont_belief_p1_c7 = models.IntegerField() cont_belief_p1_c8 = models.IntegerField() cont_belief_p1_c9 = models.IntegerField() cont_belief_p1_c10 = models.IntegerField() # Beliefs about what P2 contributed cont_belief_p2_c0 = models.IntegerField() cont_belief_p2_c1 = models.IntegerField() cont_belief_p2_c2 = models.IntegerField() cont_belief_p2_c3 = models.IntegerField() cont_belief_p2_c4 = models.IntegerField() cont_belief_p2_c5 = models.IntegerField() cont_belief_p2_c6 = models.IntegerField() cont_belief_p2_c7 = models.IntegerField() cont_belief_p2_c8 = models.IntegerField() cont_belief_p2_c9 = models.IntegerField() cont_belief_p2_c10 = models.IntegerField() # Beliefs about what P3 contributed cont_belief_p3_c0 = models.IntegerField() cont_belief_p3_c1 = models.IntegerField() cont_belief_p3_c2 = models.IntegerField() cont_belief_p3_c3 = models.IntegerField() cont_belief_p3_c4 = models.IntegerField() cont_belief_p3_c5 = models.IntegerField() cont_belief_p3_c6 = models.IntegerField() cont_belief_p3_c7 = models.IntegerField() cont_belief_p3_c8 = models.IntegerField() cont_belief_p3_c9 = models.IntegerField() cont_belief_p3_c10 = models.IntegerField() # Beliefs about what P4 contributed cont_belief_p4_c0 = models.IntegerField() cont_belief_p4_c1 = models.IntegerField() cont_belief_p4_c2 = models.IntegerField() cont_belief_p4_c3 = models.IntegerField() cont_belief_p4_c4 = models.IntegerField() cont_belief_p4_c5 = models.IntegerField() cont_belief_p4_c6 = models.IntegerField() cont_belief_p4_c7 = models.IntegerField() cont_belief_p4_c8 = models.IntegerField() cont_belief_p4_c9 = models.IntegerField() cont_belief_p4_c10 = models.IntegerField() punishment = models.IntegerField( initial=0, label='How many punishment points would you like to give to your group?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) punishment_cost = models.IntegerField(initial=0) total_earnings = models.IntegerField(initial=0) def vote_deconstruct(player: Player): if player.vote == 1: player.vote_for_1 = 1 else: player.vote_for_1 = 0 if player.vote == 2: player.vote_for_2 = 1 else: player.vote_for_2 = 0 if player.vote == 3: player.vote_for_3 = 1 else: player.vote_for_3 = 0 if player.vote == 4: player.vote_for_4 = 1 else: player.vote_for_4 = 0 # def contribution_max(player): # session = player.session # config = session.config # # return config['endowment'] def vote_counting(group): group.total_vote_for_1 = sum([p.vote_for_1 for p in group.get_players()]) group.total_vote_for_2 = sum([p.vote_for_2 for p in group.get_players()]) group.total_vote_for_3 = sum([p.vote_for_3 for p in group.get_players()]) group.total_vote_for_4 = sum([p.vote_for_4 for p in group.get_players()]) def set_leader(group): if (group.total_vote_for_1 > group.total_vote_for_2) and (group.total_vote_for_1 > group.total_vote_for_3) and ( group.total_vote_for_1 > group.total_vote_for_4): group.new_order = [1, 2, 3, 4] elif (group.total_vote_for_2 > group.total_vote_for_1) and (group.total_vote_for_2 > group.total_vote_for_3) and ( group.total_vote_for_2 > group.total_vote_for_4): group.new_order = [2, 1, 3, 4] elif (group.total_vote_for_3 > group.total_vote_for_1) and (group.total_vote_for_3 > group.total_vote_for_2) and ( group.total_vote_for_3 > group.total_vote_for_4): group.new_order = [3, 1, 2, 4] elif (group.total_vote_for_4 > group.total_vote_for_1) and (group.total_vote_for_4 > group.total_vote_for_2) and ( group.total_vote_for_4 > group.total_vote_for_3): group.new_order = [4, 1, 2, 3] else: if group.total_vote_for_1 == group.total_vote_for_2 == group.total_vote_for_3 == group.total_vote_for_4: group.new_order = np.random.choice([1, 2, 3, 4]) elif group.total_vote_for_1 == group.total_vote_for_2: group.new_order = np.random.choice([1, 2]) elif group.total_vote_for_1 == group.total_vote_for_3: group.new_order = np.random.choice([1, 3]) elif group.total_vote_for_1 == group.total_vote_for_4: group.new_order = np.random.choice([1, 4]) elif group.total_vote_for_2 == group.total_vote_for_3: group.new_order = np.random.choice([2, 3]) elif group.total_vote_for_2 == group.total_vote_for_4: group.new_order = np.random.choice([2, 4]) elif group.total_vote_for_3 == group.total_vote_for_4: group.new_order = np.random.choice([3, 4]) # def pun_cost(player): # if player.id_in_group == 1: # if player.punishment == 0: # player.punishment_cost = 0 # elif player.punishment == 1: # player.punishment_cost = 1 # elif player.punishment == 2: # player.punishment_cost = 2 # elif player.punishment == 3: # player.punishment_cost = 4 # elif player.punishment == 4: # player.punishment_cost = 6 # elif player.punishment == 5: # player.punishment_cost = 9 # elif player.punishment == 6: # player.punishment_cost = 12 # elif player.punishment == 7: # player.punishment_cost = 16 # elif player.punishment == 8: # player.punishment_cost = 20 # elif player.punishment == 9: # player.punishment_cost = 25 # elif player.punishment == 10: # player.punishment_cost = 30 def total_cont_calc(group): p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) p4 = group.get_player_by_id(4) group.total_contribution = p2.contribution + p3.contribution + p4.contribution def set_payoffs(group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) p4 = group.get_player_by_id(4) group.total_contribution = p2.contribution + p3.contribution + p4.contribution group.group_punishment = p1.punishment group.punish_factor = (10 - p1.punishment) / 10 group.individual_share = ( (group.total_contribution * Constants.eff_factor * (1 - Constants.leader_pay_factor)) / ( Constants.players_per_group - 1) ) for p in group.get_players(): p.payoff = ((Constants.endowment - p.contribution) + group.individual_share) * group.punish_factor if group.round_number > 1: prev_player = p.in_previous_rounds(group.round_number - 1) p.total_earnings = prev_player.total_earnings + p.payoff # def group_punishment(group: Group): # p1 = group.get_player_by_id(1) # group.group_punishment = p1.punishment def total_earnings_calc(player: Player): player.total_earnings = sum(player.payoff.in_all_rounds) # def check_roll(player): # if player.subsession.session.vars['rand_rolls'][player.subsession.round_number] > Constants.cont_num: # player.subsession.End_Experiment = True # Pages class Introduction(Page): pass class Vote(Page): form_model = 'player' form_fields = ['vote'] @staticmethod def vars_for_template(player): p1 = player.group.get_player_by_id(1) p2 = player.group.get_player_by_id(2) p3 = player.group.get_player_by_id(3) p4 = player.group.get_player_by_id(4) return dict( p1_in_previous_rounds=p1.in_previous_rounds(), p2_in_previous_rounds=p2.in_previous_rounds(), p3_in_previous_rounds=p3.in_previous_rounds(), p4_in_previous_rounds=p4.in_previous_rounds(), ) @staticmethod def is_displayed(player): return player.round_number == 1 class VotesWaitPage(WaitPage): @staticmethod def after_all_players_arrive(group): for p in group.get_players(): p.vote_deconstruct() group.vote_counting() group.set_leader() group.set_players(group.new_order) class ElectionResults(Page): @staticmethod def vars_for_template(group): return dict( votes_1=group.total_vote_for_1, votes_2=group.total_vote_for_2, votes_3=group.total_vote_for_3, votes_4=group.total_vote_for_4, winner=group.get_player_by_id(1) ) @staticmethod def is_displayed(player): return player.round_number == 1 class RollCheck(Page): @staticmethod def vars_for_template(player): return dict( roll=player.subsession.session.vars['rand_rolls'][player.subsession.round_number] ) @staticmethod def before_next_page(player, timeout_happened): if player.subsession.session.vars['rand_rolls'][player.subsession.round_number] > Constants.cont_num: player.subsession.End_Experiment = True class Belief_Elic_1(Page): form_model = 'player' form_fields = ['cont_belief_p1_c0', 'cont_belief_p1_c1', 'cont_belief_p1_c2', 'cont_belief_p1_c3', 'cont_belief_p1_c4', 'cont_belief_p1_c5', 'cont_belief_p1_c6', 'cont_belief_p1_c7', 'cont_belief_p1_c8', 'cont_belief_p1_c9', 'cont_belief_p1_c10'] @staticmethod def is_displayed(player): return player.id_in_group != 1 @staticmethod def error_message(player, values): print('values is', values) if values['cont_belief_p1_c0'] + values['cont_belief_p1_c1'] \ + values['cont_belief_p1_c2'] + values['cont_belief_p1_c3'] \ + values['cont_belief_p1_c4'] + values['cont_belief_p1_c5'] \ + values['cont_belief_p1_c6'] + values['cont_belief_p1_c7'] \ + values['cont_belief_p1_c8'] + values['cont_belief_p1_c9'] \ + values['cont_belief_p1_c10'] != 10: return 'The guesses must add up to 10' class Belief_Elic_2(Page): form_model = 'player' form_fields = ['cont_belief_p2_c0', 'cont_belief_p2_c1', 'cont_belief_p2_c2', 'cont_belief_p2_c3', 'cont_belief_p2_c4', 'cont_belief_p2_c5', 'cont_belief_p2_c6', 'cont_belief_p2_c7', 'cont_belief_p2_c8', 'cont_belief_p2_c9', 'cont_belief_p2_c10'] @staticmethod def is_displayed(player): return player.id_in_group != 2 @staticmethod def error_message(player, values): print('values is', values) if values['cont_belief_p2_c0'] + values['cont_belief_p2_c1'] \ + values['cont_belief_p2_c2'] + values['cont_belief_p2_c3'] \ + values['cont_belief_p2_c4'] + values['cont_belief_p2_c5'] \ + values['cont_belief_p2_c6'] + values['cont_belief_p2_c7'] \ + values['cont_belief_p2_c8'] + values['cont_belief_p2_c9'] \ + values['cont_belief_p2_c10'] != 10: return 'The guesses must add up to 10' class Belief_Elic_3(Page): form_model = 'player' form_fields = ['cont_belief_p3_c0', 'cont_belief_p3_c1', 'cont_belief_p3_c2', 'cont_belief_p3_c3', 'cont_belief_p3_c4', 'cont_belief_p3_c5', 'cont_belief_p3_c6', 'cont_belief_p3_c7', 'cont_belief_p3_c8', 'cont_belief_p3_c9', 'cont_belief_p3_c10'] @staticmethod def is_displayed(player): return player.id_in_group != 3 @staticmethod def error_message(player, values): print('values is', values) if values['cont_belief_p3_c0'] + values['cont_belief_p3_c1'] \ + values['cont_belief_p3_c2'] + values['cont_belief_p3_c3'] \ + values['cont_belief_p3_c4'] + values['cont_belief_p3_c5'] \ + values['cont_belief_p3_c6'] + values['cont_belief_p3_c7'] \ + values['cont_belief_p3_c8'] + values['cont_belief_p3_c9'] \ + values['cont_belief_p3_c10'] != 10: return 'The guesses must add up to 10' class Belief_Elic_4(Page): form_model = 'player' form_fields = ['cont_belief_p4_c0', 'cont_belief_p4_c1', 'cont_belief_p4_c2', 'cont_belief_p4_c3', 'cont_belief_p4_c4', 'cont_belief_p4_c5', 'cont_belief_p4_c6', 'cont_belief_p4_c7', 'cont_belief_p4_c8', 'cont_belief_p4_c9', 'cont_belief_p4_c10'] @staticmethod def is_displayed(player): return player.id_in_group != 4 @staticmethod def error_message(player, values): print('values is', values) if values['cont_belief_p4_c0'] + values['cont_belief_p4_c1'] \ + values['cont_belief_p4_c2'] + values['cont_belief_p4_c3'] \ + values['cont_belief_p4_c4'] + values['cont_belief_p4_c5'] \ + values['cont_belief_p4_c6'] + values['cont_belief_p4_c7'] \ + values['cont_belief_p4_c8'] + values['cont_belief_p4_c9'] \ + values['cont_belief_p4_c10'] != 10: return 'The guesses must add up to 10' class Punishment(Page): form_model = 'player' form_fields = ['punishment'] @staticmethod def vars_for_template(player): return dict( group_cont=player.group.total_contribution ) @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False and player.id_in_group == 1 @staticmethod def before_next_page(player, timeout_happened): if player.id_in_group == 1: if player.punishment == 0: player.punishment_cost = 0 elif player.punishment == 1: player.punishment_cost = 1 elif player.punishment == 2: player.punishment_cost = 2 elif player.punishment == 3: player.punishment_cost = 4 elif player.punishment == 4: player.punishment_cost = 6 elif player.punishment == 5: player.punishment_cost = 9 elif player.punishment == 6: player.punishment_cost = 12 elif player.punishment == 7: player.punishment_cost = 16 elif player.punishment == 8: player.punishment_cost = 20 elif player.punishment == 9: player.punishment_cost = 25 elif player.punishment == 10: player.punishment_cost = 30 class Contribute(Page): form_model = 'player' form_fields = ['contribution'] @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False and player.id_in_group != 1 class Total_Cont_Calc(WaitPage): after_all_players_arrive = total_cont_calc class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoffs body_text = "Please wait patiently." class Results(Page): @staticmethod def vars_for_template(player): # group = player.group # session = group.session p1 = player.group.get_player_by_id(1) return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=Constants.endowment - player.contribution, total_cont=player.group.total_contribution, pun_amt=player.group.group_punishment, pun_frac=1 - player.group.punish_factor, pun_cost=p1.punishment_cost, payoff=player.payoff, total_earn=player.total_earnings, ) @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False class FinalResults(Page): @staticmethod def is_displayed(player): return player.subsession.End_Experiment == True @staticmethod def before_next_page(player): prev_player = player.in_all_rounds() player.participant.vars['prev_conts'] = prev_player.contribution player.participant.vars['prev_rounds'] = prev_player.round_number page_sequence = [RollCheck, Contribute, Total_Cont_Calc, Belief_Elic_1, Belief_Elic_2, Belief_Elic_3, Belief_Elic_4, Punishment, ResultsWaitPage, Results, FinalResults]