from otree.api import * from datetime import datetime import random import time # from otree.api import BaseConstants, BaseSubsession, BaseGroup, BasePlayer, models, widgets, Page doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'social_mobility' players_per_group = None num_rounds = 1 current_treatments = ['CN_50_50', 'JB_50_50'] # TODO: delete at end all_treatments = ['CN_50_50', 'CN_80_20', 'CN_20_80', # control group 'JB_50_50', 'JB_80_20', 'JB_20_80', # justifying beliefs treatment 'OC_50_50', 'OC_80_20', 'OC_20_80'] # overconfidence treatment correct_slider_position = 50 # percentage the sliders in the effort task must be positioned at effort_cutoff_A_B = 24 # effort task cutoff value between ranks A and B effort_cutoff_B_C = 22 # TODO: implement correct cutoff values effort_cutoff_C_D = 20 effort_cutoff_D_E = 18 effort_cutoff_E_F = 16 effort_cutoff_F_G = 14 effort_cutoff_G_H = 12 def determine_rank(player, number_of_correct_sliders, timestamp_milliseconds): rank = 'ERROR' # initialize with error value determine_by_luck = timestamp_milliseconds >= player.ms_cutoff # 20/50/80% chance # Selection of performance group based on randomness if determine_by_luck: rank = random.choice(['H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']) # Selection of performance group based on actual performance else: if number_of_correct_sliders > Constants.effort_cutoff_A_B: rank = 'A' elif number_of_correct_sliders > Constants.effort_cutoff_B_C: rank = 'B' elif number_of_correct_sliders > Constants.effort_cutoff_C_D: rank = 'C' elif number_of_correct_sliders > Constants.effort_cutoff_D_E: rank = 'D' elif number_of_correct_sliders > Constants.effort_cutoff_E_F: rank = 'E' elif number_of_correct_sliders > Constants.effort_cutoff_F_G: rank = 'F' elif number_of_correct_sliders > Constants.effort_cutoff_G_H: rank = 'G' else: rank = 'H' return rank, determine_by_luck class Subsession(BaseSubsession): pass # def creating_session(subsession): # import itertools # treatments = itertools.cycle(Constants.current_treatments) # for player in subsession.get_players(): # player.treatment = next(treatments) class Group(BaseGroup): pass class Player(BasePlayer): # 0_TREATMENT_SELECTION treatment = models.StringField(initial='CN_50_50') ms_cutoff = models.IntegerField() # cutoff of ms used to determine luck/effort in rank determination luck_prob = models.IntegerField() # probability that rank is determined by luck effort_prob = models.IntegerField() # probability that rank is determined by effort # A_INTRODUCTION timestamp_of_ms = models.IntegerField() # range: [0; 999] # C_EFFORT_TASK # TODO: add all slider variables here # D_PERFORMANCE_SELF_ASSESSMENT rank_estimation = models.StringField(widget=widgets.RadioSelectHorizontal, choices=['H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']) # F_RANK_RESULT number_of_correct_sliders = models.IntegerField() determined_rank = models.StringField() result_determined_by_luck = models.BooleanField() determined_tokens = models.IntegerField(initial=100) # H_ATTENTION_TEST attention_check = models.BooleanField() # I_RESULT_SELF_ASSESSMENT result_belief = models.IntegerField() # L_RISK_ASSESSMENT risk_taking = models.IntegerField(choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], widget=widgets.RadioSelect) ############################### # Z_TAX_VOTE tax_vote = models.IntegerField() timer_start = models.FloatField(initial=999, blank=True) # in ms timer_end = models.IntegerField() # in ms timer_duration = models.FloatField() # in s # PAGES class A_Introduction(Page): form_model = 'player' @ staticmethod def before_next_page(player: Player, timeout_happened): player.timestamp_of_ms = round(datetime.now().time().microsecond / 1000) if "50_50" in player.treatment: player.ms_cutoff = 500 player.luck_prob = 50 player.effort_prob = 50 elif "80_20" in player.treatment: player.ms_cutoff = 200 player.luck_prob = 80 player.effort_prob = 20 elif "20_80" in player.treatment: player.ms_cutoff = 800 player.luck_prob = 20 player.effort_prob = 80 class B_EffortTaskInstructions(Page): form_model = 'player' # TODO: remove at the end (debugging purposes only) @ staticmethod def before_next_page(player: Player, timeout_happened): player.number_of_correct_sliders = 0 # random.seed(10) player.determined_rank, player.result_determined_by_luck = determine_rank( player, player.number_of_correct_sliders, player.timestamp_of_ms) class C_EffortTask(Page): pass # timeout_seconds = 60 # form_model = 'player' # form_fields = [('slider'+str(i)) for i in range(1, 60+1)] # @staticmethod # def before_next_page(player: Player, timeout_happened): # sliders = [] # TODO: insert all slider variables (at the end) # player.number_of_correct_sliders = sliders.count(Constants.correct_slider_position) # # random.seed(10) # player.determined_rank, player.result_determined_by_luck = determine_rank( # player.number_of_correct_sliders, player.timestamp_milliseconds) # # token_legend = {'A': 800, 'B': 700, 'C': 600, 'D': 500, 'E': 400, 'F': 300, 'G': 200, 'H': 100} # player.determined_tokens = token_legend[player.determined_rank] class D_PerformanceSelfAssessment(Page): form_model = 'player' form_fields = ['rank_estimation'] class E_RankAssignment(Page): form_model = 'player' class F_RankResult(Page): form_model = 'player' class G_PreliminaryBonusPayment(Page): form_model = 'player' class H_AttentionTest(Page): form_model = 'player' form_fields = ["attention_check"] class I_ResultSelfAssessment(Page): form_model = 'player' form_fields = ['result_belief'] class Z_TaxVote(Page): # TODO: UPDATE form_model = 'player' form_fields = ['tax_vote', 'timer_start'] @ staticmethod def app_after_this_page(player: Player, timeout_happened): player.timer_end = int(round(time.time() * 1000)) player.timer_duration = round((player.timer_end - player.timer_start) / 1000, 2) @staticmethod def js_vars(player): return dict( determined_rank=player.determined_rank, timer_start=player.timer_start, ) class L_RiskAssessment(Page): form_model = 'player' form_fields = ['risk_taking'] class M_End(Page): form_model = 'player' page_sequence = [A_Introduction, B_EffortTaskInstructions, D_PerformanceSelfAssessment, E_RankAssignment, F_RankResult, G_PreliminaryBonusPayment, H_AttentionTest, I_ResultSelfAssessment, L_RiskAssessment, M_End]