from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as cu, currency_range, ) # single source of truth author = 'Your name here' doc = """Your app description""" class Constants(BaseConstants): name_in_url = 'tg234_optimized' players_per_group = None num_rounds = 40 PAYOFF_BY_INFOSET = {1: cu(0.10), 2: cu(0.20), 3: cu(0.30), 4: cu(0.40), 5: cu(0.50), 6: cu(0.60), 7: cu(0.70), 8: cu(0.80), 9: cu(0.90), 10: cu(1.00), 11: cu(1.10), 12: cu(1.20), 13: cu(1.30), 14: cu(1.40), 15: cu(1.50), 16: cu(1.60), 17: cu(1.70), 18: cu(1.80), 19: cu(1.90), 20: cu(2.00), 21: cu(2.10), 22: cu(2.20), 23: cu(2.30), 24: cu(2.40), 25: cu(2.50), 26: cu(2.60), 27: cu(2.70), 28: cu(2.80), 29: cu(2.90), 30: cu(3.00), 31: cu(3.10), 32: cu(3.20), 33: cu(3.30), 34: cu(3.40), 35: cu(3.50), 36: cu(3.60), 37: cu(3.70), 38: cu(3.80), 39: cu(3.90), 40: cu(4.00), 41: cu(4.10), 42: cu(4.20), 43: cu(4.30), 44: cu(4.40), 45: cu(4.50), 46: cu(4.60), 47: cu(4.70), 48: cu(4.80), 49: cu(4.90), 50: cu(5.00), 51: cu(5.10), 52: cu(5.20), 53: cu(5.30), 54: cu(5.40), 55: cu(5.50), 56: cu(5.60), 57: cu(5.70), 58: cu(5.80), 59: cu(5.90), 60: cu(6.00), } SEQUENCES_BY_INFOSET = { 1: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 2: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 3: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 4: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 5: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 6: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 7: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 8: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 9: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 10: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 11: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 12: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 13: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 14: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 15: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 16: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 17: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 18: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 19: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 20: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 21: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 22: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 23: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 24: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 25: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 26: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 27: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 28: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 29: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 30: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 31: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 32: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 33: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 34: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 35: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 36: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 37: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 38: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 39: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 40: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 41: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 42: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 43: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 44: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 45: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 46: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 47: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 48: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 49: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 50: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 51: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 52: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 53: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 54: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 55: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 56: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 57: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 58: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 59: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], 60: [6, 2, 0, 0, 2, 2, 2, 2, 2, 6, 2, 2, 2, 0, 2, 2, 6, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 2, 2, 0, 2, 2, 2, 2, 2, 6, 0], } OPTION_BY_OUTCOME = {6: 1, 0: 1, 2: 2} class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # The participant’s assigned info_set (1..60); copied from participant.vars info_set = models.IntegerField() # Outcome/payoff for THIS round in cents (e.g., 0/3/4) outcome_cents = models.IntegerField() # Keep tg only if you still use it in your pages/templates tg = models.IntegerField(initial=3) def creating_session(subsession: Subsession): """Copy per-participant info_set to Player each round and pick this round's outcome.""" r = subsession.round_number - 1 # 0-based # Do one-time sanity checks on round 1 if subsession.round_number == 1: for pl in subsession.get_players(): part = pl.participant if 'info_set' not in part.vars: raise RuntimeError('participant.vars["info_set"] must be set before this app.') iset = int(part.vars['info_set']) if iset not in Constants.SEQUENCES_BY_INFOSET: raise RuntimeError(f'No sequence found for info_set={iset}.') seq = Constants.SEQUENCES_BY_INFOSET[iset] if len(seq) != Constants.num_rounds: raise RuntimeError( f'Sequence for info_set={iset} must have {Constants.num_rounds} entries.' ) # Default tg if you need it later if 'tg' not in part.vars: part.vars['tg'] = 3 # Per-round assignment for pl in subsession.get_players(): part = pl.participant pl.info_set = int(part.vars['info_set']) pl.tg = int(part.vars.get('tg', 3)) seq = Constants.SEQUENCES_BY_INFOSET[pl.info_set] pl.outcome_cents = int(seq[r])