import random from otree.api import * from . import config from .config import * author = 'Felix Holzmeister & Armin Pfurtscheller' doc = """ Modified from Bomb Risk Elicitation Task (BRET) à la Crosetto/Filippin (2013), Journal of Risk and Uncertainty (47): 31-65. """ # ========================================================== # LANGUAGE HELPERS # ========================================================== def get_language(player): return player.session.config.get('language', 'en') def get_lexicon(lang): if lang == 'id': from .lexicon_id import Lexicon else: from .lexicon_en import Lexicon return Lexicon def language_flags(lang): return { 'en': lang == 'en', 'id': lang == 'id', } BOX_VALUE = cu(BOX_VALUE) def dict_from_module(module): context = {} for setting in dir(module): if not setting.startswith('_') and setting.isupper(): context[setting] = getattr(module, setting) return context config_dict = dict_from_module(config) # ========================================================== # MODELS # ========================================================== class Constants(BaseConstants): name_in_url = 'b2_bret_game' num_rounds = config.NUM_ROUNDS players_per_group = None results_1_round_template = __name__ + '/results_1_round.html' results_multi_round_template = __name__ + '/results_multi_round.html' instructions_template = __name__ + '/instructions.html' class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): bomb_bret_real = models.IntegerField() bomb_row = models.IntegerField() bomb_col = models.IntegerField() boxes_collected = models.IntegerField() pay_this_round = models.BooleanField() round_result = models.CurrencyField() # ========================================================== # PAYOFF FUNCTION # ========================================================== def set_payoff(player: Player): participant = player.participant round_number = player.round_number # determine round payoff if player.bomb_bret_real: player.round_result = cu(0) else: player.round_result = player.boxes_collected * BOX_VALUE # randomly select paying round if round_number == 1: participant.vars['round_to_pay_plain'] = random.randint( 1, NUM_ROUNDS ) if RANDOM_PAYOFF: if round_number == participant.vars['round_to_pay_plain']: player.pay_this_round = True player.payoff = player.round_result else: player.pay_this_round = False player.payoff = cu(0) else: player.payoff = player.round_result # ========================================================== # PAGES # ========================================================== class Instructions_1(Page): @staticmethod def is_displayed(player: Player): return INSTRUCTIONS and player.round_number == 1 @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) return dict( Lexicon=Lexicon, num_boxes=NUM_ROWS * NUM_COLS, num_nobomb=NUM_ROWS * NUM_COLS - 1, **language_flags(lang), **config_dict, ) class Instructions_2(Page): @staticmethod def is_displayed(player: Player): return INSTRUCTIONS and player.round_number == 1 @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) return dict( Lexicon=Lexicon, num_boxes=NUM_ROWS * NUM_COLS, num_nobomb=NUM_ROWS * NUM_COLS - 1, **language_flags(lang), **config_dict, ) class Instructions_3(Page): @staticmethod def is_displayed(player: Player): return INSTRUCTIONS and player.round_number == 1 @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) return dict( Lexicon=Lexicon, num_boxes=NUM_ROWS * NUM_COLS, num_nobomb=NUM_ROWS * NUM_COLS - 1, **language_flags(lang), **config_dict, ) class Instructions_4(Page): @staticmethod def is_displayed(player: Player): return INSTRUCTIONS and player.round_number == 1 @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) return dict( Lexicon=Lexicon, num_boxes=NUM_ROWS * NUM_COLS, num_nobomb=NUM_ROWS * NUM_COLS - 1, **language_flags(lang), **config_dict, ) class Game(Page): form_model = 'player' form_fields = [ 'bomb_bret_real', 'boxes_collected', 'bomb_row', 'bomb_col', ] @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) return dict( Lexicon=Lexicon, num_boxes=NUM_ROWS * NUM_COLS, **language_flags(lang), ) @staticmethod def js_vars(player: Player): participant = player.participant reset = participant.vars.pop('reset', False) if DYNAMIC: input = False else: input = not DEVILS_GAME return dict( reset=reset, input=input, **config_dict ) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars['reset'] = True set_payoff(player) class Results(Page): @staticmethod def is_displayed(player: Player): return RESULTS and player.round_number == NUM_ROUNDS @staticmethod def vars_for_template(player: Player): lang = get_language(player) Lexicon = get_lexicon(lang) participant = player.participant round_to_pay_plain = participant.vars['round_to_pay_plain'] selected_round = player.in_round(round_to_pay_plain) total_payoff = sum( [p.payoff for p in player.in_all_rounds()] ) participant.vars['bret_payoff'] = total_payoff return dict( Lexicon=Lexicon, player_in_all_rounds=player.in_all_rounds(), box_value=BOX_VALUE, boxes_total=NUM_ROWS * NUM_COLS, boxes_collected=player.boxes_collected, bomb_bret_real=player.bomb_bret_real, bomb_row=player.bomb_row, bomb_col=player.bomb_col, round_result=player.round_result, round_to_pay_plain=round_to_pay_plain, payoff=player.payoff, total_payoff=total_payoff, selected_round_result=selected_round.round_result, **config_dict, **language_flags(lang), ) class Transition_Fancy(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds page_sequence = [ Instructions_1, Game, Results, ]