#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_com (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_com
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