from otree.api import * c = cu doc = '' class C(BaseConstants): NAME_IN_URL = 'public_good_kraemer' PLAYERS_PER_GROUP = 3 NUM_ROUNDS = 3 REV_MULT_L = (0.8, 1, 1.25) C_INTE_L = (0.01, 0.33, 0.67, 1) REV_MULT_INT = 1 C_INTE_INT = 0.333 TREATMENTS = ('EQ_C1', 'EQ_C2', 'EQ_C3', 'EQ_C4', 'INEQ_C2') ENDOWMENT = 100 class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): session = subsession.session import random if subsession.round_number == 1: session.iterator = random.choice([0,1,2,3,4]) # session.iterator= 0 def group_by_arrival_time_method(subsession: Subsession, waiting_players): if len(waiting_players) >= 3: return waiting_players[:3] for player in waiting_players: if waiting_too_long(player): player.is_surplus=True return [player] class Group(BaseGroup): treatment_id = models.StringField() c_inten_group = models.FloatField() def set_profit(group: Group): players=group.get_players() for player in players: if player.id_in_group == 1: rival1 = group.get_player_by_id(2) rival2 = group.get_player_by_id(3) elif player.id_in_group == 2: rival1 = group.get_player_by_id(3) rival2 = group.get_player_by_id(1) elif player.id_in_group == 3: rival1 = group.get_player_by_id(1) rival2 = group.get_player_by_id(2) #int_values player.received_data1 = rival1.shared_data2 player.received_data2 = rival2.shared_data1 player.cross_share1 = rival1.shared_data1 player.cross_share2 = rival2.shared_data2 #float_values player.s_self = player.received_data1 / 100 + player.received_data2 / 100 player.s_opp1 = player.shared_data1 / 100 + player.cross_share2 / 100 player.s_opp2 = player.shared_data2 / 100 + player.cross_share1 / 100 #rev_mult player.rival1_rev_mult = rival1.revenue_multiplier player.rival2_rev_mult = rival2.revenue_multiplier #profit player.profit = player.revenue_multiplier * C.ENDOWMENT * (1 + player.s_self) - group.c_inten_group / (C.PLAYERS_PER_GROUP - 1) * (player.rival1_rev_mult * C.ENDOWMENT * (1 + player.s_opp1) + player.rival2_rev_mult * C.ENDOWMENT * (1 + player.s_opp2)) #rival profit player.rival1_profit = player.rival1_rev_mult * C.ENDOWMENT * (1 + player.s_opp1) - group.c_inten_group / (C.PLAYERS_PER_GROUP - 1) * (player.revenue_multiplier * C.ENDOWMENT * (1 + player.s_self) + player.rival2_rev_mult * C.ENDOWMENT * (1 + player.s_opp2)) player.rival2_profit = player.rival2_rev_mult * C.ENDOWMENT * (1 + player.s_opp2) - group.c_inten_group / (C.PLAYERS_PER_GROUP - 1) * (player.rival1_rev_mult * C.ENDOWMENT * (1 + player.s_opp1) + player.revenue_multiplier * C.ENDOWMENT * (1 + player.s_self)) def set_treatment(group: Group): session = group.session subsession = group.subsession #assign the values to players based on treatment and role p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) if subsession.round_number == 1: if session.iterator == 0: group.treatment_id = C.TREATMENTS[0] group.c_inten_group = C.C_INTE_L[0] p1.revenue_multiplier = 1 p2.revenue_multiplier = 1 p3.revenue_multiplier = 1 session.iterator += 1 elif session.iterator == 1: group.treatment_id = C.TREATMENTS[1] group.c_inten_group = C.C_INTE_L[1] p1.revenue_multiplier = 1 p2.revenue_multiplier = 1 p3.revenue_multiplier = 1 session.iterator += 1 elif session.iterator == 2: group.treatment_id = C.TREATMENTS[2] group.c_inten_group = C.C_INTE_L[2] p1.revenue_multiplier = 1 p2.revenue_multiplier = 1 p3.revenue_multiplier = 1 session.iterator += 1 elif session.iterator == 3: group.treatment_id = C.TREATMENTS[3] group.c_inten_group = C.C_INTE_L[3] p1.revenue_multiplier = 1 p2.revenue_multiplier = 1 p3.revenue_multiplier = 1 session.iterator += 1 else: group.treatment_id = C.TREATMENTS[4] group.c_inten_group = C.C_INTE_L[1] p1.revenue_multiplier = 0.8 #p2.revenue_multiplier p1.rival1_rev_mult = 1 #p3.revenue_multiplier p1.rival2_rev_mult = 1.25 p2.revenue_multiplier = 1 #p3.revenue_multiplier p2.rival1_rev_mult = 1.25 #p1.revenue_multiplier p2.rival2_rev_mult = 0.8 p3.revenue_multiplier = 1.25 #p1.revenue_multiplier p3.rival1_rev_mult = 0.8 #p2.revenue_multiplier p3.rival2_rev_mult = 1 session.iterator = 0 def save_load_prev_round(group: Group): session = group.session subsession = group.subsession p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) if subsession.round_number > 1: prev_group = group.in_round(group.round_number - 1) group.treatment_id = prev_group.treatment_id group.c_inten_group = prev_group.c_inten_group prev_p1 = p1.in_round(p1.round_number - 1) prev_p2 = p2.in_round(p2.round_number - 1) prev_p3 = p3.in_round(p3.round_number - 1) p1.revenue_multiplier = prev_p1.revenue_multiplier p1.rival1_rev_mult = prev_p1.rival1_rev_mult p1.rival2_rev_mult = prev_p1.rival2_rev_mult p2.revenue_multiplier = prev_p2.revenue_multiplier p2.rival1_rev_mult = prev_p2.rival1_rev_mult p2.rival2_rev_mult = prev_p2.rival2_rev_mult p3.revenue_multiplier = prev_p3.revenue_multiplier p3.rival1_rev_mult = prev_p3.rival1_rev_mult p3.rival2_rev_mult = prev_p3.rival2_rev_mult def set_payoff(group: Group): import random # Iterate through players in the group for player in group.get_players(): # Fetch the player's profits from the previous rounds previous_profits = [p.profit for p in player.in_all_rounds()] # Exclude the first and last profit excluded_profits = previous_profits[1:-1] # Select one of the remaining profits at random selected_profit = random.choice(excluded_profits) # Assign the selected profit as the player's payoff player.payoff = selected_profit / 10 if player.payoff > 0: player.participant.payoff = player.payoff else: player.participant.payoff = 0 class Player(BasePlayer): shared_data1 = models.IntegerField(label='The amount of data (in %) you share with Rival 1:', max=100, min=0) shared_data2 = models.IntegerField(label='The amount of data (in %) you share with Rival 2:', max=100, min=0) received_data1 = models.IntegerField() received_data2 = models.IntegerField() cross_share1 = models.IntegerField() cross_share2 = models.IntegerField() s_self = models.FloatField() s_opp1 = models.FloatField() s_opp2 = models.FloatField() revenue_multiplier = models.FloatField(initial=C.REV_MULT_INT) rival1_rev_mult = models.FloatField(initial=C.REV_MULT_INT) rival2_rev_mult = models.FloatField(initial=C.REV_MULT_INT) rival1_profit = models.CurrencyField() rival2_profit = models.CurrencyField() profit = models.CurrencyField() is_surplus = models.BooleanField(initial=False) def prev_player(player: Player): if player.round_number > 1: prev_player = player.in_round(player.round_number - 1) return prev_player else: return player def waiting_too_long(player: Player): participant = player.participant participant = player.participant import time return time.time() - participant.wait_page_arrival > 5*60 class Grouping(WaitPage): group_by_arrival_time = True title_text = 'Grouping Players' body_text = 'Wait until other participants reach this page to be grouped together' @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Surplus(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return player.is_surplus @staticmethod def vars_for_template(player: Player): participant = player.participant # Access the stored payoff from the participant vars selected_payoff = player.participant.payoff # Access the PARTICIPATION_FEE from Constants participation_fee = 5 # Calculate the sum of PARTICIPATION_FEE and selected_payoff total_payoff = player.participant.payoff_plus_participation_fee() return { 'selected_payoff': selected_payoff, 'participation_fee': participation_fee, 'total_payoff': total_payoff, } @staticmethod def js_vars(player: Player): participant = player.participant return dict(p_payoff = player.participant.payoff_plus_participation_fee()) class Treatment_Allocation(WaitPage): after_all_players_arrive = set_treatment title_text = 'Treatment Allocation' body_text = 'Allocating a treatment to your group' @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Save_Load_Prev_round(WaitPage): after_all_players_arrive = save_load_prev_round title_text = 'Saving and loading previous round' body_text = 'Please wait until all participants leave the results page.' @staticmethod def is_displayed(player: Player): return player.round_number > 1 class Information(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): session = player.session subsession = player.subsession return player.subsession.round_number == 1 class Sharing(Page): form_model = 'player' form_fields = ['shared_data1', 'shared_data2'] @staticmethod def js_vars(player: Player): group = player.group if player.round_number > 1: return dict( c_inten=group.c_inten_group, p_r_mult=player.revenue_multiplier, r1_r_mult=player.rival1_rev_mult, r2_r_mult=player.rival2_rev_mult, no_players=C.PLAYERS_PER_GROUP, p_s1=prev_player(player).shared_data1, p_s2=prev_player(player).shared_data2, p_r1=prev_player(player).received_data1, p_r2=prev_player(player).received_data2, p_c1=prev_player(player).cross_share1, p_c2=prev_player(player).cross_share2 ) else: return dict( c_inten=group.c_inten_group, p_r_mult=player.revenue_multiplier, r1_r_mult=player.rival1_rev_mult, r2_r_mult=player.rival2_rev_mult, no_players=C.PLAYERS_PER_GROUP, p_s1=0, p_s2=0, p_r1=0, p_r2=0, p_c1=0, p_c2=0 ) class Profit_Calculation(WaitPage): after_all_players_arrive = set_profit title_text = 'Calculating Profit' body_text = 'Waiting for other participants to make their decision.' class Results(Page): form_model = 'player' class Payoff_Calculation(WaitPage): after_all_players_arrive = set_payoff title_text = 'Payoff Calculation' body_text = 'Calculating your final payoff' @staticmethod def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS page_sequence = [Grouping, Surplus, Treatment_Allocation, Save_Load_Prev_round, Information, Sharing, Profit_Calculation, Results, Payoff_Calculation]