from otree.api import * import json from datetime import datetime, timezone from .lexicon_en import Lexicon as LexiconEN from .lexicon_fr import Lexicon as LexiconFR doc = """ Your app description """ def is_example_round(player): from . import C return player.round_number <= C.NUM_EXAMPLE # Helper function language access: load lexicon & language dictionary def get_language_and_lexicon(player, strict=True): from .lexicon_fr import Lexicon as LexiconFR from .lexicon_en import Lexicon as LexiconEN lang = ( player.participant.vars['language'] if strict else player.participant.vars.get('language') or player.field_maybe_none('language') ) if lang not in ['fr', 'en']: raise ValueError(f"Unsupported or missing language: {lang}") if lang == 'fr': return LexiconFR, 'fr' else: return LexiconEN, 'en' class C(BaseConstants): NAME_IN_URL = 'lottery_example' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 # has to be equal to the sum of practice and real rounds NUM_EXAMPLE = 1 # Risk lottery parameters LOTTERY_PROB_GOOD = 0.5 LOTTERY_PROB_BAD = 0.5 ENDOWMENT = 100 # tokens available class Subsession(BaseSubsession): pass class Group(BaseGroup): pass def utc_now_iso(): return datetime.now(timezone.utc).isoformat() def append_page_timestamp(player, field_name, page_name): raw = player.field_maybe_none(field_name) or '{}' try: payload = json.loads(raw) except json.JSONDecodeError: payload = {} if field_name == 'page_shown_at_utc' and page_name in payload: return payload[page_name] = utc_now_iso() setattr(player, field_name, json.dumps(payload, ensure_ascii=True)) class Player(BasePlayer): investment = models.FloatField() page_shown_at_utc = models.LongStringField(blank=True) page_submitted_at_utc = models.LongStringField(blank=True) # PAGES class LotterySliderPage(Page): form_model = 'player' form_fields = ['investment'] @staticmethod def vars_for_template(player: Player): append_page_timestamp(player, 'page_shown_at_utc', LotterySliderPage.__name__) from . import get_language_and_lexicon Lexicon, lang = get_language_and_lexicon(player) is_example = is_example_round(player) good_return = 1 + player.session.config['mu'] + player.session.config['sigma'] bad_return = 1 + player.session.config['mu'] - player.session.config['sigma'] return dict( Lexicon=Lexicon, lang=lang, endowment=player.session.config['endowment_lottery'], good_return=good_return, bad_return=bad_return, prob_good=int(C.LOTTERY_PROB_GOOD * 100), prob_bad=int(C.LOTTERY_PROB_BAD * 100), is_example = is_example, ) @staticmethod def before_next_page(player, timeout_happened): append_page_timestamp(player, 'page_submitted_at_utc', LotterySliderPage.__name__) # def before_next_page(player, timeout_happened): # player.investment = player.investment class LotteryResultsPage(Page): @staticmethod def is_displayed(player: Player): return is_example_round(player) @staticmethod def vars_for_template(player: Player): append_page_timestamp(player, 'page_shown_at_utc', LotteryResultsPage.__name__) from . import get_language_and_lexicon Lexicon, lang = get_language_and_lexicon(player) invested = player.investment good_return = 1 + player.session.config['mu'] + player.session.config['sigma'] bad_return = 1 + player.session.config['mu'] - player.session.config['sigma'] loss_amt = invested*bad_return + (player.session.config['endowment_lottery'] - invested) gain_amt = invested*good_return + (player.session.config['endowment_lottery'] - invested) return dict( Lexicon=Lexicon, lang=lang, invested = invested, loss_amt = loss_amt, gain_amt = gain_amt, ) @staticmethod def before_next_page(player, timeout_happened): append_page_timestamp(player, 'page_submitted_at_utc', LotteryResultsPage.__name__) page_sequence = [LotterySliderPage, LotteryResultsPage]