#1 by carooo (edited )
Hello, I have an experiment that is a sequence of app A (1 round), app B (10 rounds) and app C (10 rounds). At the end of the game, I need to calculate the total payoff from app A/round 1 plus the payoff from a randomly selected round in app B plus the payoff from a randomly selected round in app C. This all happens in a separate app D. So far, I am getting nowhere, so any help is highly appreciated! Greetings Caro
#2
by
ccrabbe
Hi Caro - I am asked to write oTree software which pays on a random round quite often. Here is how I currently handle it: (1) For each app where you're picking a random round, define Player model fields called "potential_payoff" (2) In creating_session decide which round you're paying on, save that value somewhere (subsession field if you want it in the data, session.vars if you don't care) (2) Calculate your payoffs as normal, but instead of setting the value of player.payoff, save it to player.potential_payoff. This way you have what the payoff would have been saved in your data (in case you want it later or in case you want to sanity-check your payoff calculation) (3) Use an if statement to copy the value of player.potential_payoff into player.payoff only when the current round is your randomly chosen round (or if this player is one of the ones randomly chosen for payment, etc) and sets player.payoff to 0 otherwise. This way one can just use oTree's built-in payoff functionality, the template tags, etc. Thanks, --Chris
#3 by carooo (edited )
Hi Chris, thanks so much for your quick reply. The idea is that the exact round numbers of app B and C that are used for all participants' payoffs are actually randomly chosen at the very end of the session and individually for each participant. I also can't set players' payoff to zero in one round, as the payoff of each round is always shown to participants. If I understand correctly, your suggestion is based on the random round number being determined by us in advance? I was hoping the solution to this would be some set_payoffs expression in the last app of the game, where 2 random numbers between 1 and 10 are generated (easily done) and these numbers are used to call the exact round's payoff of the two previous apps. If you find the time, I would appreciate your take on this! Thank you so much! Greetings Caro
#4
by
ccrabbe
Hi Caro - You can still show them the value stored in player.potential_payoff by using the {{ player.potential_payoff }} template tag - so that shouldn't be a problem. Unless you're showing them the accumulating value in participant.payoff every round too? To us it's never mattered at what actual time the computer generates random numbers, so this method is much more straightforward for us, but if it's scientifically important to you that the computer randomly choose the rounds at one time of the experiment over the other, then you can store each round's payoff in participant.vars (with a unique key which encodes the round number, so something like participant.vars['appA_payoff_round{}'.format(player.round_number)] = player.potential_payoff and participant.vars['appB_payoff_round{}'.format(player.round_number)] = player.potential_payoff Then at whatever time in the experiment you want you can choose random numbers and access the payoff from any round of any app you've stored, since they're all saved in participant.vars (uniquely by app, round and participant). If you want the 16th round from app D, then you'd get it from participant.vars['appD_payoff_round{}'.format(16)] Thanks, --Chris
#5
by
BonnEconLab
I would suggest that you store all (potential) payoffs per round in a list as a participant field. That is, in settings.py, include something like PARTICIPANT_FIELDS = [ payoff_app_A, all_payoffs_app_B, all_payoffs_app_C, ] In vars_for_template of the first page of app B and C, initialize the lists (e.g., with some nonsensical value), like this: if player.round_number == 1: player.participant.all_payoffs_app_B = [-99999 for x in range(0, C.NUM_ROUNDS)] and if player.round_number == 1: player.participant.all_payoffs_app_C = [-99999 for x in range(0, C.NUM_ROUNDS)] On the respective pages of the different rounds of your apps B and C, you set player.participant.all_payoffs_app_B[player.round_number - 1] = player.payoff and player.participant.all_payoffs_app_C[player.round_number - 1] = player.payoff respectively. At the end of app_C you will then have, say, player.participant.payoff_app_A = 1.23 player.participant.all_payoffs_app_B = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 0.0] player.participant.all_payoffs_app_C = [0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9] From these lists, pick a random element and calculate the sum for the total payoff. For instance, player.payoff_app_B = random.choice(player.participant.all_payoffs_app_B) (I hope the code works; I can’t test it right now.)
#6 by carooo (edited )
Hi again, thanks for both of your replies. Regarding "on the respective pages of the different rounds of your apps B and C, you set player.participant.all_payoffs_app_B(...)", I'm not entirely sure where exactly you suggest I put this code? I appreciate both your help a lot! If you have any further information that could help, that would be truly terrific. Caro
#7
by
BonnEconLab
carooo wrote: > Regarding "on the respective pages of the different rounds of your apps B and C, you set player.participant.all_payoffs_app_B(...)", I'm not entirely sure where exactly you suggest I put this code? Ah, I thought that you were setting player.payoff somewhere, depending on the subject’s decision in that round. (I may have mistakenly inferred that from the conversation between you and ccrabbe.) If you are already setting player.payoff to some value, then you can include player.participant.all_payoffs_app_B[player.round_number - 1] = player.payoff simply in a new line after the line in which you set player.payoff. If that is not the case, then there is no need to use player.payoff at all. Let’s assume that you have form_model = "player" form_fields = ["some_input"] in the definition of your decision page. Then you can use @staticmethod def before_next_page(player, timeout_happened): player.participant.all_payoffs_app_B[player.round_number - 1] = \ player.some_input # or some value that depends on player.some_input in that decision page.
#8 by carooo
Thanks for clearing that up! I followed the steps but the participant_fields are not recognized ("name payoff(...) not defined") when I put them in the settings.py file (can't start devserver as a consequence). I have avoided this whole participant.vars and participant_fields business for too long it seems. Not quite sure where to go from here, but again, any additional information is highly appreciated!
#9
by
BonnEconLab
You need to use quotation marks in the settings.py file as follows: PARTICIPANT_FIELDS = [ "payoff_app_A", "all_payoffs_app_B", "all_payoffs_app_C", ] (I forgot the quotation marks in my earlier post.)
#10 by carooo
Hello to Bonn and Chris, thank you so much for your help. Just in case anyone ever encounters a similar issue: In the end it was surprisingly simple and a combination of both your ideas. I used "possible_payoffs" to show the payoff of each round and let the random round and actual payoff show at the end of each app by using a little modification of the sample game "pay_random_round" and by using PARTICIPANT_FIELDS. What made it really easy is that I can just show the total payoff from all apps and their randomly chosen round by using {{participant.payoff}} in the final template as everything is perfectly calculated and stored in that field. Thanks a lot! Being rather new to oTree, it's people like you that make it all possible! Greetings Caro