#1 by felmola
Hi all. Perhaps you could help me put understand why my bots keep crashing in the very last round. They skip to Result as expected but somehow freeze for a couple of seconds before jumping to the next app (which never loads in the browser). (See error at the bottom). The behavior is as if bots where trying to play an additional round right before jumping to the next app. A couple of questions before they get lost in the code below: 1) Is it really necessary to pass the "return upcoming_apps[0]" function below. Shouldn't the bots justjust skipped the pages ment to skip and finish without errors? 2) Why use player.participant instead of player directly? I have this page sequence: page_sequence = [RedChooses, Interaction, RedRoundOver, BlueRoundOver, BlueChooses, ShuffleWaitPage, Results] When players hit, say, round 7. In page Interaction, finished_rounds = True. class Interaction(WaitPage): @staticmethod def after_all_players_arrive(group: Group): interaction(group) if group.round_number > C.MIN_NUM_ROUNDS: if group.round_number == 7: #if random.random() <= C.STOP_PROBABILITY: print("------------------ END OF GAME ------------------", "Round number: ", group.round_number) for p in group.get_players(): p.finished_rounds = True class Results(Page): @staticmethod def app_after_this_page(player, upcoming_apps): if player.finished_rounds: return upcoming_apps[0] @staticmethod def is_displayed(player): return player.finished_rounds class PlayerBot(Bot): def play_round(self): if infinity_test == 1 and C.PLAYERS_PER_GROUP == 8 and (C.TREATMENT == 0 or C.TREATMENT == 2): if self.round_number == 1 or self.round_number % 2 != 0: if self.player.id_in_group % 2 != 0: # for blue players yield BlueRoundOver if self.player.finished_rounds == True: yield Results elif self.player.finished_rounds == False: yield Submission(BlueChooses, dict(link_to_p2=1, link_to_p4=1, link_to_p6=1, link_to_p8=1, ), check_html=False) elif self.player.id_in_group % 2 == 0: yield RedChooses, dict(help_others=1) yield RedRoundOver if self.player.finished_rounds == True: yield Results if self.round_number % 2 == 0: if self.player.id_in_group % 2 == 0: # for blue players yield BlueRoundOver if self.player.finished_rounds == True: yield Results elif self.player.finished_rounds == False: yield Submission(BlueChooses, dict(link_to_p2=1, link_to_p4=1, link_to_p6=1, link_to_p8=1, ), check_html=False) elif self.player.id_in_group % 2 != 0: yield RedChooses, dict(help_others=1) yield RedRoundOver if self.player.finished_rounds == True: yield Results The error it throws is : AssertionError: Bot expects to be on page RedChooses but current page is /p/nxaog1e1/nothingness/Introduction/351. Check your bot code, then create a new session. nothingness is the next app. Thank you very much, Felipe
#2 by felmola
I modified my code above to comply with the one in the example and the same problem came up. I tested manually and it worked as expected. However the bots failed to go to the next app when the round that kills the app is played. The error suggested that the bots are trying to submit whatever they are told to submit as if the app was not killed: "Bots expect to be on whatever page was given to them from app 1, however the current page is the first page from app 2." In this example, the killer round is 2. They are expected to jump to the next app. However you can see from the print statement that the bots try to submit stuff as if it was the third round of app 1 for them: ROUND NUMBER IN BOTS 2 Submit /p/xi781vkl/money_memory/BlockEnd/12 ROUND NUMBER IN BOTS 3 Traceback (most recent call last):..... Do you think this is an oTree issue? I'll gladly share my GitHub repo if needed. ---------------------------------------------------------------------------------------------------------------------------- infinity_test = 1 class PlayerBot(Bot): def play_round(self): if self.participant.finished_rounds == False: print("ROUND NUMBER IN BOTS", self.round_number) if infinity_test == 1 and C.PLAYERS_PER_GROUP == 8 and (C.TREATMENT == 0 or C.TREATMENT == 2): if self.round_number == 1 or self.round_number % 2 != 0: if self.player.id_in_group % 2 != 0: # for blue players yield Results yield Submission(BlueChooses, dict(link_to_p2=1, link_to_p4=1, link_to_p6=1, link_to_p8=1, ), check_html=False) elif self.player.id_in_group % 2 == 0: yield RedChooses, dict(help_others=1) yield Results elif self.round_number % 2 == 0: if self.player.id_in_group % 2 == 0: # for blue players yield Results yield Submission(BlueChooses, dict(link_to_p1=1, link_to_p3=1, link_to_p5=1, link_to_p7=1, ), check_html=False) elif self.player.id_in_group % 2 != 0: yield RedChooses, dict(help_others=1) yield Results if self.participant.finished_rounds == True: print("ROUND NUMBER IN BOTS", self.round_number) yield BlockEnd ----------------------------------------------------------------------------------------------------------------------------
#3
by
Chris_oTree
I haven't read through that code, but will say that if app_after_this_page executes in the 2nd round, then your bot must also be programmed to only play 2 rounds. So if round_number > 2 then there should be no yield statements. This way the bot will proceed to the next app.
#4 by felmola
Thank you very much Chris. That was exactly what was causing the bots to continue to an additioanl round after the killer round. Best, Felipe