from otree.api import * import random import itertools import time doc = """ CM experiment. Discrete choice task. """ class C(BaseConstants): NAME_IN_URL = 'CM_DCE_2' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 1 TASKS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] price_1 = [4, 4.5, 5, 5.5, 6] price_2 = [4, 4.5, 5, 5.5, 6] timeout = 15 # CHANGE ACCORDINGLY #ANOTHER EXAMPLE OF RANDOMIZING THE LIST # price_list_example = [(4, 5), (4.5, 5), (5, 5.5), (5.5, 4)] # Experimental budget budget = 6 # Exchange rate exchange_pounds = 0.87 matching_timeout_mins = 5 smaller_group = 6 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass def make_field(label): return models.IntegerField( choices=[[1, "A"], [2, "B"], [3, "Nessun"]], label=label, widget=widgets.RadioSelect, blank=False, ) class Player(BasePlayer): CE_choice_1 = make_field('Scelta') CE_choice_2 = make_field('Scelta') CE_choice_3 = make_field('Scelta') CE_choice_4 = make_field('Scelta') CE_choice_5 = make_field('Scelta') CE_choice_6 = make_field('Scelta') CE_choice_7 = make_field('Scelta') CE_choice_8 = make_field('Scelta') CE_choice_9 = make_field('Scelta') CE_choice_10 = make_field('Scelta') price_list = models.LongStringField() price_list_aux = models.LongStringField() random_draw = models.IntegerField() risk_1 = models.IntegerField(widget=widgets.RadioSelectHorizontal, choices=[[1, "Decisamente no"], [2, '2'], [3, '3'], [4, '4'], [5, "Decisamente sì"]]) risk_2 = models.IntegerField(widget=widgets.RadioSelectHorizontal, choices=[[1, "Decisamente no"], [2, '2'], [3, '3'], [4, '4'], [5, "Decisamente sì"]]) age = models.IntegerField(min=1900, max=2004) gender = models.StringField(widget=widgets.RadioSelect, choices=['Maschio', 'Femmina', 'Transgender', 'Non binario/non conforme', 'Preferisco non rispondere']) student = models.BooleanField(widget=widgets.RadioSelect, choices=['Sì', 'No']) study_area = models.StringField(label='Campo di studio') income = models.IntegerField(label='Reddito') payoff_bonus = models.FloatField() pounds = models.FloatField() choice = models.IntegerField() level1 = models.FloatField() level2 = models.FloatField() def waiting_too_long(player): return time.time() - player.participant.wait_page_arrival > C.matching_timeout_mins * 60 # Functions def creating_session(subsession: Subsession): if subsession.round_number == 1: for p in subsession.get_players(): p.participant.is_dropout = False #Mug price pairs for each player pairs = itertools.product(C.price_1, C.price_2) result = [pair for pair in pairs if pair[0] != pair[1]] # CAN THEY BE EQUAL TO EACH OTHER? price_list = random.sample(result, 10) # in case I randomize price list order also for bottles # price_list_aux = random.sample(price_list, 10) p.participant.price_list = price_list p.participant.price_list_aux = price_list #ANOTHER OPTION OF RANDOMIZING THE LIST # example = random.shuffle(C.price_list_example) # p.participant.price_list_example = example random_draw = random.randint(1, len(C.TASKS)) p.participant.random_draw = random_draw def waiting_seconds(player): participant = player.participant wait = int(time.time() - participant.wait_page_arrival) print('Player', player.id_in_subsession, 'waiting for', wait, 'seconds') return wait def ranked_waiting_seconds(waiting_players): waits = [waiting_seconds(p) for p in waiting_players] waits.sort(reverse=True) print(waits) return waits def group_by_arrival_time_method(subsession, waiting_players): num_waiting = len(waiting_players) subsession.session.vars['num_waiting'] = num_waiting print("number of waiting players:", num_waiting, " ", time.strftime('%X %x %Z')) if len(waiting_players) >= C.PLAYERS_PER_GROUP: print("creating group") return waiting_players[:10] waits = ranked_waiting_seconds(waiting_players) # Actual code if len(waits) == 9 and waits[8] > 60*C.matching_timeout_mins: return waiting_players if len(waits) == 8 and waits[7] > 60*C.matching_timeout_mins: return waiting_players if len(waits) == 7 and waits[6] > 60*C.matching_timeout_mins: return waiting_players if len(waits) == 6 and waits[5] > 65*C.matching_timeout_mins: return waiting_players if len(waits) == 5 and waits[4] > 65*C.matching_timeout_mins: return waiting_players if len(waits) == 4 and waits[3] > 65*C.matching_timeout_mins: return waiting_players if len(waits) == 3 and waits[2] > 65*C.matching_timeout_mins: return waiting_players if len(waits) == 2 and waits[1] > 65*C.matching_timeout_mins: return waiting_players if len(waits) == 1 and waits[0] > 65*C.matching_timeout_mins: return waiting_players ##################################### PAGES #################################################### class GBAT(WaitPage): title_text = ("Si prega di rimanere su questa pagina - La fase 1 inizierà a breve") body_text = "" group_by_arrival_time = True template_name = 'CM_DCE_2/Grouping.html' def is_displayed(self): return self.round_number == 1 @staticmethod def app_after_this_page(player: Player, upcoming_apps): if player.waiting_too_long(): return 'CM_CM_2' @staticmethod def js_vars(player): return dict(arrival_time=player.participant.wait_page_arrival, current_time=time.time(), timeout_mins=C.matching_timeout_mins) @staticmethod def after_all_players_arrive(group: Group): # save each participant's current group ID so it can be # accessed in the next app. for p in group.get_players(): participant = p.participant participant.past_group_id = group.id # class Introduction(Page): # # @staticmethod # def before_next_page(player, timeout_happened): # participant = player.participant # player.price_list = str(participant.price_list) # player.random_draw = int(participant.random_draw) class DCE_1(Page): form_model = 'player' form_fields = ['CE_choice_1'] def vars_for_template(player: Player): price_pair = player.participant.price_list[0] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) @staticmethod def before_next_page(player, timeout_happened): participant = player.participant player.price_list = str(participant.price_list) player.random_draw = int(participant.random_draw) class DCE_2(Page): form_model = 'player' form_fields = ['CE_choice_2'] def vars_for_template(player: Player): price_pair = player.participant.price_list[1] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_3(Page): form_model = 'player' form_fields = ['CE_choice_3'] def vars_for_template(player: Player): price_pair = player.participant.price_list[2] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_4(Page): form_model = 'player' form_fields = ['CE_choice_4'] def vars_for_template(player: Player): price_pair = player.participant.price_list[3] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_5(Page): form_model = 'player' form_fields = ['CE_choice_5'] def vars_for_template(player: Player): price_pair = player.participant.price_list[4] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_6(Page): form_model = 'player' form_fields = ['CE_choice_6'] def vars_for_template(player: Player): price_pair = player.participant.price_list[5] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_7(Page): form_model = 'player' form_fields = ['CE_choice_7'] def vars_for_template(player: Player): price_pair = player.participant.price_list[6] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_8(Page): form_model = 'player' form_fields = ['CE_choice_8'] def vars_for_template(player: Player): price_pair = player.participant.price_list[7] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_9(Page): form_model = 'player' form_fields = ['CE_choice_9'] def vars_for_template(player: Player): price_pair = player.participant.price_list[8] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) class DCE_10(Page): form_model = 'player' form_fields = ['CE_choice_10'] def vars_for_template(player: Player): price_pair = player.participant.price_list[9] level1 = price_pair[0] level2 = price_pair[1] return dict(level1=level1, level2=level2) def before_next_page(player: Player, timeout_happened): participant = player.participant if player.participant.random_draw == 1: mug_payoff = player.CE_choice_1 else: if player.participant.random_draw == 2: mug_payoff = player.CE_choice_2 else: if player.participant.random_draw == 3: mug_payoff = player.CE_choice_3 else: if player.participant.random_draw == 4: mug_payoff = player.CE_choice_4 else: if player.participant.random_draw == 5: mug_payoff = player.CE_choice_5 else: if player.participant.random_draw == 6: mug_payoff = player.CE_choice_6 else: if player.participant.random_draw == 7: mug_payoff = player.CE_choice_7 else: if player.participant.random_draw == 8: mug_payoff = player.CE_choice_8 else: if player.participant.random_draw == 9: mug_payoff = player.CE_choice_9 else: mug_payoff = player.CE_choice_10 participant.mug_payoff = mug_payoff participant.CE_choice_1 = player.CE_choice_1 participant.CE_choice_2 = player.CE_choice_2 participant.CE_choice_3 = player.CE_choice_3 participant.CE_choice_4 = player.CE_choice_4 participant.CE_choice_5 = player.CE_choice_5 participant.CE_choice_6 = player.CE_choice_6 participant.CE_choice_7 = player.CE_choice_7 participant.CE_choice_8 = player.CE_choice_8 participant.CE_choice_9 = player.CE_choice_9 participant.CE_choice_10 = player.CE_choice_10 class Pre_CM(Page): def is_displayed(player: Player): return player.participant.treatment_p > 2 # # TIMEOUT: CHANGE THE VALUE # timeout_seconds = C.timeout # @staticmethod # def before_next_page(player, timeout_happened): # if timeout_happened: # player.participant.is_dropout = True @staticmethod def app_after_this_page(player: Player, upcoming_apps): # print('upcoming app is', upcoming_apps) if player.participant.treatment_p > 2: return upcoming_apps[-2] # skip to the last app page_sequence = [ GBAT, # Introduction, DCE_1, DCE_2, DCE_3, DCE_4, DCE_5, DCE_6, DCE_7, DCE_8, DCE_9, DCE_10, Pre_CM, ]