from typing import List from otree.api import * import numpy as np doc = """ Public Goods Leader/No Picture """ class C(BaseConstants): NAME_IN_URL = 'PGLNP' PLAYERS_PER_GROUP = 5 ENDOWMENT = 10 CONT_NUM = 78 EFF_FACTOR = 2.4 LEADER_PAY_FACTOR = 0.25 NUM_ROUNDS = 100 BELIEF_REWARD = 0.25 POINT_EXRATE = 0.15 # instructions_template = 'public_goods/instructions.html' # """Amount allocated to each player""" class Subsession(BaseSubsession): End_Experiment = models.BooleanField(initial=False) End_Experiment_round = models.IntegerField() Belief_pay_round = models.IntegerField() 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) class Group(BaseGroup): total_contribution = models.IntegerField() individual_share = models.FloatField() 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] # PUNISHMENTS punish_factor = models.FloatField(initial=0) group_punishment = models.IntegerField(initial=0) #DO I NEED TO TAKE THIS OUT OF GROUP CLASS? WOULD IT NEED TO BE PLACED ELSEWHERE? - It will no longer be relevant anymore current_payoff_sum = models.FloatField(initial=0) reward_factor = models.FloatField(initial=0) group_reward = models.IntegerField(initial=0) class Player(BasePlayer): contribution = models.IntegerField( initial=0, min=0, max=C.ENDOWMENT, doc="""The amount contributed by the player""", ) p2_punishment = models.IntegerField( initial=0, label='How many punishment points would you like to give to Player 2?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p3_punishment = models.IntegerField( initial=0, label='How many punishment points would you like to give to Player 3?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p4_punishment = models.IntegerField( initial=0, label='How many punishment points would you like to give to Player 4?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p5_punishment = models.IntegerField( initial=0, label='How many punishment points would you like to give to Player 5?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p2_reward = models.IntegerField( initial=0, label='How many reward points would you like to give to Player 2?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p3_reward = models.IntegerField( initial=0, label='How many reward points would you like to give to Player 3?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p4_reward = models.IntegerField( initial=0, label='How many reward points would you like to give to Player 4?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) p5_reward = models.IntegerField( initial=0, label='How many reward points would you like to give to Player 5?', choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ) current_payoff = models.FloatField(initial=0) punishment_cost = models.FloatField(initial=0) reward_cost = models.FloatField(initial=0) total_earnings = models.CurrencyField(initial=0) p2_punish_factor = models.FloatField(initial=0) p3_punish_factor = models.FloatField(initial=0) p4_punish_factor = models.FloatField(initial=0) p5_punish_factor = models.FloatField(initial=0) p2_reward_factor = models.FloatField(initial=0) p3_reward_factor = models.FloatField(initial=0) p4_reward_factor = models.FloatField(initial=0) p5_reward_factor = models.FloatField(initial=0) 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) p5 = group.get_player_by_id(5) group.total_contribution = p2.contribution + p3.contribution + p4.contribution + p5.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) p5 = group.get_player_by_id(5) group.total_contribution = p2.contribution + p3.contribution + p4.contribution + p5.contribution p2.p2_punish_factor = (10 - p1.p2_punishment) / 10 p3.p3_punish_factor = (10 - p1.p3_punishment) / 10 p4.p4_punish_factor = (10 - p1.p4_punishment) / 10 p5.p5_punish_factor = (10 - p1.p5_punishment) / 10 p2.p2_reward_factor = (10 + p1.p2_reward) / 10 p3.p3_reward_factor = (10 + p1.p3_reward) / 10 p4.p4_reward_factor = (10 + p1.p4_reward) / 10 p5.p5_reward_factor = (10 + p1.p5_reward) / 10 group.individual_share = (group.total_contribution * C.EFF_FACTOR / (C.PLAYERS_PER_GROUP - 1)) for p in group.get_players(): if p.id_in_group == 2: p.payoff = ((C.ENDOWMENT - p.contribution) + group.individual_share) * p2.p2_punish_factor * p2.p2_reward_factor if p.id_in_group == 3: p.payoff = ((C.ENDOWMENT - p.contribution) + group.individual_share) * p3.p3_punish_factor * p3.p3_reward_factor if p.id_in_group == 4: p.payoff = ((C.ENDOWMENT - p.contribution) + group.individual_share) * p4.p4_punish_factor * p4.p4_reward_factor if p.id_in_group == 5: p.payoff = ((C.ENDOWMENT - p.contribution) + group.individual_share) * p5.p5_punish_factor * p5.p5_reward_factor if group.round_number > 1: prev_player = p.in_round(group.round_number - 1) p.total_earnings = prev_player.total_earnings + p.payoff else: p.total_earnings = p.payoff for p in group.get_players(): if p.id_in_group == 1: p.payoff = C.LEADER_PAY_FACTOR * (p2.payoff + p3.payoff + p4.payoff + p5.payoff) - p.punishment_cost - p.reward_cost if group.round_number > 1: prev_player = p.in_round(group.round_number - 1) p.total_earnings = prev_player.total_earnings + p.payoff else: p.total_earnings = p.payoff def sum_current_payoffs(group): p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) p4 = group.get_player_by_id(4) p5 = group.get_player_by_id(5) group.total_contribution = p2.contribution + p3.contribution + p4.contribution + p5.contribution group.individual_share = (group.total_contribution * C.EFF_FACTOR / (C.PLAYERS_PER_GROUP - 1)) for p in group.get_players(): if p != 1: p.current_payoff = ((C.ENDOWMENT - p.contribution) + group.individual_share) group.current_payoff_sum = p2.current_payoff + p3.current_payoff + p4.current_payoff + p5.current_payoff def total_earnings_calc(player: Player): player.total_earnings = sum(player.payoff.in_all_rounds) # Pages class Introduction(Page): pass class RollCheck(Page): @staticmethod def is_displayed(player): return player.subsession.round_number != 1 @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] > C.CONT_NUM: player.subsession.End_Experiment = True player.subsession.End_Experiment_round = player.subsession.round_number player.subsession.Belief_pay_round = np.random.randint(1, player.subsession.End_Experiment_round + 1) class Punishment(Page): form_model = 'player' form_fields = ['p2_punishment', 'p3_punishment', 'p4_punishment', 'p5_punishment', 'p2_reward', 'p3_reward', 'p4_reward', 'p5_reward'] @staticmethod def vars_for_template(player): p2 = player.group.get_player_by_id(2) p3 = player.group.get_player_by_id(3) p4 = player.group.get_player_by_id(4) p5 = player.group.get_player_by_id(5) return dict( p2_cont=p2.contribution, p3_cont=p3.contribution, p4_cont=p4.contribution, p5_cont=p5.contribution, group_cont=player.group.total_contribution, payoff_sum=player.group.current_payoff_sum, ) @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False and player.id_in_group == 1 # WHAT IS THE PURPOSE OF THIS FUNCTION AND WHY IS IT DUPLICATED? ALSO WHY DOES IT COPY PRIOR FUNCTION? - This was a result of me learning the "new" oTree. Several things changed from how it used to work and this was one of the functions that no longer serves a purpose. @staticmethod def before_next_page(player, timeout_happened): p1 = player.group.get_player_by_id(1) player_punishment_id_list = [p1.p2_punishment, p1.p3_punishment, p1.p4_punishment, p1.p5_punishment] if player.id_in_group == 1: for x in range(4): if player_punishment_id_list[x] == 0: player.punishment_cost = player.punishment_cost + 0 elif player_punishment_id_list[x] == 1: player.punishment_cost = player.punishment_cost + 0.5 elif player_punishment_id_list[x] == 2: player.punishment_cost = player.punishment_cost + 1 elif player_punishment_id_list[x] == 3: player.punishment_cost = player.punishment_cost + 2 elif player_punishment_id_list[x] == 4: player.punishment_cost = player.punishment_cost + 3 elif player_punishment_id_list[x] == 5: player.punishment_cost = player.punishment_cost + 4.5 elif player_punishment_id_list[x] == 6: player.punishment_cost = player.punishment_cost + 6 elif player_punishment_id_list[x] == 7: player.punishment_cost = player.punishment_cost + 8 elif player_punishment_id_list[x] == 8: player.punishment_cost = player.punishment_cost + 10 elif player_punishment_id_list[x] == 9: player.punishment_cost = player.punishment_cost + 12.5 elif player_punishment_id_list[x] == 10: player.punishment_cost = player.punishment_cost + 15 player_reward_id_list = [p1.p2_reward, p1.p3_reward, p1.p4_reward, p1.p5_reward] if player.id_in_group == 1: for x in range(4): if player_reward_id_list[x] == 0: player.reward_cost = player.reward_cost + 0 elif player_reward_id_list[x] == 1: player.reward_cost = player.reward_cost + 0.5 elif player_reward_id_list[x] == 2: player.reward_cost = player.reward_cost + 1 elif player_reward_id_list[x] == 3: player.reward_cost = player.reward_cost + 2 elif player_reward_id_list[x] == 4: player.reward_cost = player.reward_cost + 3 elif player_reward_id_list[x] == 5: player.reward_cost = player.reward_cost + 4.5 elif player_reward_id_list[x] == 6: player.reward_cost = player.reward_cost + 6 elif player_reward_id_list[x] == 7: player.reward_cost = player.reward_cost + 8 elif player_reward_id_list[x] == 8: player.reward_cost = player.reward_cost + 10 elif player_reward_id_list[x] == 9: player.reward_cost = player.reward_cost + 12.5 elif player_reward_id_list[x] == 10: player.reward_cost = player.reward_cost + 15 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 @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False class ResultsWaitPage(WaitPage): after_all_players_arrive = 'set_payoffs' body_text = "Please wait patiently." @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False class Results(Page): @staticmethod def vars_for_template(player): # group = player.group # session = group.session 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) p5 = player.group.get_player_by_id(5) if player.id_in_group == 1: return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=C.ENDOWMENT - player.contribution, total_cont=player.group.total_contribution, pun_amt_p2=round(p1.p2_punishment, 1), pun_amt_p3=round(p1.p3_punishment, 1), pun_amt_p4=round(p1.p4_punishment, 1), pun_amt_p5=round(p1.p5_punishment, 1), rew_amt_p2=round(p1.p2_reward, 1), rew_amt_p3=round(p1.p3_reward, 1), rew_amt_p4=round(p1.p4_reward, 1), rew_amt_p5=round(p1.p5_reward, 1), pun_frac_p2=round(1 - p2.p2_punish_factor, 1), pun_frac_p3=round(1 - p3.p3_punish_factor, 1), pun_frac_p4=round(1 - p4.p4_punish_factor, 1), pun_frac_p5=round(1 - p5.p5_punish_factor, 1), rew_frac_p2=round(p2.p2_reward_factor, 1), rew_frac_p3=round(p3.p3_reward_factor, 1), rew_frac_p4=round(p4.p4_reward_factor, 1), rew_frac_p5=round(p5.p5_reward_factor, 1), pun_cost=p1.punishment_cost, rew_cost=p1.reward_cost, payoff=round(player.payoff, 2), total_earn=round(player.total_earnings, 2), ) if player.id_in_group == 2: return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=C.ENDOWMENT - player.contribution, total_cont=player.group.total_contribution, pun_amt=round(p1.p2_punishment,1), rew_amt=round(p1.p2_reward, 1), pun_frac=round(1 - p2.p2_punish_factor,1), rew_frac=round(p2.p2_reward_factor,1), pun_cost=p1.punishment_cost, rew_cost=p1.reward_cost, payoff=round(player.payoff,2), total_earn=round(player.total_earnings,2), ) if player.id_in_group == 3: return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=C.ENDOWMENT - player.contribution, total_cont=player.group.total_contribution, pun_amt=round(p1.p3_punishment,1), rew_amt=round(p1.p3_reward, 1), pun_frac=round(1 - p3.p3_punish_factor,1), rew_frac=round(p3.p3_reward_factor,1), pun_cost=p1.punishment_cost, rew_cost=p1.reward_cost, payoff=round(player.payoff,2), total_earn=round(player.total_earnings,2), ) if player.id_in_group == 4: return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=C.ENDOWMENT - player.contribution, total_cont=player.group.total_contribution, pun_amt=round(p1.p4_punishment,1), rew_amt=round(p1.p4_reward, 1), pun_frac=round(1 - p4.p4_punish_factor,1), rew_frac=round(p4.p4_reward_factor,1), pun_cost=p1.punishment_cost, rew_cost=p1.reward_cost, payoff=round(player.payoff,2), total_earn=round(player.total_earnings,2), ) if player.id_in_group == 5: return dict( ID=player.id_in_group, cont=player.contribution, priv_cont=C.ENDOWMENT - player.contribution, total_cont=player.group.total_contribution, pun_amt=round(p1.p5_punishment,1), rew_amt=round(p1.p5_reward, 1), pun_frac=round(1 - p5.p5_punish_factor,1), rew_frac=round(p5.p5_reward_factor,1), pun_cost=p1.punishment_cost, rew_cost=p1.reward_cost, payoff=round(player.payoff,2), total_earn=round(player.total_earnings,2), ) @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False class Current_Payoffs_Calc(WaitPage): after_all_players_arrive = 'sum_current_payoffs' @staticmethod def is_displayed(player): return player.subsession.End_Experiment == False # class Belief_Payoffs(WaitPage): # # @staticmethod # def is_displayed(player): # return player.subsession.End_Experiment == True # # after_all_players_arrive = 'elicitation_final_payoff' class FinalResults(Page): @staticmethod def is_displayed(player): return player.subsession.End_Experiment == True @staticmethod def before_next_page(player, timeout_happened): prev_player = player.in_all_rounds() player.participant.vars['prev_conts'] = prev_player.contribution player.participant.vars['prev_rounds'] = prev_player.round_number @staticmethod def vars_for_template(player): return dict( total_earn=round(player.total_earnings*C.POINT_EXRATE,2), show_up_payment=round(7,2), exp_payment=round(player.total_earnings*C.POINT_EXRATE+player.belief_payoff+7,2), ) page_sequence = [RollCheck, Contribute, Total_Cont_Calc, Current_Payoffs_Calc, Punishment, ResultsWaitPage, Results, FinalResults]