from dis import Instruction from otree.api import ( Page, WaitPage, models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) from otree.models import player, subsession import random doc = """ This is a one-period public goods crowding out game with 3 players. """ class Constants(BaseConstants): name_in_url = 'crowding_out' players_per_group = 2 num_rounds = 8 instructions_template = 'crowding_out/instructions.html' # """Amount allocated to each player""" #endowment = c(22) multiplier = 2 class Subsession(BaseSubsession): pass class Group(BaseGroup): total_contribution = models.CurrencyField() average_contribution = models.CurrencyField() individual_share = models.CurrencyField() ''' class Player(BasePlayer): contribution = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", label="How much will you contribute to the charity (from 0 to 22)?", ) ''' class Player(BasePlayer): endowment = models.IntegerField() tax = models.StringField() intensity = models.StringField() charity = models.CurrencyField(label="Please enter your total contributions to all the 4 most effective charities provided above.") contribution = models.CurrencyField() def creating_session(subsession): # randomize to treatments if subsession.round_number == 1 or subsession.round_number == 2 or subsession.round_number == 5 or subsession.round_number == 6: for player in subsession.get_players(): player.endowment = 22 if subsession.round_number == 3 or subsession.round_number == 4 or subsession.round_number == 7 or subsession.round_number == 8: for player in subsession.get_players(): player.endowment = 28 if subsession.round_number == 1 or subsession.round_number == 5 or subsession.round_number == 3 or subsession.round_number == 7: for player in subsession.get_players(): player.tax = 'no' if subsession.round_number == 2 or subsession.round_number == 6 or subsession.round_number == 4 or subsession.round_number == 8: for player in subsession.get_players(): player.tax = 'yes' if subsession.round_number == 1 or subsession.round_number == 2 or subsession.round_number == 3 or subsession.round_number == 4: for player in subsession.get_players(): player.intensity = 'low' if subsession.round_number == 5 or subsession.round_number == 6 or subsession.round_number == 7 or subsession.round_number == 8: for player in subsession.get_players(): player.intensity = 'high' ''' for player in subsession.get_players(): player.endowment = random.choice([22, 28]) player.tax = random.choice(['no', 'yes']) player.intensity = random.choice(['high', 'low']) #print('set player.endowment to', player.endowment) ''' # FUNCTIONS def vars_for_admin_report(subsession: Subsession): contributions = [p.contribution for p in subsession.get_players() if 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)', ) def set_payoffs(group: Group): group.total_contribution = sum([p.contribution for p in group.get_players()]) #group.average_contribution = sum([p.contribution for p in group.get_players()]) / Constants.players_per_group group.individual_share = ( group.total_contribution * Constants.multiplier / Constants.players_per_group ) for p in group.get_players(): p.payoff = 0.1*(p.endowment - p.contribution) + 0.1*group.individual_share p.group.average_contribution = group.total_contribution / Constants.players_per_group # PAGES class Introduction(Page): """Description of the game: How to play and returns expected""" def is_displayed(player): return player.round_number == 1 class Instruction(Page): """Description of the game: How to play and returns expected""" pass class Charity(Page): def is_displayed(player): return player.round_number == 5 class Contribute(Page): """Player: Choose how much to contribute""" form_model = 'player' form_fields = ['charity'] def before_next_page(player, timeout_happened): player.contribution = player.charity @staticmethod def error_message(player, values): print('values is', values) if player.subsession.round_number == 1 or player.subsession.round_number == 2 or player.subsession.round_number == 3 or player.subsession.round_number == 4: if values['charity'] > 22: return 'The sum of the numbers can not exceed 22. Please enter again.' if player.subsession.round_number == 5 or player.subsession.round_number == 6 or player.subsession.round_number == 7 or player.subsession.round_number == 8: if values['charity'] > 28: return 'The sum of the numbers can not exceed 28. Please enter again.' class ResultsWaitPage(WaitPage): after_all_players_arrive = 'set_payoffs' body_text = "Waiting for other participants to contribute." class Results(Page): """Players payoff: How much each has earned""" @staticmethod def vars_for_template(player: Player): group = player.group return dict(total_earnings=group.total_contribution) class End(Page): def is_displayed(player): return player.round_number == 8 page_sequence = [Introduction, Instruction, Charity, Contribute, ResultsWaitPage, Results, End]