#1 by tartwijktvan
Dear oTree forum members, I am working on developing a repeated one-shot Prisoner's Dilemma (PD) game in oTree and would like some help. I specifically would like a group of 8 players to play against each other in one-on-one PDs for 7 rounds, and that each player faces another player only once for these 7 rounds (so that all players play against all players). On top of this, I would like the order to be randomized. I have tried to adopt the randomization procedure from a fellow PhD student who used it for one of his publications (see the def do_my_shuffle(player)). However, he used the previous version of oTree coding that relied largely on self. Hence, I have tried to update it to the newest oTree programming version. My issue is that I am not sure how to have oTree repeat the randomization in do_my_shuffle when getting to the ShuffleGroupsWaitPage at the end. I receive a TypeError: ShuffleGroupsWaitPage.after_all_players_arrive() got an unexpected keyword argument 'subsession'. Eager to hear any solutions to this problem! My current __init__.py code is displayed here: from otree.api import * doc = """ Here I will create a repeated Prisoner's Dilemma with 8 players participating with each other once. """ class C(BaseConstants): NAME_IN_URL = 'multiRoundPD' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 7 MULTIPLICATION_FACTOR = 2 ENDOWMENT = cu(500) NUM_PLAYERS = 8 PLAYERS_PER_SESSION = 8 class Subsession(BaseSubsession): def random_group_order(player): player.group_randomly() print(player.get_group_matrix()) def do_my_shuffle(player): # get all players in session players = player.get_players() # get total numbers of participants num_players = player.session.num_participants # couple participants to their variables for x in range(num_players): players[int(x)] = "p" + str(x + 1) print(players) print("p" + str(x + 1) + ".coupled_ADV") print("p" + str(x + 1) + ".coupled_DISADV") print("p" + str(x + 1) + ".multiplier") print("p" + str(x + 1) + ".endowment") # create variables to count itterations inside the loop x = 0 d = {} # randomize players from random import shuffle shuffle(players) if player.round_number > 1: for player_self in player.get_players(): player_self.coupled_pother1 = player_self.in_round(player.round_number - 1).coupled_pother1 player_self.coupled_pother2 = player_self.in_round(player.round_number - 1).coupled_pother2 player_self.coupled_pother3 = player_self.in_round(player.round_number - 1).coupled_pother3 player_self.coupled_pother4 = player_self.in_round(player.round_number - 1).coupled_pother4 player_self.coupled_pother5 = player_self.in_round(player.round_number - 1).coupled_pother5 player_self.coupled_pother6 = player_self.in_round(player.round_number - 1).coupled_pother6 player_self.coupled_pother7 = player_self.in_round(player.round_number - 1).coupled_pother7 player_self.coupled_pother8 = player_self.in_round(player.round_number - 1).coupled_pother8 for player_self in player.get_players(): print("Paired Previously before shuffle") print("p1 other1:") print(player_self.coupled_pother1) print("p1 other2:") print(player_self.coupled_pother2) print("p1 other3:") print(player_self.coupled_pother3) print("p1 other4:") print(player_self.coupled_pother4) print("p1 other5:") print(player_self.coupled_pother5) print("p1 other6:") print(player_self.coupled_pother6) print("p1 other7:") print(player_self.coupled_pother7) print("p1 other8:") print(player_self.coupled_pother8) print("p.id") print(player_self.random_id) # randomize players from random import shuffle shuffle(players) import random if player.round_number == 1: number_list = [1, 2, 3, 4, 5, 6, 7] print("Original list:", number_list) random.shuffle(number_list) print("List after first shuffle:", number_list) player.session.vars['ran_number_list'] = number_list # print("List after first shuffle:", number_list) print(player.session.vars['ran_number_list']) print(player.session.vars['ran_number_list'][0]) print(player.session.vars['ran_number_list'][1]) print(player.session.vars['ran_number_list'][2]) if player.round_number == player.session.vars['ran_number_list'][0]: matrix = player.get_group_matrix() new_structure = [[1, 2], [3, 4], [5, 6], [7, 8]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][1]: matrix = player.get_group_matrix() new_structure = [[1, 3], [5, 2], [8, 6], [7, 4]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][2]: matrix = player.get_group_matrix() new_structure = [[1, 4], [3, 5], [7, 6], [8, 2]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][3]: matrix = player.get_group_matrix() new_structure = [[1, 5], [3, 6], [4, 8], [2, 7]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][4]: matrix = player.get_group_matrix() new_structure = [[1, 6], [3, 7], [8, 5], [4, 2]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][5]: matrix = player.get_group_matrix() new_structure = [[1, 7], [3, 8], [5, 4], [2, 6]] player.set_group_matrix(new_structure) if player.round_number == player.session.vars['ran_number_list'][6]: matrix = player.get_group_matrix() new_structure = [[1, 8], [3, 2], [5, 7], [4, 6]] player.set_group_matrix(new_structure) print(player.get_group_matrix()) class Group(BaseGroup): pass class Player(BasePlayer): cooperation = models.CurrencyField( min_value=0, max_value=100, label="How many points would you like to transfer to your partner?" ) outcome = models.CurrencyField() # FUNCTIONS def set_payoffs(group: Group): for player in group.get_players(): partner = player.get_others_in_group()[0] player.outcome = C.ENDOWMENT - player.cooperation + (partner.cooperation * C.MULTIPLICATION_FACTOR) # PAGES class Contribution(Page): form_model = 'player' form_fields = ['cooperation'] class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoffs class Results(Page): @staticmethod def vars_for_template(player: Player): partner = player.get_others_in_group()[0] return { 'own_cooperation': player.cooperation, 'partner_cooperation': partner.cooperation, 'own_payoff': player.outcome } class ShuffleGroupsWaitPage (WaitPage): body_text = "We are waiting for the other participants. We thank you for your patience!" wait_for_all_groups = True @staticmethod def after_all_players_arrive(player): player.Subsession.do_my_shuffle() page_sequence = [Contribution, ResultsWaitPage, Results, ShuffleGroupsWaitPage]
#2 by xindamate_xyz (edited )
Hi, From the doc https://otree.readthedocs.io/en/latest/multiplayer/waitpages.html, "If you set wait_for_all_groups = True, then after_all_players_arrive must be a Subsession function." i also define after_all_players_arrive ub subsession, but it still throw errors. so I think maybe can move the calling of do_my_shuffle() to other methods Thanks Tina, https://xindamate.com/
#3 by xindamate_xyz
Hi, I have resolved, the key part is this, note that the parameter is subsession. @staticmethod def after_all_players_arrive(subsession): subsession.do_my_shuffle() print(666) and following is full file. import logging import itertools from otree.api import * doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'anony' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 class Subsession(BaseSubsession): def do_my_shuffle(self): print(1111) class Group(BaseGroup): pass class Player(BasePlayer): def creating_session(self): # Log a message at the start of the session creation logging.info("Session is being created") # Example: Randomly grouping players self.group_randomly() # Log another message after some operations logging.info("Players have been grouped randomly") # PAGES class MyPage(Page): pass class ResultsWaitPage(WaitPage): body_text = "We are waiting for the other participants. We thank you for your patience!" wait_for_all_groups = True @staticmethod def after_all_players_arrive(subsession): subsession.do_my_shuffle() print(666) class Results(Page): pass page_sequence = [MyPage, ResultsWaitPage, Results] Thanks Tina, https://xindamate.com/
#4 by tartwijktvan
Dear Tina, Thank you! This indeed seems to do the trick for me. @staticmethod def after_all_players_arrive(subsession): subsession.do_my_shuffle() Best, Tycho