from otree.api import * c = cu doc = '' class C(BaseConstants): NAME_IN_URL = 'Checkout' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 TOT_EXP_TIME = 30 PARTICIPATE_FEE = 4.5 BONUS_PAY = 1 N_ITEMS = 5 TREAT1_PAR_N = 100 TREAT2_PAR_N = 100 TREAT3_PAR_N = 100 TREAT4_PAR_N = 100 INFO_EASY = 'weight information' INFO_DIFF = 'both weight and price information' TABLE_EASY = 'sorted alphabetically' TABLE_DIFF = 'listed in random order' ACTION_EASY = 'the weight from a drop-down list' ACTION_DIFF = 'the weight from a drop-down list and the price using a slider bar' TIMELIMIT_EASY_SHORT = 26 TIMELIMIT_EASY_MEDIUM = 48 TIMELIMIT_EASY_LONG = 89 TIMELIMIT_DIFF_SHORT = 56 TIMELIMIT_DIFF_MEDIUM = 104 TIMELIMIT_DIFF_LONG = 194 CASHIER_TIME_LB_EASY = 4 CASHIER_TIME_UB_EASY = 19 CASHIER_TIME_LB_DIFF = 9 CASHIER_TIME_UB_DIFF = 40 CHECKOUT_TIME_MU_EASY = 2.183 CHECKOUT_TIME_SD_EASY = 0.45 CHECKOUT_TIME_MU_DIFF = 2.954 CHECKOUT_TIME_SD_DIFF = 0.453 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): treatment_group = models.FloatField() co_method = models.StringField(initial='NA') co_method_randnum = models.IntegerField(initial=0) cashier_preference1 = models.IntegerField(initial=50) cashier_preference2 = models.IntegerField(initial=50) cashier_preference3 = models.IntegerField(initial=50) cashier_preference4 = models.IntegerField(initial=50) cashier_preference5 = models.IntegerField(initial=50) cashier_preference6 = models.IntegerField(initial=50) p1survey1 = models.IntegerField(choices=[[1, 'Daily'], [2, 'A few times a week'], [3, 'A few times a month'], [4, 'A few times every six months'], [5, 'A few times a year'], [6, 'Never']], widget=widgets.RadioSelect) p1survey2 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey3 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey4 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey5 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey6 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey7 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) p1survey8 = models.IntegerField(choices=[[1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Neutral'], [5, 'Somewhat agree'], [6, 'Agree'], [7, 'Strongly agree']], widget=widgets.RadioSelect) timelimit_q1 = models.StringField() timelimit_q1sec = models.StringField() timelimit_q2 = models.StringField() timelimit_q2sec = models.FloatField() timelimit_q3 = models.StringField() timelimit_q4 = models.StringField() timelimit_q5 = models.StringField() timelimit_q6 = models.StringField() cashier_time_stmt_scenario1 = models.StringField() cashier_time_stmt_scenario2 = models.StringField() information_scenario1 = models.StringField() information_scenario2 = models.StringField() table_scenario1 = models.StringField() table_scenario2 = models.StringField() action_scenario1 = models.StringField() action_scenario2 = models.StringField() quiz1 = models.StringField(choices=[['a', 'eight questions that ask about my general opinions on self-service systems.'], ['b', 'six questions that ask about my preference of self-checkout vs. cashier checkout.'], ['c', 'a simulated checkout game.'], ['d', 'questions that ask about my demographic information.']], widget=widgets.RadioSelect) quiz2 = models.StringField(choices=[['a', '5'], ['b', '10'], ['c', '15'], ['d', '20']], widget=widgets.RadioSelect) quiz3 = models.StringField(choices=[['a', 'Weight'], ['b', 'Price'], ['c', 'Both weight and price'], ['d', 'Either weight or price']], widget=widgets.RadioSelect) quiz4 = models.StringField(choices=[['a', 'In alphabetical order'], ['b', 'In random order'], ['c', 'In either way'], ['d', 'None of the above']], widget=widgets.RadioSelect) quiz5 = models.StringField(choices=[['a', 'I will always use cashier-checkout.'], ['b', 'I will self-checkout 3 items.'], ['c', 'I am more likely to use self-checkout than cashier-checkout.'], ['d', 'I may still use self-checkout, even if the chance is small (3 out of 10).']], widget=widgets.RadioSelect) quiz6 = models.StringField(choices=[['a', 'One question from Survey – Part 2 will be randomly selected, and I will experience the checkout process.'], ['b', 'Which checkout option (self or cashier) will be assigned to me depends on my preference expressed in Survey – Part 2.'], ['c', 'If the self-checkout option is assigned to me, I need to manually enter the product information. '], ['d', 'If the cashier-checkout option is assigned to me, I just need to wait for a “simulated” cashier to enter the product information for me.'], ['e', 'All statements above are true.']], widget=widgets.RadioSelect) quiz7 = models.StringField(choices=[['a', 'I will earn a bonus regardless of how much time it takes to complete the checkout game.'], ['b', 'I cannot earn a bonus if I am assigned to a cashier-checkout.'], ['c', 'I can only earn a bonus if I am assigned to a self-checkout.'], ['d', 'I can earn a bonus regardless of which checkout option is assigned to me, as long as the checkout is completed within a specific time limit. ']], widget=widgets.RadioSelect) quiz8 = models.StringField(choices=[['a', 'I will earn a partial reward if I exit the study in the middle of the study.'], ['b', 'I can skip some of the surveys and the game and earn a partial reward.'], ['c', 'I must complete all the surveys and the checkout game to receive a cash payment.'], ['d', 'I will earn my reward upon completing only the checkout game without finishing the final survey.']], widget=widgets.RadioSelect) quiz9 = models.StringField(choices=[['a', '1'], ['b', '3'], ['c', '5'], ['d', 'Unlimited']], widget=widgets.RadioSelect) quiz_attempt_left = models.IntegerField(initial=0) quiz_failed_attempts = models.IntegerField(initial=0) num_correct_quiz = models.IntegerField(initial=0) num_incorrect_quiz = models.IntegerField() incorrect_quiz_num_list = models.StringField() surveyage = models.IntegerField() surveygender = models.IntegerField(choices=[[1, 'Male'], [2, 'Female'], [3, 'Other'], [4, 'Prefer not to say']], widget=widgets.RadioSelect) surveyedu = models.IntegerField(choices=[[1, 'Primary'], [2, 'Secondary'], [3, 'Associate'], [4, 'Bachelors'], [5, 'Masters'], [6, 'Doctor']], widget=widgets.RadioSelect) surveydevice = models.IntegerField(choices=[[1, 'Cell phone'], [2, 'Tablet'], [3, 'Laptop'], [4, 'Desktop'], [5, 'Other']], widget=widgets.RadioSelect) cat_1 = models.StringField() cat_2 = models.StringField() cat_3 = models.StringField() cat_4 = models.StringField() cat_5 = models.StringField() item_1 = models.StringField() item_2 = models.StringField() item_3 = models.StringField() item_4 = models.StringField() item_5 = models.StringField() p_1 = models.FloatField() p_2 = models.FloatField() p_3 = models.FloatField() p_4 = models.FloatField() p_5 = models.FloatField() w_1 = models.FloatField() w_2 = models.FloatField() w_3 = models.FloatField() w_4 = models.FloatField() w_5 = models.FloatField() cashier_time_1 = models.FloatField() cashier_time_2 = models.FloatField() cashier_time_3 = models.FloatField() cashier_time_4 = models.FloatField() cashier_time_5 = models.FloatField() start_time_item1 = models.FloatField() start_time_item2 = models.FloatField() start_time_item3 = models.FloatField() start_time_item4 = models.FloatField() start_time_item5 = models.FloatField() endtime_game = models.FloatField() time_is_up = models.FloatField(initial=0) study_start_time = models.FloatField() study_end_time = models.FloatField() def live_method_sp2(player: Player, data): player.cashier_preference1 = int(data['cashier_preference1_var']) player.cashier_preference2 = int(data['cashier_preference2_var']) player.cashier_preference3 = int(data['cashier_preference3_var']) player.cashier_preference4 = int(data['cashier_preference4_var']) player.cashier_preference5 = int(data['cashier_preference5_var']) player.cashier_preference6 = int(data['cashier_preference6_var']) def live_method_pgp(player: Player, data): player.start_time_item1 = float(data['start_time_item1_var']) def live_method_item1(player: Player, data): player.start_time_item2 = float(data['start_time_item2_var']) player.time_is_up = float(data['time_is_up_var']) def live_method_item2(player: Player, data): player.start_time_item3 = float(data['start_time_item3_var']) player.time_is_up = float(data['time_is_up_var']) def live_method_item3(player: Player, data): player.start_time_item4 = float(data['start_time_item4_var']) player.time_is_up = float(data['time_is_up_var']) def live_method_item4(player: Player, data): player.start_time_item5 = float(data['start_time_item5_var']) player.time_is_up = float(data['time_is_up_var']) def live_method_item5(player: Player, data): player.endtime_game = float(data['endtime_game_var']) player.time_is_up = float(data['time_is_up_var']) class AssignParticipants(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): group = player.group import time player.study_start_time = time.time() # Group 1: Easy -> Difficult & Low TP -> High TP # Group 2: Difficult -> Easy & Low TP -> High TP # Group 3: Easy -> Difficult & High TP -> Low TP # Group 4: Difficult -> Easy & High TP -> Low TP import math num_treatment = sum(x > 0 for x in [C.TREAT1_PAR_N, C.TREAT2_PAR_N, C.TREAT3_PAR_N, C.TREAT4_PAR_N]) group_num = math.ceil(player.id_in_group / num_treatment) r = player.id_in_group - (group_num - 1) *num_treatment tmpt_group = 0 if (C.TREAT1_PAR_N >0): tmpt_group = tmpt_group + 1 tmpt_group1 = tmpt_group else: tmpt_group1 = 0 if (C.TREAT2_PAR_N >0): tmpt_group = tmpt_group + 1 tmpt_group2 = tmpt_group else: tmpt_group2 = 0 if (C.TREAT3_PAR_N >0): tmpt_group = tmpt_group + 1 tmpt_group3 = tmpt_group else: tmpt_group3 = 0 if (C.TREAT4_PAR_N >0): tmpt_group = tmpt_group + 1 tmpt_group4 = tmpt_group else: tmpt_group4 = 0 if (r <= tmpt_group1): player.treatment_group = 1 elif (r <= tmpt_group2): player.treatment_group = 2 elif (r <= tmpt_group3): player.treatment_group = 3 elif (r <= tmpt_group4): player.treatment_group = 4 # Treatment Group 1 if (player.treatment_group == 1): player.information_scenario1 = C.INFO_EASY player.table_scenario1 = C.TABLE_EASY player.information_scenario2 = C.INFO_DIFF player.table_scenario2 = C.TABLE_DIFF player.action_scenario1 = C.ACTION_EASY player.action_scenario2 = C.ACTION_DIFF player.timelimit_q1 = str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + " seconds (short)" player.timelimit_q1sec = str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) player.timelimit_q2 = str(int(round(C.TIMELIMIT_EASY_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q2sec = C.TIMELIMIT_EASY_MEDIUM player.timelimit_q3 = str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds (long)" player.timelimit_q4 = str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + " seconds (short)" player.timelimit_q5 = str(int(round(C.TIMELIMIT_DIFF_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q6 = str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds (long)" player.cashier_time_stmt_scenario1 = "Between " + str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds" player.cashier_time_stmt_scenario2 = "Between " + str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds" # Treatment Group 2 if (player.treatment_group == 2): player.information_scenario1 = C.INFO_DIFF player.table_scenario1 = C.TABLE_DIFF player.information_scenario2 = C.INFO_EASY player.table_scenario2 = C.TABLE_EASY player.action_scenario1 = C.ACTION_DIFF player.action_scenario2 = C.ACTION_EASY player.timelimit_q1 = str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + " seconds (short)" player.timelimit_q1sec = str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) player.timelimit_q2 = str(int(round(C.TIMELIMIT_DIFF_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q2sec = C.TIMELIMIT_DIFF_MEDIUM player.timelimit_q3 = str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds (long)" player.timelimit_q4 = str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + " seconds (short)" player.timelimit_q5 = str(int(round(C.TIMELIMIT_EASY_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q6 = str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds (long)" player.cashier_time_stmt_scenario1 = "Between " + str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds" player.cashier_time_stmt_scenario2 = "Between " + str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds" # Treatment Group 3 if (player.treatment_group == 3): player.information_scenario1 = C.INFO_EASY player.table_scenario1 = C.TABLE_EASY player.information_scenario2 = C.INFO_DIFF player.table_scenario2 = C.TABLE_DIFF player.action_scenario1 = C.ACTION_EASY player.action_scenario2 = C.ACTION_DIFF player.timelimit_q1 = str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds (long)" player.timelimit_q1sec = str(int(round(C.TIMELIMIT_EASY_LONG, 0))) player.timelimit_q2 = str(int(round(C.TIMELIMIT_EASY_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q2sec = C.TIMELIMIT_EASY_MEDIUM player.timelimit_q3 = str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + " seconds (short)" player.timelimit_q4 = str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds (long)" player.timelimit_q5 = str(int(round(C.TIMELIMIT_DIFF_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q6 = str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + " seconds (short)" player.cashier_time_stmt_scenario1 = "Between " + str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds" player.cashier_time_stmt_scenario2 = "Between " + str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds" # Treatment Group 4 if (player.treatment_group == 4): player.information_scenario1 = C.INFO_DIFF player.table_scenario1 = C.TABLE_DIFF player.information_scenario2 = C.INFO_EASY player.table_scenario2 = C.TABLE_EASY player.action_scenario1 = C.ACTION_DIFF player.action_scenario2 = C.ACTION_EASY player.timelimit_q1 = str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds (long)" player.timelimit_q1sec = str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) player.timelimit_q2 = str(int(round(C.TIMELIMIT_DIFF_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q2sec = C.TIMELIMIT_DIFF_MEDIUM player.timelimit_q3 = str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + " seconds (short)" player.timelimit_q4 = str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds (long)" player.timelimit_q5 = str(int(round(C.TIMELIMIT_EASY_MEDIUM, 0))) + " seconds (medium)" player.timelimit_q6 = str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + " seconds (short)" player.cashier_time_stmt_scenario1 = "Between " + str(int(round(C.TIMELIMIT_DIFF_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_DIFF_LONG, 0))) + " seconds" player.cashier_time_stmt_scenario2 = "Between " + str(int(round(C.TIMELIMIT_EASY_SHORT, 0))) + "-" + str(int(round(C.TIMELIMIT_EASY_LONG, 0))) + " seconds" # Cashier Checkout time import numpy as np if player.treatment_group == 1 or player.treatment_group == 3: mu, sigma = C.CHECKOUT_TIME_MU_EASY, C.CHECKOUT_TIME_SD_EASY np.random.seed(seed=None) s = np.random.lognormal(mu, sigma, 5) s[0] = np.min([np.max([s[0], C.CASHIER_TIME_LB_EASY]), C.CASHIER_TIME_UB_EASY]) s[1] = np.min([np.max([s[1], C.CASHIER_TIME_LB_EASY]), C.CASHIER_TIME_UB_EASY]) s[2] = np.min([np.max([s[2], C.CASHIER_TIME_LB_EASY]), C.CASHIER_TIME_UB_EASY]) s[3] = np.min([np.max([s[3], C.CASHIER_TIME_LB_EASY]), C.CASHIER_TIME_UB_EASY]) s[4] = np.min([np.max([s[4], C.CASHIER_TIME_LB_EASY]), C.CASHIER_TIME_UB_EASY]) elif player.treatment_group == 2 or player.treatment_group == 4: mu, sigma = C.CHECKOUT_TIME_MU_DIFF, C.CHECKOUT_TIME_SD_DIFF np.random.seed(seed=None) s = np.random.lognormal(mu, sigma, 5) s[0] = np.min([np.max([s[0], C.CASHIER_TIME_LB_DIFF]), C.CASHIER_TIME_UB_DIFF]) s[1] = np.min([np.max([s[1], C.CASHIER_TIME_LB_DIFF]), C.CASHIER_TIME_UB_DIFF]) s[2] = np.min([np.max([s[2], C.CASHIER_TIME_LB_DIFF]), C.CASHIER_TIME_UB_DIFF]) s[3] = np.min([np.max([s[3], C.CASHIER_TIME_LB_DIFF]), C.CASHIER_TIME_UB_DIFF]) s[4] = np.min([np.max([s[4], C.CASHIER_TIME_LB_DIFF]), C.CASHIER_TIME_UB_DIFF]) player.cashier_time_1 = s[0] player.cashier_time_2 = s[1] player.cashier_time_3 = s[2] player.cashier_time_4 = s[3] player.cashier_time_5 = s[4] return False class ConsentDisclosure(Page): form_model = 'player' class InstructionQuiz(Page): form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4', 'quiz5', 'quiz6', 'quiz7', 'quiz8', 'quiz9'] @staticmethod def error_message(player: Player, values): group = player.group solutions = dict(quiz1='a' , quiz2='a' , quiz3='a' , quiz4='b' , quiz5='d' , quiz6='e' , quiz7='d' , quiz8='c' , quiz9='b') if player.treatment_group == 2 or player.treatment_group == 4: solutions["quiz3"] = "c" solutions["quiz4"] = "a" incorrect_list = [] player.num_correct_quiz = 9 if values["quiz1"] != solutions["quiz1"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(1) if values["quiz2"] != solutions["quiz2"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(2) if values["quiz3"] != solutions["quiz3"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(3) if values["quiz4"] != solutions["quiz4"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(4) if values["quiz5"] != solutions["quiz5"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(5) if values["quiz6"] != solutions["quiz6"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(6) if values["quiz7"] != solutions["quiz7"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(7) if values["quiz8"] != solutions["quiz8"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(8) if values["quiz9"] != solutions["quiz9"]: player.num_correct_quiz = player.num_correct_quiz - 1 incorrect_list.append(9) player.incorrect_quiz_num_list = str(incorrect_list)[1:-1] player.num_incorrect_quiz = 9-player.num_correct_quiz if player.num_correct_quiz == 9: player.quiz_failed_attempts = 999 if player.num_correct_quiz != 9: player.quiz_failed_attempts += 1 player.quiz_attempt_left = 3 - player.quiz_failed_attempts if player.quiz_failed_attempts < 3: return "Quiz ", str(incorrect_list)[1:-1], " were answered incorrectly. Please fix. You have " + str(3 - player.quiz_failed_attempts) + " attempts left." errors = {name: 'Incorrect' for name in solutions if values[name] != solutions[name]} if errors and player.quiz_failed_attempts < 3: return errors class FailQuiz(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): if player.in_round(1).quiz_failed_attempts == 3: return True else: return False class PassQuizCongrats(Page): form_model = 'player' class Survey_Part1(Page): form_model = 'player' form_fields = ['p1survey1', 'p1survey2', 'p1survey3', 'p1survey4', 'p1survey5', 'p1survey6', 'p1survey7', 'p1survey8'] class Survey_Part1_Complete(Page): form_model = 'player' class Survey_Part2_Practice(Page): form_model = 'player' class Practice_Scenario1(Page): form_model = 'player' class Practice_Game1(Page): form_model = 'player' @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group) class Practice_Scenario2(Page): form_model = 'player' class Practice_Game2(Page): form_model = 'player' @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group) class Survey_Part2_Practice_Complete(Page): form_model = 'player' class Survey_Part2(Page): form_model = 'player' live_method = 'live_method_sp2' class ChooseQuestionAssignMethod(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): import random if player.co_method_randnum == 0: player.co_method_randnum = random.randint(1, 100) if player.co_method_randnum > player.cashier_preference2: player.co_method = "Self checkout" else: player.co_method = "Cashier checkout" return True class PreGamePage(Page): form_model = 'player' live_method = 'live_method_pgp' class Item1(Page): form_model = 'player' live_method = 'live_method_item1' @staticmethod def is_displayed(player: Player): group = player.group # Shuffle Categories import random random.seed(player.id_in_group) cat_array = ["Fruit", "Coffee", "Seafood", "Vege", "Meat"]; random.shuffle(cat_array) player.cat_1 = cat_array[0] player.cat_2 = cat_array[1] player.cat_3 = cat_array[2] player.cat_4 = cat_array[3] player.cat_5 = cat_array[4] # Items fruit_list = ["Peach","Blueberry","Mango","Cherry","Watermelon","Lemon","Orange","Pear","Grapes","Pineapple","Raspberry","Kiwi","Apricot","Lychee","Grapefruit","Apple","Guava","Banana","Papaya","Cantaloup","Nectarine","Pomegranate","Plum","Mandarin","Jackfruit","Melon","Coconut","Dragon Fruit","Cloudberry","Pineberry","Passionfruit","Tamarillo","Tamarind","Tangelo","Tayberry","Lime","Loquat","Longan","Feijoa","Fig"] coffee_list = ["Arabica","Bourbon","Catimor","Catuai","Caturra","Excelsa","Geisha","Icatu","Jackson","Jamaican","Jember","Kent","Kona Typica","Liberica","Maracatu","Maragogype","Mocca","Mundo","Pacamara","Pacas","Arusha","Benguet","Bernardina","Charrier","Harar","Sidamo","Yirgacheffe","Bonifieur","Kona","Java","Maragogipe","Maragaturra","Mocha","Sagada","Santos","Sarchimor","Typica","Uganda","Brutte","Starmaya"] seafood_list = ["Anchovies","Anglerfish","Barracuda","Bass","Blowfish","Bluefish","Bonito","Bream","Burbot","Carp","Catfish","Dogfish","Dorade","Flounder","Grouper","Haddock","Halibut","Herring","Lamprey","Monkfish","Mullet","Parrotfish","Perch","Pike","Pilchard","Pollock","Pomfret","Pompano","Sablefish","Sardine","Shark","Skate","Sturgeon","Surimi","Swordfish","Tilapia","Tilefish","Turbot","Wahoo","Whiting"] vege_list = ["Artichokes","Arugula","Asparagus","Avocados","Basil","Beets","Broccoli","Carrots","Cauliflower","Chard","Corn","Cucumber","Eggplant","Fennel","Fiddleheads","Garlic","Green Onions","Kohlrabi","Morels","Mushrooms","Nettles","Lettuce","Okra","Parsley","Potatoes","Radish","Rhubarb","Spinach","Spring Onions","Tomatoes","Turnips","Bok Choy","Broccolini","Cabbage","Celeriac","Celery","Daikon","Parsnips","Kale","Leeks"] meat_list = ["Ribeye Steak","Rib Roast","Arm Roast","Chuck Roast","Chuck Steak","Brisket","T-Bone Steak","Sirloin Steak","Short Ribs","Flank Steak","Round Steak","Cube Steak","Rump Roast","Ground Beef","Stew Meat","Soup Bones","Chicken Breast","Chicken Thighs","Chicken Wings","Chicken Liver","Chicken Heart","Gizzard","Bacon","Ham","Pork Belly","Pork Rib Roast","Pork Ribs","Pork Steak","Pork Tenderloin","Pork Shoulder","Sausage","Pork Chops","Ground Pork","Lamb Rib","Lamb Shank","Lamb Breast","Lamb Sirloin","Lamb Neck","Pekin Duck","Turkey"] price = { "Peach" : 1.3, "Blueberry" : 5.4, "Mango" : 3.8, "Cherry" : 6.6, "Watermelon" : 2.7, "Lemon" : 4.9, "Orange" : 1.2, "Pear" : 3.9, "Grapes" : 3.2, "Pineapple" : 1.5, "Raspberry" : 6.3, "Kiwi" : 4.3, "Apricot" : 4.2, "Lychee" : 6.6, "Grapefruit" : 3.6, "Apple" : 3.4, "Guava" : 4.6, "Banana" : 3.3, "Papaya" : 2.9, "Cantaloup" : 4.5, "Nectarine" : 5.4, "Pomegranate" : 6.0, "Plum" : 3.6, "Mandarin" : 3.1, "Jackfruit" : 0.4, "Melon" : 3.6, "Coconut" : 6.0, "Dragon Fruit" : 1.7, "Cloudberry" : 3.5, "Pineberry" : 6.4, "Passionfruit" : 3.1, "Tamarillo" : 6.1, "Tamarind" : 5.1, "Tangelo" : 3.6, "Tayberry" : 6.3, "Lime" : 4.4, "Loquat" : 5.0, "Longan" : 1.8, "Feijoa" : 6.9, "Fig" : 6.6, "Arabica" : 6.2, "Bourbon" : 4.6, "Catimor" : 5.1, "Catuai" : 1.6, "Caturra" : 3.5, "Excelsa" : 4.5, "Geisha" : 3.1, "Icatu" : 1.4, "Jackson" : 2.5, "Jamaican" : 4.1, "Jember" : 0.7, "Kent" : 1.0, "Kona Typica" : 3.1, "Liberica" : 0.4, "Maracatu" : 5.9, "Maragogype" : 5.8, "Mocca" : 3.3, "Mundo" : 0.5, "Pacamara" : 4.5, "Pacas" : 0.6, "Arusha" : 1.7, "Benguet" : 1.3, "Bernardina" : 4.5, "Charrier" : 0.9, "Harar" : 6.4, "Sidamo" : 6.7, "Yirgacheffe" : 2.2, "Bonifieur" : 5.4, "Kona" : 2.6, "Java" : 4.2, "Maragogipe" : 3.6, "Maragaturra" : 6.0, "Mocha" : 4.7, "Sagada" : 1.9, "Santos" : 6.1, "Sarchimor" : 1.6, "Typica" : 5.7, "Uganda" : 6.3, "Brutte" : 4.2, "Starmaya" : 6.1, "Anchovies" : 0.9, "Anglerfish" : 2.1, "Barracuda" : 1.7, "Bass" : 5.2, "Blowfish" : 1.5, "Bluefish" : 3.5, "Bonito" : 0.2, "Bream" : 4.0, "Burbot" : 0.1, "Carp" : 6.1, "Catfish" : 6.2, "Dogfish" : 3.3, "Dorade" : 5.9, "Flounder" : 1.2, "Grouper" : 0.1, "Haddock" : 2.1, "Halibut" : 0.1, "Herring" : 1.9, "Lamprey" : 4.1, "Monkfish" : 1.6, "Mullet" : 1.1, "Parrotfish" : 4.8, "Perch" : 4.3, "Pike" : 6.9, "Pilchard" : 4.0, "Pollock" : 2.0, "Pomfret" : 2.5, "Pompano" : 2.2, "Sablefish" : 1.7, "Sardine" : 0.8, "Shark" : 1.4, "Skate" : 5.8, "Sturgeon" : 1.5, "Surimi" : 5.8, "Swordfish" : 5.1, "Tilapia" : 4.6, "Tilefish" : 3.1, "Turbot" : 6.4, "Wahoo" : 0.9, "Whiting" : 4.0, "Artichokes" : 2.1, "Arugula" : 3.9, "Asparagus" : 0.3, "Avocados" : 4.6, "Basil" : 4.4, "Beets" : 5.4, "Broccoli" : 5.6, "Carrots" : 1.0, "Cauliflower" : 5.4, "Chard" : 2.1, "Corn" : 4.5, "Cucumber" : 2.6, "Eggplant" : 1.4, "Fennel" : 6.0, "Fiddleheads" : 1.0, "Garlic" : 0.9, "Green Onions" : 1.5, "Kohlrabi" : 0.5, "Morels" : 2.5, "Mushrooms" : 4.9, "Nettles" : 2.3, "Lettuce" : 1.5, "Okra" : 2.5, "Parsley" : 0.5, "Potatoes" : 3.1, "Radish" : 0.9, "Rhubarb" : 6.1, "Spinach" : 4.7, "Spring Onions" : 4.5, "Tomatoes" : 3.4, "Turnips" : 4.1, "Bok Choy" : 5.5, "Broccolini" : 3.6, "Cabbage" : 3.8, "Celeriac" : 3.0, "Celery" : 3.4, "Daikon" : 4.4, "Parsnips" : 3.1, "Kale" : 4.9, "Leeks" : 0.4, "Ribeye Steak" : 6.3, "Rib Roast" : 7.0, "Arm Roast" : 6.1, "Chuck Roast" : 5.3, "Chuck Steak" : 0.4, "Brisket" : 1.0, "T-Bone Steak" : 2.6, "Sirloin Steak" : 4.8, "Short Ribs" : 1.8, "Flank Steak" : 1.1, "Round Steak" : 1.1, "Cube Steak" : 4.2, "Rump Roast" : 5.9, "Ground Beef" : 2.2, "Stew Meat" : 7.0, "Soup Bones" : 2.3, "Chicken Breast" : 0.9, "Chicken Thighs" : 3.8, "Chicken Wings" : 2.1, "Chicken Liver" : 6.4, "Chicken Heart" : 0.7, "Gizzard" : 5.9, "Bacon" : 5.9, "Ham" : 3.6, "Pork Belly" : 2.4, "Pork Rib Roast" : 2.5, "Pork Ribs" : 3.8, "Pork Steak" : 2.4, "Pork Tenderloin" : 3.9, "Pork Shoulder" : 6.7, "Sausage" : 0.2, "Pork Chops" : 1.4, "Ground Pork" : 5.9, "Lamb Rib" : 1.7, "Lamb Shank" : 1.0, "Lamb Breast" : 1.2, "Lamb Sirloin" : 6.9, "Lamb Neck" : 3.6, "Pekin Duck" : 4.8, "Turkey" : 4.6 } weight = { "Peach" : 5.0, "Blueberry" : 5.5, "Mango" : 4.0, "Cherry" : 3.5, "Watermelon" : 6.0, "Lemon" : 6.5, "Orange" : 8.5, "Pear" : 5.0, "Grapes" : 7.5, "Pineapple" : 4.0, "Raspberry" : 5.0, "Kiwi" : 0.5, "Apricot" : 6.5, "Lychee" : 8.0, "Grapefruit" : 4.0, "Apple" : 5.5, "Guava" : 4.5, "Banana" : 7.0, "Papaya" : 9.0, "Cantaloup" : 8.5, "Nectarine" : 2.0, "Pomegranate" : 1.0, "Plum" : 3.5, "Mandarin" : 9.0, "Jackfruit" : 8.0, "Melon" : 2.5, "Coconut" : 3.0, "Dragon Fruit" : 3.5, "Cloudberry" : 9.0, "Pineberry" : 1.0, "Passionfruit" : 2.0, "Tamarillo" : 8.5, "Tamarind" : 7.5, "Tangelo" : 0.5, "Tayberry" : 2.0, "Lime" : 3.5, "Loquat" : 6.0, "Longan" : 7.5, "Feijoa" : 6.5, "Fig" : 2.5, "Arabica" : 1.0, "Bourbon" : 3.0, "Catimor" : 5.5, "Catuai" : 6.0, "Caturra" : 9.0, "Excelsa" : 3.0, "Geisha" : 6.0, "Icatu" : 7.0, "Jackson" : 9.0, "Jamaican" : 0.5, "Jember" : 1.5, "Kent" : 0.5, "Kona Typica" : 9.0, "Liberica" : 3.0, "Maracatu" : 1.5, "Maragogype" : 4.5, "Mocca" : 9.0, "Mundo" : 6.5, "Pacamara" : 5.0, "Pacas" : 0.5, "Arusha" : 3.0, "Benguet" : 0.5, "Bernardina" : 6.5, "Charrier" : 3.0, "Harar" : 5.5, "Sidamo" : 5.5, "Yirgacheffe" : 1.0, "Bonifieur" : 4.0, "Kona" : 7.0, "Java" : 2.5, "Maragogipe" : 4.0, "Maragaturra" : 9.0, "Mocha" : 2.5, "Sagada" : 4.5, "Santos" : 5.0, "Sarchimor" : 3.0, "Typica" : 7.0, "Uganda" : 3.5, "Brutte" : 4.0, "Starmaya" : 8.5, "Anchovies" : 5.0, "Anglerfish" : 9.0, "Barracuda" : 3.0, "Bass" : 5.0, "Blowfish" : 5.0, "Bluefish" : 5.0, "Bonito" : 3.0, "Bream" : 9.0, "Burbot" : 4.0, "Carp" : 8.5, "Catfish" : 3.0, "Dogfish" : 4.0, "Dorade" : 1.0, "Flounder" : 9.0, "Grouper" : 3.5, "Haddock" : 6.0, "Halibut" : 6.0, "Herring" : 6.5, "Lamprey" : 6.5, "Monkfish" : 7.5, "Mullet" : 0.5, "Parrotfish" : 0.5, "Perch" : 9.0, "Pike" : 7.5, "Pilchard" : 9.0, "Pollock" : 1.0, "Pomfret" : 2.5, "Pompano" : 9.0, "Sablefish" : 1.5, "Sardine" : 8.5, "Shark" : 3.5, "Skate" : 1.5, "Sturgeon" : 8.0, "Surimi" : 4.0, "Swordfish" : 6.0, "Tilapia" : 8.5, "Tilefish" : 3.0, "Turbot" : 4.5, "Wahoo" : 6.0, "Whiting" : 4.0, "Artichokes" : 2.5, "Arugula" : 9.0, "Asparagus" : 8.0, "Avocados" : 2.0, "Basil" : 3.5, "Beets" : 5.5, "Broccoli" : 3.0, "Carrots" : 1.5, "Cauliflower" : 6.5, "Chard" : 7.5, "Corn" : 7.0, "Cucumber" : 5.0, "Eggplant" : 6.5, "Fennel" : 4.5, "Fiddleheads" : 3.0, "Garlic" : 9.0, "Green Onions" : 9.0, "Kohlrabi" : 2.0, "Morels" : 7.5, "Mushrooms" : 1.5, "Nettles" : 0.5, "Lettuce" : 8.0, "Okra" : 5.0, "Parsley" : 8.0, "Potatoes" : 5.0, "Radish" : 0.5, "Rhubarb" : 4.0, "Spinach" : 8.0, "Spring Onions" : 6.0, "Tomatoes" : 5.5, "Turnips" : 2.5, "Bok Choy" : 7.5, "Broccolini" : 4.0, "Cabbage" : 7.0, "Celeriac" : 5.0, "Celery" : 4.5, "Daikon" : 1.0, "Parsnips" : 4.0, "Kale" : 4.0, "Leeks" : 5.0, "Ribeye Steak" : 4.0, "Rib Roast" : 1.0, "Arm Roast" : 9.0, "Chuck Roast" : 6.0, "Chuck Steak" : 4.0, "Brisket" : 3.0, "T-Bone Steak" : 0.5, "Sirloin Steak" : 4.5, "Short Ribs" : 1.5, "Flank Steak" : 9.0, "Round Steak" : 4.5, "Cube Steak" : 1.5, "Rump Roast" : 7.5, "Ground Beef" : 7.5, "Stew Meat" : 7.0, "Soup Bones" : 3.0, "Chicken Breast" : 3.0, "Chicken Thighs" : 1.5, "Chicken Wings" : 3.5, "Chicken Liver" : 3.5, "Chicken Heart" : 1.0, "Gizzard" : 9.0, "Bacon" : 7.5, "Ham" : 3.0, "Pork Belly" : 7.5, "Pork Rib Roast" : 0.5, "Pork Ribs" : 2.0, "Pork Steak" : 4.5, "Pork Tenderloin" : 8.0, "Pork Shoulder" : 6.5, "Sausage" : 3.5, "Pork Chops" : 7.0, "Ground Pork" : 4.0, "Lamb Rib" : 6.0, "Lamb Shank" : 4.5, "Lamb Breast" : 5.0, "Lamb Sirloin" : 2.5, "Lamb Neck" : 8.5, "Pekin Duck" : 5.5, "Turkey" : 9.0 } item = { "Fruit" : random.choice(fruit_list), "Coffee" : random.choice(coffee_list), "Seafood" : random.choice(seafood_list), "Vege" : random.choice(vege_list), "Meat" : random.choice(meat_list) } player.item_1 = item[player.cat_1] player.item_2 = item[player.cat_2] player.item_3 = item[player.cat_3] player.item_4 = item[player.cat_4] player.item_5 = item[player.cat_5] player.p_1 = price[player.item_1] player.p_2 = price[player.item_2] player.p_3 = price[player.item_3] player.p_4 = price[player.item_4] player.p_5 = price[player.item_5] player.w_1 = weight[player.item_1] player.w_2 = weight[player.item_2] player.w_3 = weight[player.item_3] player.w_4 = weight[player.item_4] player.w_5 = weight[player.item_5] return True @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group, item_1 = player.item_1, cat_1 = player.cat_1, w_1 = player.w_1, p_1 = player.p_1, item_2 = player.item_2, item_3 = player.item_3, item_4 = player.item_4, item_5 = player.item_5, checkout_bonus_time = player.timelimit_q2sec, start_time_item1 = player.start_time_item1, cashier_time_1 = player.cashier_time_1, cashier_time_2 = player.cashier_time_2, cashier_time_3 = player.cashier_time_3, cashier_time_4 = player.cashier_time_4, cashier_time_5 = player.cashier_time_5, co_method = player.co_method ) class Item2(Page): form_model = 'player' live_method = 'live_method_item2' @staticmethod def is_displayed(player: Player): if player.co_method == "Self checkout" and player.time_is_up == 0: return True else: return False @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group, item_2 = player.item_2, cat_2 = player.cat_2, w_2 = player.w_2, p_2 = player.p_2, checkout_bonus_time = player.timelimit_q2sec, start_time_item1 = player.start_time_item1 ) class Item3(Page): form_model = 'player' live_method = 'live_method_item3' @staticmethod def is_displayed(player: Player): if player.co_method == "Self checkout" and player.time_is_up == 0: return True else: return False @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group, item_3 = player.item_3, cat_3 = player.cat_3, w_3 = player.w_3, p_3 = player.p_3, checkout_bonus_time = player.timelimit_q2sec, start_time_item1 = player.start_time_item1 ) class Item4(Page): form_model = 'player' live_method = 'live_method_item4' @staticmethod def is_displayed(player: Player): if player.co_method == "Self checkout" and player.time_is_up == 0: return True else: return False @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group, item_4 = player.item_4, cat_4 = player.cat_4, w_4 = player.w_4, p_4 = player.p_4, checkout_bonus_time = player.timelimit_q2sec, start_time_item1 = player.start_time_item1 ) class Item5(Page): form_model = 'player' live_method = 'live_method_item5' @staticmethod def is_displayed(player: Player): if player.co_method == "Self checkout" and player.time_is_up == 0: return True else: return False @staticmethod def js_vars(player: Player): group = player.group return dict(treatment_group = player.treatment_group, item_5 = player.item_5, cat_5 = player.cat_5, w_5 = player.w_5, p_5 = player.p_5, checkout_bonus_time = player.timelimit_q2sec, start_time_item1 = player.start_time_item1 ) class AmostDone(Page): form_model = 'player' class FinalSurvey(Page): form_model = 'player' form_fields = ['surveyage', 'surveygender', 'surveyedu', 'surveydevice'] @staticmethod def error_message(player: Player, values): num_answered_survey = 0 if values["surveyage"] > 0: num_answered_survey = num_answered_survey + 1 if values["surveygender"] > 0: num_answered_survey = num_answered_survey + 1 if values["surveyedu"] > 0: num_answered_survey = num_answered_survey + 1 if values["surveydevice"] > 0: num_answered_survey = num_answered_survey + 1 player.surveyage = values["surveyage"] player.surveygender = values["surveygender"] player.surveyedu = values["surveyedu"] player.surveydevice = values["surveydevice"] if num_answered_survey < 4: return "All questions must be answered to proceed. Please fix." class ProlificCompletion(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): participant = player.participant participant.finished = True import time player.study_end_time = time.time() if player.time_is_up == 0: player.payoff = C.BONUS_PAY return True page_sequence = [AssignParticipants, ConsentDisclosure, InstructionQuiz, FailQuiz, PassQuizCongrats, Survey_Part1, Survey_Part1_Complete, Survey_Part2_Practice, Practice_Scenario1, Practice_Game1, Practice_Scenario2, Practice_Game2, Survey_Part2_Practice_Complete, Survey_Part2, ChooseQuestionAssignMethod, PreGamePage, Item1, Item2, Item3, Item4, Item5, AmostDone, FinalSurvey, ProlificCompletion]