#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]