oTree Forum >

How to properly keep player information from one round to the next ?

#1 by DonutMan

Hello all,
I'm really new in oTree and I try to develop my very first Prisoner's dilemma application.

I'm stuck with propagating the information stored in player object from one round to the next one.

I have two players (PLAYERS_PER_GROUP = 2) and three rounds (NUM_ROUNDS = 3).

At the first page, I ask their name, age and gender.
On the second page, I ask them to choose if they betray or not
Then I print the result

I do not want that the players to be asked their name/age/gender after the first round, so I added a is_displayed() function for this page with the following return : "return (player.round_number == 1)"

As explained in the oTree documentation (https://otree.readthedocs.io/en/latest/rounds.html#passing-data-between-rounds-or-apps), it is expected that the player objects are not propagated from one round to the other one.

The documentation gives some hints to achieve player propagation but I fail adding this in my code. Where is the best place to add this propagation ?

Here's a small code that I began to develop :

        if player.round_number > 1:
            subsession = player.subsession
            subsession_init = subsession.in_round(1)

            player_list = subsession_init.get_players()
            participant_list = [p.participant for p in player_list]

            participant = player.participant

            index = participant_list.index(participant)
            player_init = player_list[index]

            player.name = player_init.name
            player.age = player_init.age
            player.gender = player_init.gender

Thanks a lot for any advice ! :)



#2 by DonutMan

In fact, I tried this code in the vars_for_template() function of the second page.

It works a little bit even if I think it is a very very ugly place to store such a redefinition of player's variables (I'm not creating vars for template but rather reload previous state).

But moreover, all the game will be broken because the player's opponent, which is accessed by player.get_others_in_group()[0], is still a "blank" player (with additonnal fields name/age/gender set to None). It seems that these field are updated a little after but I dont know when nor why.

On the internet, some people suggest to add these name/age/gender fields to the participant object itself. This make sense since this identify a participant and not a player. But the oTree documentation does not mention that...

And since I think it's an issue that many many project may encounter, it should be easy to handle.

Nevertheless, I do not find any "official" and simple solution that address this issue.

If you have some canonical example, I'm highly interested ! (for example, I saw that "otree startproject" may create a lot of example, perhaps the solution is inside one of them ?)

Thanks a lot for any advice :)



#3 by DonutMan

In fact, what i want to do in simple words, is to propagate variables such as I'm able to print somehow at each round :

Hello {{ player_name }}, your opponent name is {{ opponent_name }}.

And I do not want the participant to be asked their name at each round...

#4 by gr0ssmann

Have you considered using in_previous_rounds() etc.? https://otree.readthedocs.io/en/latest/rounds.html#in-rounds-in-previous-rounds-in-round-etc

#5 by DonutMan

Hello gr0ssmann,
thank you very much for your answer.

Yes, if I understand right what you suggest, it should be easier to access the variables from a previous state of player rather than trying to propagate those variables from a round to the next one.

But the title of the section of the documentation you quote is "Passing data between rounds or apps" which is a little ambigous. And sadly the documentation does not provide any example on *how* to pass data between rounds/apps, in a clear and robust way.

I was thinking a little bit on my problem and saw two things :.
1- the name/age/gender should not be linked to a player but rather to a participant
2- by design, the player are reseted from one round to another one

So my conclusion is that the name/age/gender should belong to the participant object and not the player. There might be a form_model defined for participant object but I did not found any information about it in the documentation... The only form_model described is the one linked to "player".

So far, this is the cleanest way I found to work around this issue :
- the page that asks the name/age/gender is displayed only in round_number 1
- I used the before_next_page() function to copy these three parameters in the participant object
- For the next rounds, I know that player.name, player.age and player.gender will be set to "None". I will not try to access them but I will look into player.participant.name, player.participant.age and player.participant.gender

class Intro(Page):
    form_model = 'player'
    form_fields = ['name', 'age', 'gender']
    def is_displayed(player: Player):
        return (player.round_number == 1)

    def before_next_page(player: Player, timeout_happened):
        # This should be called only for the first round (see is_displayed() function)
        participant = player.participant
        participant.name = player.name
        participant.age = player.age
        participant.gender = player.gender

Write a reply

Set forum username