from otree.api import * from otree.models import Participant is_dropout = models.BooleanField(initial=False) USE_POINTS = True # you can have a real effort task and then the experiment in the same app, or two apps divided --> ask Jonas # if you want 2 apps, put them in session.configs --> app sequence: ['prisoners_dilemma','public_goods'] c = Currency doc = """ Baseline treatment """ class Constants(BaseConstants): name_in_url = 'resource_game' players_per_group = 4 num_rounds = 16 A_value = 0.25 B_value = 0.1 # Functions class Subsession(BaseSubsession): pass class Group(BaseGroup): total_harvest = models.IntegerField() A_stock_remained = models.IntegerField(initial=50) B_stock_remained = models.IntegerField(initial=50) A_growth_rate = models.IntegerField(initial=0) B_growth_rate = models.IntegerField(initial=3) class Player(BasePlayer): # timeout_seconds = models.IntegerField(initial=120) # DO TIMEOUT harvest = models.IntegerField( min=0, max=Group.A_stock_remained, # this has to be variable and dynamic, label="How many units of A do you want to harvest?" # it has to change during the course of the game ) @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return 120 @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: player.harvest = 3 participant.is_dropout = True @staticmethod def error_message(player, value): print('value is', value) if value > Group.A_stock_remained: return 'You cannot harvest more than the whole resource stock' def custom_export(players): # this is for custom data export # header row yield ['session', 'participant_code', 'round_number', 'id_in_group', 'payoff'] for p in players: participant = p.participant session = p.session yield [session.code, participant.code, p.round_number, p.id_in_group, p.payoff] # PAGES class Introduction(Page): # you only have to see this the first round DO ONLY FIRST ROUND @staticmethod def is_displayed(player): if player.round_number == 1: return True else: return False timeout_seconds = 60 # replacement with bot, just to continue class Instructions(Page): # having the opportunity to go back and see the instructions would be nice, # MAYBE NOT @staticmethod # Real effort task + bots def is_displayed(player): if player.round_number == 1: return True else: return False timeout_seconds = 300 # replacement with bot, just to continue class Harvest(Page): form_model = "player" form_fields = ["harvest"] timeout_seconds = 150 # https://otree.readthedocs.io/en/latest/multiplayer/waitpages.html?highlight=is_dropout# # replacing-dropped-out-player-with-a-bot # replacement with bot + the number @staticmethod def vars_for_template(player: Player): if Group.round_number == range(0, 17): # in all rounds, I want to show the image return dict( image_path="resource_game/Resource.jpg" ) class ResultsWaitPage(WaitPage): body_text = "Waiting for other participants to contribute." @staticmethod def after_all_players_arrive(group: Group): total_harvest = 0 for player in group.get_players(): total_harvest += player.harvest Group.total_harvest = total_harvest @staticmethod def vars_for_template(group): if Group.A_stock_remained - Group.total_harvest == range(0, 5): # this should mean from 0 to 4 Group.A_growth_rate = 0 elif Group.A_stock_remained - Group.total_harvest == range(5, 10): # same.Example: range(0, 5, 1) or range Group.A_growth_rate = 1 elif Group.A_stock_remained - Group.total_harvest == range(10, 15): Group.A_growth_rate = 2 elif Group.A_stock_remained - Group.total_harvest == range(15, 20): Group.A_growth_rate = 1 elif Group.A_stock_remained - Group.total_harvest == range(20, 25): Group.A_growth_rate = 7 elif Group.A_stock_remained - Group.total_harvest == range(25, 30): Group.A_growth_rate = 9 elif Group.A_stock_remained - Group.total_harvest == range(30, 35): Group.A_growth_rate = 7 elif Group.A_stock_remained - Group.total_harvest == range(35, 40): Group.A_growth_rate = 5 elif Group.A_stock_remained - Group.total_harvest == range(40, 45): Group.A_growth_rate = 3 elif Group.A_stock_remained - Group.total_harvest == range(45, 50): Group.A_growth_rate = 1 else: Group.A_growth_rate = 0 @staticmethod # question Ignasi: do I have to make one different function with staticmethod? def vars_for_template(group): if Group.B_stock_remained - Group.total_harvest == 0: Group.B_growth_rate = 0 elif Group.B_stock_remained - Group.total_harvest == range(1, 5): Group.B_growth_rate = 1 elif Group.B_stock_remained - Group.total_harvest == range(5, 10): Group.B_growth_rate = 2 elif Group.B_stock_remained - Group.total_harvest == range(10, 15): Group.B_growth_rate = 3 elif Group.B_stock_remained - Group.total_harvest == range(15, 20): Group.B_growth_rate = 4 elif Group.B_stock_remained - Group.total_harvest == range(20, 25): Group.B_growth_rate = 10 elif Group.B_stock_remained - Group.total_harvest == range(25, 30): Group.B_growth_rate = 13 elif Group.B_stock_remained - Group.total_harvest == range(30, 35): Group.B_growth_rate = 12 elif Group.B_stock_remained - Group.total_harvest == range(35, 40): Group.B_growth_rate = 10 elif Group.B_stock_remained - Group.total_harvest == range(40, 45): Group.B_growth_rate = 9 elif Group.B_stock_remained - Group.total_harvest == range(45, 50): Group.B_growth_rate = 5 elif Group.B_stock_remained - Group.total_harvest == 50: Group.B_growth_rate = 3 else: Group.B_growth_rate = 0 # they can actually surpass 50, and stay there, without harvesting @staticmethod def vars_for_template(group): if Group.round_number == 1: Group.A_stock_remained = 50 else: Group.A_stock_remained = Group.A_stock_remained - Group.total_harvest + Group.A_growth_rate # + growth rate if Group.round_number == 1: Group.B_stock_remained = 50 else: Group.B_stock_remained = Group.B_stock_remained - Group.total_harvest + Group.B_growth_rate # plus growth # rate, you can use "result" format (see Lesson 3) class Results(Page): @staticmethod def vars_for_template(player: Player): player.payoff = player.payoff = player.harvest * Constants.A_value + Group.B_stock_remained * Constants.B_value class Depletion(Page): def is_displayed(group): # this page is displayed, and not the end --> check and be sure if Group.A_stock_remained == 0: return True # wait Jonas, if this yes, then... the other class End(Page): def is_displayed(group): return group.round_number == Constants.num_rounds def vars_for_template(player: Player): all_players = player.in_all_rounds() combined_payoff = 0 for player in all_players: combined_payoff += player.payoff return { "combined_payoff": combined_payoff } page_sequence = [Introduction, Instructions, Harvest, ResultsWaitPage, Results, Depletion, End]