from otree.api import * c = cu doc = "\nEach player decides if to free ride or to volunteer from which all will\nbenefit.\nSee: Diekmann, A. (1985). Volunteer's dilemma. Journal of Conflict\nResolution, 605-610.\n" class C(BaseConstants): NAME_IN_URL = 'InvestmentDecision' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 2 NUM_OTHER_PLAYERS = 1 REWARD_NONINVESTOR = 20 REWARD_INVESTOR = 15 REWARD_FAIL = 10 INSTRUCTIONS_TEMPLATE = 'InvestmentDecision/instructions.html' class Subsession(BaseSubsession): investor_payoff = models.FloatField() def creating_session(subsession: Subsession): session = subsession.session import random subsession.group_randomly() subsession.investor_payoff = random.randint(9,20) print(subsession.get_group_matrix()) class Group(BaseGroup): has_volunteer = models.BooleanField(initial=False) class Player(BasePlayer): is_volunteer = models.BooleanField(initial=False) volunteer_id = models.IntegerField() has_volunteer = models.BooleanField(initial=False) NC_Taste = models.IntegerField(choices=[[1, '1. Very unlikely '], [2, '2. Unlikely '], [3, '3. Not sure '], [4, '4. Likely '], [5, '5. Very likely ']], label='Admitting that your tastes are different from those of your friends. ', widget=widgets.RadioSelectHorizontal) NC_Argue = models.IntegerField(choices=[[1, '1. Very unlikely'], [2, '2. Unlikely '], [3, '3. Not sure'], [4, '4. Likely'], [5, '5. Very likely']], label='Arguing with a friend who has a very different opinion on an issue. ', widget=widgets.RadioSelectHorizontal) NC_Speak = models.IntegerField(choices=[[1, '1. Very unlikely'], [2, '2. Unlikely'], [3, '3. Not sure'], [4, '4. Likely'], [5, '5. Very likely']], label='Speaking your mind about an unpopular issue at a social occasion.\u2028', widget=widgets.RadioSelectHorizontal) investor_payoff = models.FloatField() time_spent = models.FloatField(blank=True) def live_method(player: Player, data): group = player.group participant = player.participant group = player.group if group.has_volunteer: return if data.get('volunteer'): # If the participant decides to invest if not group.has_volunteer: # Check if this is the first investment in the group group.has_volunteer = True player.is_volunteer = True # Mark the investing player # Record the time spent for the investing player player.time_spent = data['timeSpent'] # Update time_spent for all players in the group to ensure consistency for p in player.get_others_in_group(): p.time_spent = player.time_spent p.is_volunteer = False # Notify all clients to proceed to the next page # This assumes you have a mechanism to broadcast to all clients return {0: dict(finished=True, timeSpent=player.time_spent)} # You'll need to adjust this for actual broadcasting else: # If there's already a volunteer, synchronize the time_spent for latecomers # This part may need adjustment based on your application's flow return def get_partners(player: Player): group = player.group return player.get_others_in_group() def set_payoffs(player: Player): session = player.session subsession = player.subsession group = player.group player.investor_payoff = subsession.investor_payoff if group.has_volunteer: player.has_volunteer = True if player.is_volunteer == True: player.payoff = subsession.investor_payoff else: player.payoff = C.REWARD_NONINVESTOR else: player.payoff = C.REWARD_FAIL for p in player.get_others_in_group(): p.payoff = C.REWARD_FAIL def get_all_rounds(player: Player): all_rounds = player.in_all_rounds() return all_rounds class DisplayInfo(Page): form_model = 'player' @staticmethod def vars_for_template(player: Player): partners = get_partners(player) payoff = set_payoffs(player) return dict(partners = partners, payoff = payoff) class InfoWait(WaitPage): wait_for_all_groups = True class Decision(Page): form_model = 'player' form_fields = ['time_spent'] timeout_seconds = 60 timer_text = 'Time left: ' live_method = 'live_method' @staticmethod def is_displayed(player: Player): group = player.group group = player.group return not group.has_volunteer @staticmethod def vars_for_template(player: Player): partners = get_partners(player) payoff = set_payoffs(player) return dict(partners = partners, payoff = payoff) class Results_Succeed(Page): form_model = 'group' @staticmethod def is_displayed(player: Player): group = player.group return group.has_volunteer @staticmethod def vars_for_template(player: Player): payoff = set_payoffs(player) all_rounds = get_all_rounds(player) return dict(payoff = payoff, all_rounds = all_rounds) @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant all_rounds = get_all_rounds(player) investor_payoff_allrounds = [r.investor_payoff for r in all_rounds] round_number_allrounds = [r.round_number for r in all_rounds] is_volunteer_allrounds = [r.is_volunteer for r in all_rounds] has_volunteer_allrounds = [r.has_volunteer for r in all_rounds] payoff_allrounds = [r.payoff for r in all_rounds] participant.investor_payoff_allrounds = investor_payoff_allrounds participant.round_number_allrounds = round_number_allrounds participant.is_volunteer_allrounds = is_volunteer_allrounds participant.has_volunteer_allrounds = has_volunteer_allrounds participant.payoff_allrounds = payoff_allrounds class Results_Fail(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): group = player.group return not group.has_volunteer @staticmethod def vars_for_template(player: Player): payoff = set_payoffs(player) all_rounds = get_all_rounds(player) return dict(payoff = payoff, all_rounds = all_rounds) @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant all_rounds = get_all_rounds(player) investor_payoff_allrounds = [r.investor_payoff for r in all_rounds] round_number_allrounds = [r.round_number for r in all_rounds] is_volunteer_allrounds = [r.is_volunteer for r in all_rounds] has_volunteer_allrounds = [r.has_volunteer for r in all_rounds] payoff_allrounds = [r.payoff for r in all_rounds] participant.investor_payoff_allrounds = investor_payoff_allrounds participant.round_number_allrounds = round_number_allrounds participant.is_volunteer_allrounds = is_volunteer_allrounds participant.has_volunteer_allrounds = has_volunteer_allrounds participant.payoff_allrounds = payoff_allrounds class DecisionWait(WaitPage): wait_for_all_groups = True class Investment_Finished(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): session = player.session subsession = player.subsession return player.subsession.round_number >= 10 class LotteryWait(WaitPage): wait_for_all_groups = True class Lottery_Instruction1(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): session = player.session subsession = player.subsession return player.subsession.round_number >= 10 class Wait1(WaitPage): wait_for_all_groups = True class Lottery_Instruction2(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): session = player.session subsession = player.subsession return player.subsession.round_number >= 10 class Wait2(WaitPage): wait_for_all_groups = True class Lottery_Instruction3(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): session = player.session subsession = player.subsession return player.subsession.round_number >= 10 page_sequence = [DisplayInfo, InfoWait, Decision, Results_Succeed, Results_Fail, DecisionWait, Investment_Finished, LotteryWait, Lottery_Instruction1, Wait1, Lottery_Instruction2, Wait2, Lottery_Instruction3]