#1 by jamiehax
I have a game where I would like to repeat a certain subset of pages with a 50% probability each time after reaching the end of that subset. I call add_interaction in an after_all_players_arrive method from the ResultsWaitPage. The function to add pages to the page_sequence seems to work fine, but the problem seems to be that oTree doesn't look at this page_sequence after __init__.py is first called. I know I could get similar functionality with a live page, but it would be nice to get it to work this way of anyone has any ideas.
class ResultsWaitPage(WaitPage):
@staticmethod
def after_all_players_arrive(group: Group):
group.round_num += 1
payout_tuple = C.PAYOUT_MATRIX[group.p1_choice][group.p2_choice]
group.get_player_by_id(1).round_payout = payout_tuple[0]
group.get_player_by_id(1).total_payout += payout_tuple[0]
group.get_player_by_id(2).round_payout = payout_tuple[1]
group.get_player_by_id(2).total_payout += payout_tuple[1]
add_interaction()
page_sequence = [Instructions, InteractionWaitPage, Interaction, ResultsWaitPage, AfterInteraction, Results]
def add_interaction():
r = random.randint(1, 100)
if r <= 50:
for index, page in reversed(list(enumerate(page_sequence))):
if type(page) is type(AfterInteraction):
page_sequence.insert(index + 1, InteractionWaitPage)
page_sequence.insert(index + 2, Interaction)
page_sequence.insert(index + 3, ResultsWaitPage)
page_sequence.insert(index + 4, AfterInteraction)
break
#2 by coralio (edited )
Hi!
I think you can't do it that way. The right way to do this in oTree is to use many rounds (like NUM_ROUNDS =30 in the Constants class C), and then control whether they are displayed or not in the static method is_displayed.
- Create many rounds (30). Using prob=0.5, reaching round 30 is less than 1 over a billion. Having 30 rounds is not costly.
- Aux pages InteractionWaitPage, Interaction, ResultsWaitPage and AfterInteraction ( I don't know if AfterInteraction is an actual page or some artifact you created) should only be shown if r is <= 50.
- The result of r is a random boolean "is_shown". Where "is_shown" should be stored depends on whether it's common to all players in a group, groups in a session, or to each player individually. For instance, if the r is the same for all players in the game, we compute "is_shown" and store it in the session object. The resulting code would be as follows (even though I'd rather do all the random computation in creating_session, I'll do it your way here):
class C(BaseConstants):
NUM_ROUNDS = 30
# At the very beginning, when the session is being created,
# all aux pages are shown for the first round:
def creating_session(subsession):
if subsession.round_number == 1:
subsession.is_shown = True
# We store is_shown in the Subsession class. (If r were different accross groups, do this in the Group class)
class Subsession(BaseSubsession):
# This field determined whether each round is shown for all players
is_shown = models.BooleanField(initial=False)
class ResultsWaitPage(WaitPage):
# We wait for all players in the session, since "is_shown will be common to all.
wait_for_all_groups = True
# Note now that after_all_players_arrive is a subsession method
def after_all_players_arrive(subsession):
YOUR SAME CODE HERE
# I've passed subsession to your function.
add_interaction(subsession)
def add_interaction(subsession):
# In the last round, we can't decide nothing about the next round
if subsession.round_number == C.NUM_ROUNDS:
return
r = random.randint(1, 100)
if r <= 50
# We decide whether aux pages are shown in the NEXT ROUND.
# This is stored in the session object, because we want the outcome to be the same for all players
subsession.in_round(subsession.round_number + 1).is_shown = True
class Instructions(Page):
@staticmethod
def is_displayed(player: Player):
return player.round_number == 1;
# Show Results only in the last round
class Results(Page):
@staticmethod
def is_displayed(player: Player):
return player.round_number == C.NUM_ROUNDS;
# Repeat the code below the rest of aux pages: Interaction, ResultsWaitPage, AfterInteraction
class InteractionWaitPage(WaitPage):
@staticmethod
def is_displayed(player: Player):
return player.session.is_shown;
page_sequence = [Instructions, InteractionWaitPage, Interaction, ResultsWaitPage, AfterInteraction, Results]