import random from decimal import Decimal, ROUND_HALF_UP from otree.api import ( BaseConstants, BaseSubsession, BaseGroup, BasePlayer, WaitPage, Page, models, widgets ) doc = """ Your app description """ def round_half_up(x, ndigits=0): d = Decimal(str(x)) q = Decimal('1').scaleb(-ndigits) y = d.quantize(q, rounding=ROUND_HALF_UP) return float(y) if ndigits else int(y) # def creating_session(subsession): # condition = itertools.cycle(['Strong', 'Weak', 'None', 'Strong']) # if subsession.round_number == 1: # for group in subsession.get_groups(): # group.condition = next(condition) # for group_player in group.get_players(): # group_player.participant.condition = group.condition # elif subsession.round_number > 1: # for group in subsession.get_groups(): # group.condition = group.in_round(1).condition # if subsession.round_number == 1: # for group in subsession.get_groups(): # if group.id_in_subsession in range(1, 6): # group.condition = 'Strong' # elif group.id_in_subsession in range(6, 11): # group.condition = 'Weak' # else: # group.condition = 'None' # for group_player in group.get_players(): # group_player.participant.condition = group.condition # else: # subsession.group_like_round(1) class C(BaseConstants): NAME_IN_URL = 'MOTY2' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 12 Fixed = 3000 Show_Up = 5 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): workstation = models.StringField(label = 'Please enter the workstation number:') condition = models.StringField() sub_condition = models.StringField() sender_amount = models.IntegerField(initial=0, min=0, max=3000) other_sent = models.IntegerField() joint = models.IntegerField() joint_portion = models.FloatField() stage1compensation = models.FloatField() compensation = models.IntegerField(initial=0) identifier = models.IntegerField() approach = models.StringField( choices=[['LOW', 'LOW'], ['HIGH', 'HIGH']], doc="""Level of effort""", widget=widgets.RadioSelect, ) payment = models.IntegerField() #Comprehension Check questions def make_field(label): return models.IntegerField( choices=[[1, "True",], [2, "False"]], label=label, widget=widgets.RadioSelect, ) quiz1 = make_field("There will be two stages in today’s study.") quiz2 = make_field('You will be required to pass multiple quizzes before making any actual decisions.') quiz3 = make_field("In Stage 1, you and the other employee have the same compensation plan.") quiz4 = make_field('You and the other employee can invest between 0 and 3000 Lira in the joint project.') quiz5 = make_field('The joint project amount is not multiplied.') quiz6 = make_field('The joint project amount is equally shared among you and the other employee.') quiz7 = make_field('In Stage 2, you will be paired with the same participant as in Stage 1.') quiz8 = make_field('You will choose HIGH or LOW in each period of Stage 2.') quiz9 = make_field('The other employee will also choose HIGH or LOW in each period of Stage 2.') quiz10 = make_field('In Stage 2, you and the other employee have the same compensation plan.') quiz11 = make_field('Choosing HIGH or LOW costs the same amount to you.') quiz12 = make_field('You make the most money in a period when you choose LOW and the other employee in your company chooses HIGH.') quiz13 = make_field('Your company provides an individual bonus for choosing HIGH.') quiz14 = models.StringField( label = 'There are two different types of companies in terms of compensation plan. Which company gives a larger individual bonus for choosing HIGH?', choices = ['Type A', 'Type B'], widget=widgets.RadioSelect) quiz15 = make_field('There are two different types of companies in terms of individual bonuses.') quiz16a = make_field('Type A Company pays a 220 Lira individual bonus to any employee who chooses HIGH in a period.') quiz16b = make_field('Type A Company pays a 90 Lira individual bonus to any employee who chooses HIGH in a period.') quiz16c = make_field('The company pays a 90 Lira individual bonus to any employee who chooses HIGH in a period.') # quiz11b = models.StringField( # label = 'Your company gives ___ Lira as individual bonus to any employee that chooses HIGH in a period.', # choices = ['220', '90', '0'], # widget=widgets.RadioSelect) # quiz11c = models.StringField( # label = 'Your company gives ___ Lira as individual bonus to any employee that chooses HIGH in a period.', # choices = ['220', '90', '0'], # widget=widgets.RadioSelect) #Count of incorrect responses to Comprehension Check Questions incorrect_quiz1 = models.IntegerField(initial=0) incorrect_quiz2 = models.IntegerField(initial=0) incorrect_quiz3 = models.IntegerField(initial=0) incorrect_quiz4 = models.IntegerField(initial=0) incorrect_quiz5 = models.IntegerField(initial=0) incorrect_quiz6 = models.IntegerField(initial=0) incorrect_quiz7 = models.IntegerField(initial=0) incorrect_quiz8 = models.IntegerField(initial=0) incorrect_quiz9 = models.IntegerField(initial=0) incorrect_quiz10 = models.IntegerField(initial=0) incorrect_quiz11 = models.IntegerField(initial=0) incorrect_quiz12 = models.IntegerField(initial=0) incorrect_quiz13 = models.IntegerField(initial=0) incorrect_quiz14 = models.IntegerField(initial=0) incorrect_quiz15 = models.IntegerField(initial=0) incorrect_quiz16a = models.IntegerField(initial=0) incorrect_quiz16b = models.IntegerField(initial=0) incorrect_quiz16c = models.IntegerField(initial=0) #PEQs def make_field2(label): return models.IntegerField( choices=[[1, "Strongly disagree",], [2, "Disagree",], [3, "Somewhat disagree",], [4, "Neither agree nor disagree",], [5, "Somewhat agree",], [6, "Agree",], [7, "Strongly agree"] ], label=label, widget=widgets.RadioSelectHorizontal, ) peq1 = make_field2("I was upset that our company offered a smaller individual bonus than other companies. ") peq2 = make_field2("I appreciated that our company offered a larger individual bonus than other companies.") peq3 = make_field2("I thought the individual bonus from my company was fair.") peq4 = make_field2("I considered the amount of the individual bonus offered by the other company when evaluating the trustworthiness of my partner.") peq4b = make_field2("I considered the amount of the individual bonus when evaluating the trustworthiness of my partner.") peq5 = make_field2("I sympathized with people in other companies because their companies offered a smaller individual bonus than ours. ") peq6 = models.StringField( label = 'Are you generally a person who is fully prepared to take risks or do you try to avoid taking risks?', choices = ['1: Not at all willing to take risks', '2', '3', '4', '5', '6', '7: Very willing to take risks'], widget=widgets.RadioSelect) #Demographic Questions age = models.IntegerField(min = 18, max = 99, label = 'What is your age?') gender = models.StringField( label = 'What is your gender?', choices = ['Male', 'Female', 'Non-Binary', 'Prefer not to answer', 'Other'], widget=widgets.RadioSelect) gender2 = models.StringField( label = 'I identify as') def payoff(player: Player): players = player.group.get_players() player_approach = {} # player_approach[f'player{player.id_in_group}'] = player.approach current_round = None for i in players: player_approach[f'player{i.id_in_group}'] = i.approach if not current_round: current_round = i.round_number if player_approach['player1'] == 'LOW' and player_approach['player2'] == 'LOW': if player.sub_condition == 'None': players[0].payment = 790 players[1].payment = 790 elif player.sub_condition == 'Weak': players[0].payment = 790 players[1].payment = 790 elif player.sub_condition == 'Strong': players[0].payment = 790 players[1].payment = 790 elif player_approach['player1'] == 'HIGH' and player_approach['player2'] == 'HIGH': if player.sub_condition == 'None': players[0].payment = 850 players[1].payment = 850 elif player.sub_condition == 'Weak': players[0].payment = 940 players[1].payment = 940 elif player.sub_condition == 'Strong': players[0].payment = 1070 players[1].payment = 1070 elif player_approach['player1'] == 'HIGH': if player.sub_condition == 'None': players[0].payment = 640 players[1].payment = 1000 elif player.sub_condition == 'Weak': players[0].payment = 730 players[1].payment = 1000 elif player.sub_condition == 'Strong': players[0].payment = 860 players[1].payment = 1000 else: if player.sub_condition == 'None': players[0].payment = 1000 players[1].payment = 640 elif player.sub_condition == 'Weak': players[0].payment = 1000 players[1].payment = 730 elif player.sub_condition == 'Strong': players[0].payment = 1000 players[1].payment = 860 for i in players: if current_round > 1: last_round = i.in_round(current_round - 1) print(f'in payoff... in round {current_round}') i.compensation = i.payment + last_round.compensation i.participant.compensation = i.compensation else: i.compensation = i.payment # PAGES class Workstation(Page): @staticmethod def is_displayed(player: Player): player.condition = player.session.config['vars']['condition'] for group in player.subsession.get_groups(): if player.condition == 'WS': if player.group.id_in_subsession == 1: player.sub_condition = 'Strong' else: player.sub_condition = 'Weak' if player.condition == 'WN': if player.group.id_in_subsession == 1: player.sub_condition = 'None' else: player.sub_condition = 'Weak' if player.condition == 'WW': player.sub_condition = 'Weak' return player.round_number == 1 form_model = 'player' form_fields = ["workstation"] class Policy(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class TaskO(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 # @staticmethod # def before_next_page(player: Player, timeout_happened): # # print(player.group.condition) # if player.group.condition == "None": # player.participant.condition = "None" # elif player.group.condition == "Weak": # player.participant.condition = "Weak" # elif player.group.condition == "Strong": # player.participant.condition = "Strong" # # print(player.participant.condition) class Quiz1(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz1", "quiz2"] @staticmethod def error_message(player, values): solutions = dict( quiz1=1, quiz2=1 ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz1': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz1 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz2': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz2 += 1 return error_messages class Stage1(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz2(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz3"] @staticmethod def error_message(player, values): solutions = dict( quiz3=1, ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz3': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz3 += 1 return error_messages class Stage1Task(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz3(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz4", "quiz5", "quiz6"] @staticmethod def error_message(player, values): solutions = dict( quiz4=1, quiz5=2, quiz6=1 ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz4': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz4 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz5': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz5 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz6': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz6 += 1 return error_messages class SenderPage(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["sender_amount"] class Transition(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.sender_amount = player.sender_amount # print(player.participant.sender_amount) class Quiz4(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz7"] @staticmethod def error_message(player, values): solutions = dict( quiz7=1, ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz7': error_messages[field_name] = 'INCORRECT! Please try it again.' player.incorrect_quiz7 += 1 return error_messages class Stage2Task(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz5(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz8", "quiz9"] @staticmethod def error_message(player, values): solutions = dict( quiz8 = 1, quiz9 = 1 ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz8': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz8 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz9': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz9 += 1 return error_messages class Stage2Contract(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz6(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ["quiz10", "quiz11", "quiz12"] @staticmethod def error_message(player, values): solutions = dict( quiz10 = 1, quiz11 = 2, quiz12 = 1 ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz10': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz10 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz11': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz11 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz12': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz12 += 1 return error_messages class Stage2Bonus(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz7(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' # form_fields = ["quiz13", "quiz14"] def get_form_fields(player: Player): if player.condition == 'WN': return ["quiz14"] elif player.condition == 'WS': return ["quiz13", "quiz14"] elif player.condition == 'WW': return ["quiz13"] @staticmethod def error_message(player, values): if player.condition == 'WN': solutions = dict( quiz14 = 'Type A' ) if player.condition == 'WS': solutions = dict( quiz13 = 1, quiz14 = 'Type A' ) if player.condition == 'WW': solutions = dict( quiz13 = 1, ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz13': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz13 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz14': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz14 += 1 return error_messages class Stage2Role(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Quiz8(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' # form_fields = ["quiz13", "quiz14"] def get_form_fields(player: Player): if player.condition == 'WS': return ["quiz15", "quiz16a"] elif player.condition == 'WN': return ["quiz15", "quiz16b"] elif player.condition == 'WW': return ["quiz16c"] @staticmethod def error_message(player, values): if player.condition == 'WS': solutions = dict( quiz15 = 1, quiz16a = 1 ) if player.condition == 'WN': if player.sub_condition == "Weak": solutions = dict( quiz15 = 1, quiz16b = 1 ) if player.sub_condition == "None": solutions = dict( quiz15 = 1, quiz16b = 1 ) if player.condition == 'WW': solutions = dict( quiz16c = 1 ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name] and field_name == 'quiz15': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz15 += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz16a': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz16a += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz16b': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz16b += 1 if values[field_name] != solutions[field_name] and field_name == 'quiz16c': error_messages[field_name] = 'INCORRECT! Please try again.' player.incorrect_quiz16c += 1 return error_messages class CollectEffort(Page): form_model = 'player' form_fields = ['approach'] class ResultsWaitPage(WaitPage): body_text = "Please wait until the other participant makes decision." def after_all_players_arrive(group: Group): for p in group.get_players(): payoff(p) class Results(Page): @staticmethod def vars_for_template(player: Player): players = player.group.get_players() return_dict = {} for i in players: return_dict[f'player{i.id_in_group}'] = i.approach return_dict[f'player{i.id_in_group}_payment'] = i.payment return return_dict # # We need to collect their Lira amount across all rounds # @staticmethod # def payoff(player: Player): # player.payment = player.participant.compensation class FinalWaitPage(WaitPage): body_text = "Please wait for your group member!" wait_for_player_in_group = True class Transition2(Page): # Change to Round Number = 12 after testing @staticmethod def is_displayed(player: Player): return player.round_number == 12 @staticmethod def before_next_page(player, timeout_happened): player.sender_amount = player.participant.sender_amount print(player.sender_amount) print(player.participant.sender_amount ) class Process(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 form_model = 'player' def vars_for_template(player: Player): for x in player.get_others_in_group(): player.other_sent = x.sender_amount player.joint = (player.other_sent + player.sender_amount) * 3 player.joint_portion = round_half_up(player.joint / 2) player.stage1compensation = C.Fixed - player.sender_amount + player.joint_portion joint_portion = player.joint_portion stage1compensation = player.stage1compensation return_dict = { 'joint_portion': f"{joint_portion:,.0f}", 'stage1compensation': f"{stage1compensation:,.0f}" } return return_dict @staticmethod def get_form_fields(player: Player): if player.condition == "WS" and player.sub_condition == "Weak": return ["peq1", "peq3"] elif player.condition == "WN" and player.sub_condition == "Weak": return ["peq2", "peq3"] else: return ["peq3"] class Process2(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 form_model = 'player' @staticmethod def get_form_fields(player: Player): if player.condition == "WN" and player.sub_condition == "Weak": return ["peq4", "peq5", "peq6"] elif player.condition == "WW": return ["peq4b", "peq6"] else: return ["peq4", "peq6"] class Demo(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 form_model = 'player' form_fields = ["age", "gender"] class Demo2(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 and player.gender == "Other" form_model = 'player' form_fields = ["gender2"] class ResponderPage(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 form_model = 'player' def vars_for_template(player: Player): joint_portion = player.joint_portion stage1compensation = player.stage1compensation return_dict = { 'joint_portion': f"{joint_portion:,.0f}", 'stage1compensation': f"{stage1compensation:,.0f}" } return return_dict # # If Di wants to use her credit pool @staticmethod def before_next_page(player, timeout_happened): player.payoff = ((player.stage1compensation + player.compensation)/960) player.identifier = random.randint(1, 6000) # If Di wants to use her paid pool # @staticmethod # def before_next_page(player, timeout_happened): # player.payoff = ((player.stage1compensation + player.compensation)/720) + C.Show_Up # player.identifier = random.randint(1, 6000) class Final(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 12 def vars_for_template(player: Player): stage1compensation = player.stage1compensation stage2compensation = player.compensation return_dict = { 'stage1_lira': f"{stage1compensation:,.0f}", 'stage2_lira': f"{stage2compensation:,.0f}", 'identifier': f'player_{player.id_in_subsession}_{player.identifier}'} return return_dict # Full Instructions page_sequence = [Workstation, Policy, TaskO, Quiz1, Stage1, Quiz2, Stage1Task, Quiz3, SenderPage, Transition, Quiz4, Stage2Task, Quiz5, Stage2Contract, Quiz6, Stage2Bonus, Quiz7, Stage2Role, Quiz8, CollectEffort, ResultsWaitPage, Results, Transition2, FinalWaitPage, Process, Process2, Demo, Demo2, ResponderPage, Final] # # Partial Instructions # page_sequence = [Policy, SenderPage, Transition, CollectEffort, ResultsWaitPage, Results, Transition2, FinalWaitPage, ResponderPage, Demo, Demo2, Final]