oTree Forum >

Help Randomizing Players in Prisoner's Dilemma

#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

Write a reply

Set forum username