from otree.api import * import random doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'tm_ns_a' PLAYERS_PER_GROUP = None NUM_TRIAL_ROUNDS = 1 NUM_ROUNDS = 20 + NUM_TRIAL_ROUNDS PAYOFFS = dict( C=(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 54, 55, 56, 57, 58, 59, 60, 55, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 57, 58, 59, 47, 48, 52, 53, 54, 55, 56, 57, 58, 59, 60, 60, 59, 58, 57, 56), A=(45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 53, 54, 55, 56, 57, 58, 59, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 54, 55, 56, 57), D=(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 52, 55, 56, 47, 48, 49, 50, 51, 52, 53, 54, 46, 47, 48, 49, 50, 51, 52, 53, 54, 53, 52, 51, 50, 49, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 50, 51), B=(40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 45, 46, 47, 48, 49, 50, 51, 52, 51, 50, 49, 48, 47, 46, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 48, 49), ) #predetermined sequence RECOMMENDATION_SEQUENCE = [ 'A','A','C','A','D','C','A','C','A','A', 'C','D','A','A','C', 'B','A','C','C','A', ] TRIAL_RECOMMENDATIONS = [ 'A', ] class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): first_choice = models.StringField( choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')], label='Which envelope would you like to open?:', ) suggestion = models.StringField() final_choice = models.StringField( choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')], label='What is your final choice?:' ) check_q1 = models.BooleanField( label="After seeing the AI system's recommendation, I have to change my initial answer", choices=[(True, 'True'), (False, 'False')]) check_q2 = models.IntegerField( label='I feel confident in the decisions I have made in this game (1: Not at all, 5: Very)', choices=[1, 2, 3, 4, 5], widget=widgets.RadioSelectHorizontal, ) check_q3 = models.IntegerField( label='The recommendations during this game provided useful input for my decisions (1: Strongly Disagree, 5: Strongly Agree)', choices=[1, 2, 3, 4, 5], widget=widgets.RadioSelectHorizontal, ) payoff_round = models.IntegerField() round_time_two = models.FloatField() time_game_two = models.FloatField() game_total_two = models.CurrencyField() active = models.BooleanField() treatment = models.StringField() sequence = models.StringField() stage = models.IntegerField() def get_cumulative_payoff(self): return sum(p.payoff for p in self.in_all_rounds()) def real_round(self): return self.round_number - C.NUM_TRIAL_ROUNDS def total_real_rounds(self): return C.NUM_ROUNDS - C.NUM_TRIAL_ROUNDS def creating_session(subsession): for p in subsession.get_players(): order = p.participant.vars['order'] p.treatment = 'NS' p.stage = 1 p.sequence = order p.active = ( (order == 'A') ) # PAGES class InstructionsOne(Page): @staticmethod def is_displayed(player): return player.active and player.round_number == 1 class Decision(Page): form_model = 'player' @staticmethod def is_displayed(player): return player.active and player.round_number > C.NUM_TRIAL_ROUNDS @staticmethod def get_form_fields(player): fields = ['first_choice', 'final_choice'] if player.round_number == 17: fields += ['check_q2', 'check_q3'] return fields @staticmethod def vars_for_template(player): from time import time if 'timer_start_two' not in player.participant.vars: player.participant.vars['timer_start_two'] = time() player.participant.vars['round_start_two'] = time() real_round = player.round_number - C.NUM_TRIAL_ROUNDS rec = C.RECOMMENDATION_SEQUENCE[real_round - 1] return dict( recommended_option=rec ) @staticmethod def before_next_page(player, timeout_happened): dist = C.PAYOFFS[player.final_choice] payoff = random.choice(dist) player.payoff_round = payoff player.payoff = payoff real_round = player.round_number - C.NUM_TRIAL_ROUNDS player.suggestion = C.RECOMMENDATION_SEQUENCE[real_round - 1] from time import time start = player.participant.vars.get('round_start_two') if start is not None: player.round_time_two = time() - start if player.round_number == C.NUM_ROUNDS: player.time_game_two = ( time() - player.participant.vars['timer_start_two'] ) class Results(Page): @staticmethod def is_displayed(player): return player.active and player.round_number > C.NUM_TRIAL_ROUNDS @staticmethod def vars_for_template(player): return { 'round_payoff': player.payoff_round, 'choice': player.final_choice, 'round_number': player.round_number, } class TrialDecision(Page): form_model = 'player' form_fields = ['first_choice', 'final_choice'] @staticmethod def is_displayed(player): return player.active and player.round_number <= C.NUM_TRIAL_ROUNDS @staticmethod def vars_for_template(player): rec = C.TRIAL_RECOMMENDATIONS[player.round_number - 1] return dict(recommended_option=rec) @staticmethod def before_next_page(player, timeout_happened): dist = C.PAYOFFS[player.final_choice] payoff = random.choice(dist) player.payoff_round = payoff player.payoff = 0 class TrialResults(Page): form_model = 'player' @staticmethod def is_displayed(player): return player.active and player.round_number <= C.NUM_TRIAL_ROUNDS @staticmethod def get_form_fields(player): if player.round_number == C.NUM_TRIAL_ROUNDS: return ['check_q1'] return [] @staticmethod def vars_for_template(player): return dict( round_payoff=player.payoff_round, choice=player.final_choice, round_number=player.round_number, is_trial=True ) @staticmethod def error_message(player, values): if player.round_number != C.NUM_TRIAL_ROUNDS: return None correct = dict( check_q1=False, ) wrong = [ field for field, right_answer in correct.items() if values.get(field) != right_answer ] if wrong: return "One or more answers are incorrect, please correct them before continuing to the game." return None class TotalResults(Page): @staticmethod def is_displayed(player): return player.active and player.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player): real_rounds = player.in_rounds(C.NUM_TRIAL_ROUNDS + 1, C.NUM_ROUNDS) total = sum(p.payoff for p in real_rounds) return { 'total_payoff': total } @staticmethod def before_next_page(player, timeout_happened): real_rounds = player.in_rounds(C.NUM_TRIAL_ROUNDS + 1, C.NUM_ROUNDS) player.game_total_two = sum(p.payoff for p in real_rounds) page_sequence = [InstructionsOne, TrialDecision, TrialResults, Decision, Results, TotalResults]