import random from otree.api import * doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'war_of_attrition' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 5 PRIZE_VALUE = cu(100) # unit costs are equal in symmetric games and could be different in asymmetric contests PLAYER_1_UNIT_COST_PER_PERIOD = cu(1) PLAYER_2_UNIT_COST_PER_PERIOD = cu(1) # the following are not needed for the standard, unconstrained WoA. For symmetric games they should be equal. # PLAYER_1_BUDGET = xxx # PLAYER_2_BUDGET = yyy class Subsession(BaseSubsession): pass class Group(BaseGroup): # defining variables at group level makes them accessible by all players player1_max_wait_time = models.IntegerField( label="How many days are you prepared to stay in the game?", min=0 # max=PLAYER_1_BUDGET / PLAYER_1_UNIT_COST_PER_PERIOD # only needed for the budget constrained variant of the WoA ) #player1_wins = models.BooleanField player2_max_wait_time = models.IntegerField( label="How long are you prepared to stay in the game before quiting?", min=0 # max=PLAYER_2_BUDGET / PLAYER_2_UNIT_COST_PER_PERIOD # only needed for the budget constrained variant of the WoA ) #player2_wins = models.BooleanField class Player(BasePlayer): # to fix the bug in accessing boolean variables in the Results.html # try defining max_wait_time and win_status here and call them there as members of 'player' win_status = models.BooleanField() # functions def set_payoffs(group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) min_wait_time = min(group.player1_max_wait_time, group.player2_max_wait_time) if group.player1_max_wait_time > group.player2_max_wait_time: # player 1 wins #group.player1_wins = True p1.win_status = True #group.player2_wins = False p2.win_status = False p1.payoff = C.PRIZE_VALUE - min_wait_time * C.PLAYER_1_UNIT_COST_PER_PERIOD # note that player 1's unit cost is counted p2.payoff = - min_wait_time * C.PLAYER_2_UNIT_COST_PER_PERIOD # note that player 2's unit cost is counted elif group.player2_max_wait_time > group.player1_max_wait_time: # player 2 wins #group.player1_wins = False p1.win_status = False #group.player2_wins = True p2.win_status = True p1.payoff = - min_wait_time * C.PLAYER_1_UNIT_COST_PER_PERIOD # note that player 1's unit cost is counted p2.payoff = C.PRIZE_VALUE - min_wait_time * C.PLAYER_2_UNIT_COST_PER_PERIOD # note that player 2's unit cost is counted else: # both players chose the same max_wait_time, hence the winner is selected randomly if random.random() < 0.5: #group.player1_wins = True p1.win_status = True #group.player2_wins = False p2.win_status = False p1.payoff = C.PRIZE_VALUE - min_wait_time * C.PLAYER_1_UNIT_COST_PER_PERIOD # note that player 1's unit cost is counted p2.payoff = - min_wait_time * C.PLAYER_2_UNIT_COST_PER_PERIOD # note that player 2's unit cost is counted else: #group.player1_wins = False p1.win_status = False #group.player2_wins = True p2.win_status = True p1.payoff = - min_wait_time * C.PLAYER_1_UNIT_COST_PER_PERIOD # note that player 1's unit cost is counted p2.payoff = C.PRIZE_VALUE - min_wait_time * C.PLAYER_2_UNIT_COST_PER_PERIOD # note that player 2's unit cost is counted # PAGES class Player1_DecisionPage(Page): form_model = 'group' form_fields = ['player1_max_wait_time'] # to make the page visible only to player 1 @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 class Player2_DecisionPage(Page): form_model = 'group' form_fields = ['player2_max_wait_time'] # to make the page visible only to player 2 @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 class ResultsWaitPage(WaitPage): # check if there is need to add a message here to notify a player # that the result is pending the choice by the other player? after_all_players_arrive = set_payoffs class Results(Page): pass page_sequence = [Player1_DecisionPage, Player2_DecisionPage, ResultsWaitPage, Results] # verify how can players enter their choice in parallel and not in a sequence defined above