from otree.api import * NUMBER_OF_ROUNDS_DRAWN = 3 START_OF_DRAW_WINDOW = 0 END_OF_DRAW_WINDOW = 30 def make_field_1_7(label): return models.StringField( choices=[1, 2, 3, 4, 5, 6, 7], label=label, widget=widgets.RadioSelectHorizontal, ) def make_field_0_10(label): return models.StringField( choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], label=label, widget=widgets.RadioSelectHorizontal, ) class C(BaseConstants): NAME_IN_URL = 'questions' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 1 MIN = 18 MAX = 150 class Subsession(BaseSubsession): BPMin = models.IntegerField() BPMax = models.IntegerField() ExchangeRate = models.FloatField() pass class Group(BaseGroup): pass class Player(BasePlayer): # PEQ1 ManipulationCheckAnonymity = make_field_1_7('It felt very costly to me to point out potential misreporting of others.') ManipulationCheckIncentives = make_field_1_7('Pointing out others for potential' ' misreporting could bring direct benefits for me.') Sure = make_field_1_7('I pointed others out only when I was very sure about their misreporting.') Sufficient = make_field_1_7('I feel that the number of investigations per round was sufficient.') Future = make_field_1_7('When I pointed out others, I hoped that they would be more honest in the future.') InvestigationThreat = make_field_1_7('I reported more honestly than I would have ' 'done otherwise, because of the threat of an investigation.') PerceivedCost = make_field_1_7('Raising the flag reduced my chances of winning the competition within my group significantly.') # PEQ2 LL1 = models.StringField(label='', ) LL2 = models.StringField(label='', ) LL3 = models.StringField(label='', ) LL4 = models.StringField(label='', ) LL5 = models.StringField(label='', ) LL6 = models.StringField(label='', ) LL7 = models.StringField(label='', ) LL8 = models.StringField(label='', ) LL9 = models.StringField(label='', ) LL10 = models.StringField(label='', ) UL1 = models.StringField(label='', ) UL2 = models.StringField(label='', ) UL3 = models.StringField(label='', ) UL4 = models.StringField(label='', ) UL5 = models.StringField(label='', ) UL6 = models.StringField(label='', ) UL7 = models.StringField(label='', ) UL8 = models.StringField(label='', ) UL9 = models.StringField(label='', ) UL10 = models.StringField(label='', ) Risk = make_field_0_10('') Altruism1 = PEQ3_Age = models.IntegerField( label='', min=0, max=1000 ) Altruism2 = make_field_0_10('') ReciprocityPos1 = make_field_0_10('') ReciprocityNeg1 = make_field_0_10('') ReciprocityNeg2 = make_field_0_10('') ReciprocityNeg3 = make_field_0_10('') #PEQ2 part2 HonorFamily1 = make_field_1_7('') MoralIntegrity1 = make_field_1_7('') MoralIntegrity2 = make_field_1_7('') HonorFamily2 = make_field_1_7('') MoralIntegrity3 = make_field_1_7('') MoralIntegrity4 = make_field_1_7('') HonorFamily3 = make_field_1_7('') HonorFamily4 = make_field_1_7('') MoralIntegrity5 = make_field_1_7('') MoralIntegrity6 = make_field_1_7('') MoralIntegrity7 = make_field_1_7('') SocialImage1 = make_field_1_7('') SocialImage2 = make_field_1_7('') SocialImage3 = make_field_1_7('') SocialImage4 = make_field_1_7('') SocialImage5 = make_field_1_7('') SocialImage6 = make_field_1_7('') # PEQ3 PEQ3_Gender = models.StringField( label='1. What is your gender?', choices=[[1, 'Male'], [2, 'Female'], [3, 'Other'], [4, 'Do not prefer to answer'], [5, 'Non-binary'], [6, 'Self-identification'] ], widget=widgets.RadioSelect ) PEQ3_Gender_Text = models.StringField(label='') PEQ3_Age = models.IntegerField( label='2. What is your age? (Please enter a number)', min=C.MIN, max=C.MAX ) PEQ3_Degree = models.StringField( label='3. What is your highest degree?', choices=[[1, 'High School '], [2, 'Undergraduate Degree'], [3, 'Graduate Degree'], [4, 'Professional Degree'], [5, 'Ph.D.'], [6, 'Post Doctoral Degree'], [7, 'Other']], widget=widgets.RadioSelect, ) BonusPayout = models.IntegerField() ChosenRound_1 = models.IntegerField() ChosenRound_2 = models.IntegerField() ChosenRound_3 = models.IntegerField() pass # FUNCTIONS def calculate_bonus_payout(player: Player, chosen_rounds): return sum(list(map(lambda x: player.participant.bonus_totals[x], chosen_rounds))) def calculate_payoffs(subsession: Subsession): import random import math players = list(subsession.get_players()) for player in players: chosen_rounds = random.sample(range(START_OF_DRAW_WINDOW, END_OF_DRAW_WINDOW), NUMBER_OF_ROUNDS_DRAWN) player.BonusPayout = calculate_bonus_payout(player, chosen_rounds) player.ChosenRound_1 = chosen_rounds[0]+1 player.ChosenRound_2 = chosen_rounds[1]+1 player.ChosenRound_3 = chosen_rounds[2]+1 player.participant.BonusPayout = player.BonusPayout player.participant.ChosenRound_1 = player.ChosenRound_1 player.participant.ChosenRound_2 = player.ChosenRound_2 player.participant.ChosenRound_3 = player.ChosenRound_3 bonus_payouts = list(map(lambda p: p.BonusPayout, players)) subsession.BPMin = min(bonus_payouts) subsession.BPMax = max(bonus_payouts) subsession.ExchangeRate = 20 / ((1 + subsession.BPMax) - subsession.BPMin) for player in players: if player.BonusPayout == subsession.BPMax: player.payoff = 40 elif player.BonusPayout == subsession.BPMin: player.payoff = 20 else: player.payoff = math.floor(20 + (player.BonusPayout - subsession.BPMin)*subsession.ExchangeRate) player.participant.calulated_final_payoff = player.payoff pass # PAGES class PEQ1(Page): form_model = 'player' form_fields = ['ManipulationCheckAnonymity', 'ManipulationCheckIncentives', 'Sure', 'Sufficient', 'Future', 'InvestigationThreat', 'PerceivedCost'] pass class PEQ2(Page): form_model = 'player' form_fields = ['LL1', 'LL2', 'LL3', 'LL4', 'LL5', 'LL6', 'LL7', 'LL8', 'LL9', 'LL10', 'UL1', 'UL2', 'UL3', 'UL4', 'UL5', 'UL6', 'UL7', 'UL8', 'UL9', 'UL10', 'Risk', 'Altruism1', 'Altruism2', 'ReciprocityPos1', 'ReciprocityNeg1', 'ReciprocityNeg2', 'ReciprocityNeg3'] pass class PEQ2_PART2(Page): form_model = 'player' form_fields = ['HonorFamily1','HonorFamily2','HonorFamily3','HonorFamily4', 'MoralIntegrity1','MoralIntegrity2','MoralIntegrity3', 'MoralIntegrity4','MoralIntegrity5','MoralIntegrity6','MoralIntegrity7', 'SocialImage1','SocialImage2','SocialImage3','SocialImage4','SocialImage5','SocialImage6'] pass class PEQ3(Page): form_model = 'player' form_fields = ['PEQ3_Gender', 'PEQ3_Age', 'PEQ3_Degree', 'PEQ3_Gender_Text'] pass class PrePostQuestionsWaitPage(WaitPage): wait_for_all_groups = True after_all_players_arrive = calculate_payoffs pass page_sequence = [PrePostQuestionsWaitPage, PEQ1, PEQ2, PEQ2_PART2, PEQ3]