from otree.api import * import random doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'in_a_c' PLAYERS_PER_GROUP = None NUM_TRIAL_ROUNDS = 1 NUM_ROUNDS = 20 + NUM_TRIAL_ROUNDS PAYOFFS = dict( D=(13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 24, 25, 26, 27, 28, 29, 30, 25, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 27, 28, 29, 17, 18, 22, 23, 24, 25, 26, 27, 28, 29, 30, 30, 29, 28, 27, 26), B=(15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 23, 24, 25, 26, 27, 28, 29, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 24, 25, 26, 27), C=(13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 25, 26, 17, 18, 19, 20, 21, 22, 23, 24, 16, 17, 18, 19, 20, 21, 22, 23, 24, 23, 22, 21, 20, 19, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 18, 19, 20, 21, 22, 23, 24, 25, 26, 20, 21), A=(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 20, 21, 22, 21, 20, 19, 18, 17, 16, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 18, 19), ) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): choice = models.StringField( choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')], label='Which envelope would you like to open?:', ) check_q1 = models.StringField( label='What is the main goal of the game?', choices=[ ('fast', 'Complete the game as fast as possible'), ('points', 'Collect as many points as possible'), ('options', 'Try out every option') ], widget=widgets.RadioSelect ) check_q2 = models.IntegerField( label='I feel confident in the decisions I have made so far in this game (1: Not at all, 5: Very)', choices=[1, 2, 3, 4, 5], widget=widgets.RadioSelectHorizontal, ) check_q3 = models.IntegerField( label='I feel able to make better decisions as the game progresses (1: Strongly Disagree, 5: Strongly Agree)', choices=[1, 2, 3, 4, 5], widget=widgets.RadioSelectHorizontal, ) prolific_id = models.StringField( label='Before you continue, please enter your Prolific participant ID:', blank=False ) payoff_round = models.IntegerField() round_time = models.FloatField() time_game_one = models.FloatField() game_total_one = models.CurrencyField() 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(): if 'order' not in p.participant.vars: p.participant.vars['order'] = ( 'A' if random.random() < 0.5 else 'B' ) # PAGES class Introduction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player, timeout_happened): from time import time if 'experiment_start_time' not in player.participant.vars: player.participant.vars['experiment_start_time'] = time() class Decision(Page): form_model = 'player' @staticmethod def get_form_fields(player): fields = ['choice'] if player.round_number == 17: fields += ['check_q2', 'check_q3'] return fields @staticmethod def is_displayed(player): return player.round_number > C.NUM_TRIAL_ROUNDS @staticmethod def vars_for_template(player): from time import time if 'timer_start_one' not in player.participant.vars: player.participant.vars['timer_start_one'] = time() player.participant.vars['round_start_one'] = time() @staticmethod def before_next_page(player, timeout_happened): dist = C.PAYOFFS[player.choice] payoff = random.choice(dist) player.payoff_round = payoff player.payoff = payoff from time import time start = player.participant.vars.get('round_start_one') if start is not None: player.round_time = time() - start if player.round_number == C.NUM_ROUNDS: player.time_game_one = ( time() - player.participant.vars['timer_start_one'] ) class Results(Page): @staticmethod def is_displayed(player): return player.round_number > C.NUM_TRIAL_ROUNDS @staticmethod def vars_for_template(player): return { 'round_payoff': player.payoff_round, 'choice': player.choice, 'round_number': player.round_number, } class TrialDecision(Page): form_model = 'player' form_fields = ['choice'] @staticmethod def is_displayed(player): return player.round_number <= C.NUM_TRIAL_ROUNDS @staticmethod def before_next_page(player, timeout_happened): dist = C.PAYOFFS[player.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.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.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='points', ) 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 Tutorial(Page): form_model = 'player' form_fields = ['prolific_id'] @staticmethod def is_displayed(player): return player.round_number == 1 class TotalResults(Page): @staticmethod def is_displayed(player): return 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_one = sum(p.payoff for p in real_rounds) page_sequence = [Introduction, Tutorial, TrialDecision, TrialResults, Decision, Results, TotalResults]