from otree.api import * import random import itertools import time from random import choice import re doc = """ """ author = 'Zeyu Qiu' def set_scale_choices_list(length): choices_list = [] for i in range(length): choices_list.append((i + 1, str(i + 1))) return choices_list def make_scale_field(label_string, length): return models.IntegerField( choices=set_scale_choices_list(length), widget=widgets.RadioSelectHorizontal, label=label_string # blank=True ) class C(BaseConstants): NAME_IN_URL = 'Indonesia_Luck_Merit' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 25 multiplier = 0.75 pounds = 200 fixed = 5000 class Subsession(BaseSubsession): pass def creating_session(subsession): # treatments for p in subsession.get_players(): if p.id_in_subsession: pressures = itertools.cycle([1,1,2,2]) for player in subsession.get_players(): player.code_treatment = next(pressures) if p.code_treatment == 1: p.treatment = "luck" elif p.code_treatment == 2: p.treatment = "merit" for player in subsession.get_players(): if player.treatment == "luck": if player.id_in_group == 1: player.type = 'high' player.my_endowment = 30 player.other_endowment = 10 elif player.id_in_group == 2: player.type = 'low' player.my_endowment = 10 player.other_endowment = 30 for p in subsession.get_players(): letter = [str('A'), str('B'), str('C'), str('D'), str('E'), str('F'), str('G'), str('H'), str('I'), str('J'), str('K'), str('L'), str('M'), str('N'), str('O'), str('P'), str('Q'), str('R'), str('S'), str('T'), str('U'), str('V'), str('W'), str('X'), str('Y'), str('Z')] p.random_letter_1 = random.choice(letter) p.random_letter_2 = random.choice(letter) for p in subsession.get_players(): rand = [int(1), int(2), int(3), int(4), int(5), int(6), int(7), int(8), int(9), int(10), int(11), int(12), int(13), int(14), int(15), int(16), int(17), int(18), int(19), int(20), int(21), int(22), int(23), int(24), int(25), int(26), int(27), int(28), int(29), int(30), int(31), int(32), int(33), int(34), int(35), int(36), int(37), int(38), int(39), int(40), int(41), int(42), int(43), int(44), int(45), int(46), int(47), int(48), int(49), int(50), int(51), int(52), int(53), int(54), int(55), int(56), int(57), int(58), int(59), int(60), int(61), int(62), int(63), int(64), int(65), int(66), int(67), int(68), int(69), int(70), int(71), int(72), int(73), int(74), int(75), int(76), int(77), int(78), int(79), int(80), int(81), int(82), int(83), int(84), int(85), int(86), int(87), int(88), int(89), int(90), int(91), int(92), int(93), int(94), int(95), int(96), int(97), int(98), int(99), int(100)] p.digits1 = random.choice(rand) rand.remove(p.digits1) p.digits2 = random.choice(rand) rand.remove(p.digits2) p.digits3 = random.choice(rand) rand.remove(p.digits3) p.digits4 = random.choice(rand) rand.remove(p.digits4) p.digits5 = random.choice(rand) rand.remove(p.digits5) p.digits6 = random.choice(rand) rand.remove(p.digits6) p.digits7 = random.choice(rand) rand.remove(p.digits7) p.digits8 = random.choice(rand) rand.remove(p.digits8) p.digits9 = random.choice(rand) rand.remove(p.digits9) p.digits10 = random.choice(rand) rand.remove(p.digits10) p.digits11 = random.choice(rand) rand.remove(p.digits11) p.digits12 = random.choice(rand) rand.remove(p.digits12) p.digits13 = random.choice(rand) rand.remove(p.digits13) p.digits14 = random.choice(rand) rand.remove(p.digits14) p.digits15 = random.choice(rand) rand.remove(p.digits15) p.digits16 = random.choice(rand) rand.remove(p.digits16) p.digits17 = random.choice(rand) rand.remove(p.digits17) p.digits18 = random.choice(rand) rand.remove(p.digits18) p.digits19 = random.choice(rand) rand.remove(p.digits19) p.digits20 = random.choice(rand) rand.remove(p.digits20) p.digits21 = random.choice(rand) rand.remove(p.digits21) p.digits22 = random.choice(rand) rand.remove(p.digits22) p.digits23 = random.choice(rand) rand.remove(p.digits23) p.digits24 = random.choice(rand) rand.remove(p.digits24) p.digits25 = random.choice(rand) rand.remove(p.digits25) p.digits26 = random.choice(rand) rand.remove(p.digits26) # roles and endowment for p in subsession.get_players(): if p.random_letter_1 == 'A': p.answer_1 = p.digits1 elif p.random_letter_1 == 'B': p.answer_1 = p.digits2 elif p.random_letter_1 == 'C': p.answer_1 = p.digits3 elif p.random_letter_1 == 'D': p.answer_1 = p.digits4 elif p.random_letter_1 == 'E': p.answer_1 = p.digits5 elif p.random_letter_1 == 'F': p.answer_1 = p.digits6 elif p.random_letter_1 == 'G': p.answer_1 = p.digits7 elif p.random_letter_1 == 'H': p.answer_1 = p.digits8 elif p.random_letter_1 == 'I': p.answer_1 = p.digits9 elif p.random_letter_1 == 'J': p.answer_1 = p.digits10 elif p.random_letter_1 == 'K': p.answer_1 = p.digits11 elif p.random_letter_1 == 'L': p.answer_1 = p.digits12 elif p.random_letter_1 == 'M': p.answer_1 = p.digits13 elif p.random_letter_1 == 'N': p.answer_1 = p.digits14 elif p.random_letter_1 == 'O': p.answer_1 = p.digits15 elif p.random_letter_1 == 'P': p.answer_1 = p.digits16 elif p.random_letter_1 == 'Q': p.answer_1 = p.digits17 elif p.random_letter_1 == 'R': p.answer_1 = p.digits18 elif p.random_letter_1 == 'S': p.answer_1 = p.digits19 elif p.random_letter_1 == 'T': p.answer_1 = p.digits20 elif p.random_letter_1 == 'U': p.answer_1 = p.digits21 elif p.random_letter_1 == 'V': p.answer_1 = p.digits22 elif p.random_letter_1 == 'W': p.answer_1 = p.digits23 elif p.random_letter_1 == 'X': p.answer_1 = p.digits24 elif p.random_letter_1 == 'Y': p.answer_1 = p.digits25 elif p.random_letter_1 == 'Z': p.answer_1 = p.digits26 for p in subsession.get_players(): if p.random_letter_2 == 'A': p.answer_2 = p.digits1 elif p.random_letter_2 == 'B': p.answer_2 = p.digits2 elif p.random_letter_2 == 'C': p.answer_2 = p.digits3 elif p.random_letter_2 == 'D': p.answer_2 = p.digits4 elif p.random_letter_2 == 'E': p.answer_2 = p.digits5 elif p.random_letter_2 == 'F': p.answer_2 = p.digits6 elif p.random_letter_2 == 'G': p.answer_2 = p.digits7 elif p.random_letter_2 == 'H': p.answer_2 = p.digits8 elif p.random_letter_2 == 'I': p.answer_2 = p.digits9 elif p.random_letter_2 == 'J': p.answer_2 = p.digits10 elif p.random_letter_2 == 'K': p.answer_2 = p.digits11 elif p.random_letter_2 == 'L': p.answer_2 = p.digits12 elif p.random_letter_2 == 'M': p.answer_2 = p.digits13 elif p.random_letter_2 == 'N': p.answer_2 = p.digits14 elif p.random_letter_2 == 'O': p.answer_2 = p.digits15 elif p.random_letter_2 == 'P': p.answer_2 = p.digits16 elif p.random_letter_2 == 'Q': p.answer_2 = p.digits17 elif p.random_letter_2 == 'R': p.answer_2 = p.digits18 elif p.random_letter_2 == 'S': p.answer_2 = p.digits19 elif p.random_letter_2 == 'T': p.answer_2 = p.digits20 elif p.random_letter_2 == 'U': p.answer_2 = p.digits21 elif p.random_letter_2 == 'V': p.answer_2 = p.digits22 elif p.random_letter_2 == 'W': p.answer_2 = p.digits23 elif p.random_letter_2 == 'X': p.answer_2 = p.digits24 elif p.random_letter_2 == 'Y': p.answer_2 = p.digits25 elif p.random_letter_2 == 'Z': p.answer_2 = p.digits26 # treatment in player section class Group(BaseGroup): select = models.IntegerField() class Player(BasePlayer): calc_page_start = models.FloatField() calc_page_duration = models.FloatField() code = models.StringField(label='') code_treatment = models.IntegerField() treatment = models.StringField() type = models.StringField() my_endowment = models.IntegerField() other_endowment = models.IntegerField() digits1 = models.IntegerField() digits2 = models.IntegerField() digits3 = models.IntegerField() digits4 = models.IntegerField() digits5 = models.IntegerField() digits6 = models.IntegerField() digits7 = models.IntegerField() digits8 = models.IntegerField() digits9 = models.IntegerField() digits10 = models.IntegerField() digits11 = models.IntegerField() digits12 = models.IntegerField() digits13 = models.IntegerField() digits14 = models.IntegerField() digits15 = models.IntegerField() digits16 = models.IntegerField() digits17 = models.IntegerField() digits18 = models.IntegerField() digits19 = models.IntegerField() digits20 = models.IntegerField() digits21 = models.IntegerField() digits22 = models.IntegerField() digits23 = models.IntegerField() digits24 = models.IntegerField() digits25 = models.IntegerField() digits26 = models.IntegerField() random_letter_1 = models.StringField() random_letter_2 = models.StringField() digit_response_1 = models.IntegerField(label='', min=0, max=100) digit_response_2 = models.IntegerField(label='', min=0, max=100) answer_1 = models.IntegerField() answer_2 = models.IntegerField() sum_of_correct = models.IntegerField(label='', initial=0) total_correct = models.IntegerField(label='', initial=0) other_correct = models.IntegerField(label='', initial=0) tie = models.StringField(initial='0') control_question = models.StringField( choices=[ ['1', 'I agree to take part. Take me to the study.'], ['2', 'I do not agree to take part in this study. Take me back to Besample.'], ], label="Do you agree to participate in this study?", widget=widgets.RadioSelect ) question1 = models.IntegerField( label="", min=0, ) question2 = models.IntegerField( label="", min=0, ) correct = models.IntegerField(label='', initial=0) totalNumCorrect = models.IntegerField() correct_prev = models.IntegerField(label='', initial=0) contribution = models.IntegerField( label="", min=0, ) ct_10_0 = models.IntegerField(min=0, max=10) ct_10_1 = models.IntegerField(min=0, max=10) ct_10_2 = models.IntegerField(min=0, max=10) ct_10_3 = models.IntegerField(min=0, max=10) ct_10_4 = models.IntegerField(min=0, max=10) ct_10_5 = models.IntegerField(min=0, max=10) ct_10_6 = models.IntegerField(min=0, max=10) ct_10_7 = models.IntegerField(min=0, max=10) ct_10_8 = models.IntegerField(min=0, max=10) ct_10_9 = models.IntegerField(min=0, max=10) ct_10_10 = models.IntegerField(min=0, max=10) ct_10_11 = models.IntegerField(min=0, max=10) ct_10_12 = models.IntegerField(min=0, max=10) ct_10_13 = models.IntegerField(min=0, max=10) ct_10_14 = models.IntegerField(min=0, max=10) ct_10_15 = models.IntegerField(min=0, max=10) ct_10_16 = models.IntegerField(min=0, max=10) ct_10_17 = models.IntegerField(min=0, max=10) ct_10_18 = models.IntegerField(min=0, max=10) ct_10_19 = models.IntegerField(min=0, max=10) ct_10_20 = models.IntegerField(min=0, max=10) ct_10_21 = models.IntegerField(min=0, max=10) ct_10_22 = models.IntegerField(min=0, max=10) ct_10_23 = models.IntegerField(min=0, max=10) ct_10_24 = models.IntegerField(min=0, max=10) ct_10_25 = models.IntegerField(min=0, max=10) ct_10_26 = models.IntegerField(min=0, max=10) ct_10_27 = models.IntegerField(min=0, max=10) ct_10_28 = models.IntegerField(min=0, max=10) ct_10_29 = models.IntegerField(min=0, max=10) ct_10_30 = models.IntegerField(min=0, max=10) ct_30_0 = models.IntegerField(min=0, max=30) ct_30_1 = models.IntegerField(min=0, max=30) ct_30_2 = models.IntegerField(min=0, max=30) ct_30_3 = models.IntegerField(min=0, max=30) ct_30_4 = models.IntegerField(min=0, max=30) ct_30_5 = models.IntegerField(min=0, max=30) ct_30_6 = models.IntegerField(min=0, max=30) ct_30_7 = models.IntegerField(min=0, max=30) ct_30_8 = models.IntegerField(min=0, max=30) ct_30_9 = models.IntegerField(min=0, max=30) ct_30_10 = models.IntegerField(min=0, max=30) contribution_2 = models.IntegerField( label="", min=0, ) contribution_estimate = models.IntegerField( label="", min=0, ) fair_contribute = models.IntegerField( label="", min=0, ) other_fair_contribute = models.IntegerField( label="", min=0, ) gender = models.StringField( choices=[ ['1', 'Laki-laki'], ['2', 'Perempuan'], ], label="1. Apa jenis kelamin Anda?", widget=widgets.RadioSelect ) other_gender_belief = models.StringField( choices=[ ['1', 'Laki-laki'], ['2', 'Perempuan'], ], label="2. Menurut Anda, apa jenis kelamin anggota kelompok yang dipasangkan dengan Anda pada Eksperimen 1?", widget=widgets.RadioSelect ) age = models.StringField( label="3. Berapa usia Anda (tahun, bulan)?", ) year = models.IntegerField( label="4. Anda berada di kelas berapa?", min=0, max=20 ) pocket = models.IntegerField( label="5. Berapa uang saku Anda dalam sehari?", min=0, ) max_income = models.StringField( choices=[ ['1', 'Sangat penting'], ['2', 'Penting'], ['3', 'Biasa saja'], ['4', 'Tidak penting'], ['5', 'Sangat tidak penting'], ], label="6. Seberapa penting bagi Anda untuk mendapatkan penghasilan sebanyak mungkin untuk diri sendiri selama eksperimen ini?", widget=widgets.RadioSelect ) trust = models.StringField( choices=[ ['1', 'Kebanyakan orang bisa dipercaya'], ['2', 'Anda harus sangat berhati-hati saat berurusan dengan orang lain'], ], label="7. Secara umum, menurut Anda apakah kebanyakan orang bisa dipercaya atau Anda harus sangat berhati-hati saat berurusan dengan orang lain?", widget=widgets.RadioSelect ) risk = models.StringField( choices=[ ['0', ''], ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) satisfied = models.StringField( choices=[ ['0', ''], ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) religious = models.StringField( choices=[ ['1', 'Sangat taat'], ['2', 'Taat'], ['3', 'Cukup taat'], ['4', 'Tidak taat'], ], label="10. Berdasarkan kehidupan Anda sehari-hari yang berkaitan dengan agama, menurut Anda seberapa taat Anda dalam menjalankan ajaran agama?", widget=widgets.RadioSelect ) instructions = models.StringField( choices=[ ['1', 'Sangat sulit'], ['2', 'Sulit'], ['3', 'Biasa saja'], ['4', 'Mudah'], ['5', 'Sangat mudah'], ], label="11. Bagaimana menurut Anda petunjuk/penjelasan dalam eksperimen ini?", widget=widgets.RadioSelect ) feedback = models.StringField( blank=True, label="12. Apakah Anda memiliki komentar atau masukan lain tentang eksperimen ini?", ) realized_contribution = models.IntegerField() other_contribution = models.IntegerField() other_contribution_2 = models.IntegerField() belief_points = models.IntegerField() other_belief = models.IntegerField() my_points_2 = models.FloatField() my_points = models.FloatField() bonus_earnings = models.FloatField() def question1_error_message(player, value): correct_unequal_q1 = 10 if value != correct_unequal_q1: error_unequal_q1 = "Jawaban: (10 - 0) + 0,75 × 0 = 10 poin" return error_unequal_q1 def question2_error_message(player, value): correct_unequal_q2 = 31 if value != correct_unequal_q2: error_unequal_q2 = "Jawaban: (30 - 8) + 0,75 × 12 = 31 poin" return error_unequal_q2 def digit_response_1_error_message(player, value): if value != player.answer_1: error_message = "Jawaban anda belum tepat, Silahkan coba lagi." return error_message def digit_response_2_error_message(player, value): if value != player.answer_2: error_message = "Jawaban anda belum tepat, Silahkan coba lagi." return error_message def contribution_error_message(player, value): contribution_answer_equal = player.my_endowment if value > contribution_answer_equal: error_message = "Anda tidak dapat memberikan kontribusi lebih besar dari jumlah token yang telah diberikan kepada Anda. Silakan coba lagi." return error_message def contribution_2_error_message(player, value): contribution_answer_equal = player.my_endowment if value > contribution_answer_equal: error_message = "Anda tidak dapat memberikan kontribusi lebih besar dari jumlah token yang telah diberikan kepada Anda. Silakan coba lagi." return error_message def contribution_estimate_error_message(player, value): contribution_estimate_answer_equal = player.other_endowment if value > contribution_estimate_answer_equal: error_message = "Tebakan Anda tidak boleh melebihi jumlah token yang telah diberikan kepada anggota kelompok lainnya. Silakan coba lagi." return error_message def fair_contribute_error_message(player, value): contribution_estimate_answer_equal = player.my_endowment if value > contribution_estimate_answer_equal: error_message = "Anda tidak dapat memberikan kontribusi lebih besar dari jumlah token yang telah diberikan kepada Anda. Silakan coba lagi." return error_message def other_fair_contribute_error_message(player, value): contribution_estimate_answer_equal = player.other_endowment if value > contribution_estimate_answer_equal: error_message = "Anggota kelompok yang lain tidak dapat berkontribusi lebih dari jumlah token yang telah diberikan kepada mereka. Silakan coba lagi." return error_message def set_payoffs(group): players = group.get_players() total_contribution2 = sum(p.contribution_2 for p in players) total_belief = sum(p.contribution_estimate for p in players) group.select = random.choice([0, 1]) selected_player = players[group.select] nonselected_player = players[1 - group.select] nonselected_player.realized_contribution = nonselected_player.contribution other_uncond = nonselected_player.contribution E = selected_player.my_endowment if E == 10: fieldname = f'ct_10_{other_uncond}' # other_uncond should be 0..30 in this treatment elif E == 30: fieldname = f'ct_30_{other_uncond}' # other_uncond should be 0..10 in this treatment else: raise ValueError(f"Unexpected endowment: {E}") selected_player.realized_contribution = getattr(selected_player, fieldname) total_contribution = selected_player.realized_contribution + nonselected_player.realized_contribution for p in players: other = p.get_others_in_group()[0] p.other_contribution = other.realized_contribution p.other_contribution_2 = total_contribution2 - p.contribution_2 diff = abs(p.contribution_estimate - p.other_contribution_2) if diff == 0: p.belief_points = 6 elif diff == 1: p.belief_points = 4 elif diff == 2: p.belief_points = 2 else: p.belief_points = 0 p.other_belief = total_belief - p.contribution_estimate # payoff in points (MPCR = 0.75) p.my_points = round((p.my_endowment - p.realized_contribution) + C.multiplier * total_contribution, 2) p.my_points_2 = round((p.my_endowment - p.contribution_2) + C.multiplier * total_contribution2 + p.belief_points, 2) # convert points -> pounds and add fixed fee p.bonus_earnings = round((p.my_points+p.my_points_2) * C.pounds, 2) # store total earnings in pounds in oTree's payoff field p.payoff = round(C.fixed + p.bonus_earnings, 2) class Welcome(Page): form_model = 'player' def is_displayed(player: Player): return player.round_number == 1 class Code(Page): form_model = 'player' form_fields = ['code'] def is_displayed(player: Player): return player.round_number == 1 class General_Instructions(Page): def is_displayed(player: Player): return player.round_number == 1 class Description(Page): def is_displayed(player: Player): return player.round_number == 1 class Questions(Page): form_model = 'player' form_fields = ['question1', 'question2'] def is_displayed(player: Player): return player.round_number == 1 class Experiment(Page): def is_displayed(player: Player): return player.round_number == 1 class Examples(Page): def is_displayed(player: Player): return player.round_number == 1 class countdown(Page): timeout_seconds = 5 def is_displayed(player: Player): return player.round_number == 1 def before_next_page(player: Player, timeout_happened): player.participant.vars['expiry'] = time.time() + (2 * 30) def get_timeout_seconds(player): return player.participant.vars['expiry'] - time.time() class RealEffort(Page): form_model = 'player' form_fields = ['digit_response_1', 'digit_response_2'] get_timeout_seconds = get_timeout_seconds def is_displayed(player): return get_timeout_seconds(player) > 1 def before_next_page(player: Player, timeout_happened): if player.answer_1 == player.digit_response_1 and player.answer_2 == player.digit_response_2: player.correct = 1 player.totalNumCorrect = sum([p.correct for p in player.in_all_rounds()]) if player.round_number != 0: player.in_round(player.round_number+1).correct_prev = player.in_round(player.round_number).totalNumCorrect else: player.correct_prev = 0 player.in_round(C.NUM_ROUNDS).total_correct = sum([p.correct for p in player.in_all_rounds()]) class WaitAfterTaskPage(WaitPage): body_text = "Please wait while the other participant in your group makes their decisions." def is_displayed(player): return player.round_number == 25 and player.treatment == "merit" def after_all_players_arrive(group: Group): for p in group.get_players(): p.in_round(C.NUM_ROUNDS).sum_of_correct = sum([p.in_round(C.NUM_ROUNDS).total_correct for p in group.get_players()]) p.in_round(C.NUM_ROUNDS).other_correct = p.in_round(C.NUM_ROUNDS).sum_of_correct - p.in_round(C.NUM_ROUNDS).total_correct for p in group.get_players(): if p.treatment == "merit": if p.total_correct > p.other_correct: p.type = "high" p.my_endowment = 30 p.other_endowment = 10 elif p.total_correct < p.other_correct: p.type = "low" p.my_endowment = 10 p.other_endowment = 30 elif p.total_correct == p.other_correct: if p.id_in_group == 1: p.type = "high" p.my_endowment = 30 p.other_endowment = 10 p.tie = "1" else: p.type = "low" p.my_endowment = 10 p.other_endowment = 30 p.tie = "1" class Contribution_decision(Page): form_model = 'player' form_fields = ['contribution'] def is_displayed(player): return player.round_number == 25 class Conditional(Page): form_model = 'player' form_fields = ['contribution'] def is_displayed(player): return player.round_number == 25 def get_form_fields(player): if player.my_endowment == 10: return [f'ct_10_{k}' for k in range(31)] # 0..30 elif player.my_endowment == 30: return [f'ct_30_{k}' for k in range(11)] # 0..10 class P2(Page): form_model = 'player' def is_displayed(player): return player.round_number == 25 class P2_Contribution_decision(Page): form_model = 'player' form_fields = ['contribution_2','contribution_estimate'] def is_displayed(player): return player.round_number == 25 class Q1(Page): form_model = 'player' def is_displayed(player): return player.round_number == 25 def get_form_fields(player: Player): return ['fair_contribute', 'other_fair_contribute'] class Final_Questionnaire(Page): form_model = 'player' form_fields = ['gender', 'other_gender_belief', 'age', 'year', 'pocket', 'max_income', 'trust', 'risk', 'satisfied', 'religious', 'instructions', 'feedback'] def is_displayed(player): return player.round_number == 25 class ResultsWaitPage(WaitPage): def is_displayed(player): return player.round_number == 25 after_all_players_arrive = set_payoffs class Thanks(Page): def is_displayed(player): return player.round_number == 25 def vars_for_template(player): group = player.group # group.select is 0/1; id_in_group is 1/2 selected_me = (group.select == player.id_in_group - 1) return dict(selected_me=selected_me, payoff_num=float(player.payoff)) page_sequence = [Welcome,Code,General_Instructions,Description, Questions,Experiment,Examples,countdown,RealEffort,WaitAfterTaskPage ,Contribution_decision,Conditional, P2,P2_Contribution_decision,Q1, Final_Questionnaire,ResultsWaitPage,Thanks]