from otree.api import * import random import itertools import time from random import choice doc = """ """ class C(BaseConstants): NAME_IN_URL = 'whistle_imperfect' PLAYERS_PER_GROUP = 6 NUM_ROUNDS = 20 multiplier = 3 fixed = 2.5 pounds = 1/60 class Subsession(BaseSubsession): pass def creating_session(subsession): if subsession.round_number == 1: subsession.group_randomly(fixed_id_in_group=True) else: subsession.group_like_round(1) for p in subsession.get_players(): if p.id_in_group in [1, 2, 3, 4]: p.type = "cont" elif p.id_in_group == 5: p.type = "admin" elif p.id_in_group == 6: p.type = "coll" for p in subsession.get_players(): if p.id_in_group == 1: p.type2 = "A1" elif p.id_in_group == 2: p.type2 = "A2" elif p.id_in_group == 3: p.type2 = "A3" elif p.id_in_group == 4: p.type2 = "A4" elif p.id_in_group == 5: p.type2 = "B" elif p.id_in_group == 6: p.type2 = "C" class Group(BaseGroup): pass class Player(BasePlayer): type = models.StringField() type2 = models.StringField() contribution = models.IntegerField( label = 'Please, write below the amount of ECU you would like to contribute to the project. (note that the amount you enter should be in between 0 and 10 ECU).' ) release = models.IntegerField( ) pool = models.IntegerField() multiplied_pool = models.IntegerField() estimated_multiplied_pool = models.IntegerField() estimate_a = models.IntegerField( label= 'How many ECU do you estimate that the other three A-participants have contributed on average? (note that the amount you enter should be in between 0 and 10 ECU).' ) estimate_b = models.IntegerField( label= 'How many ECU do you estimate that A-participants have contributed on average? (note that the amount you enter should be in between 0 and 10 ECU).' ) estimate_c = models.IntegerField( label = 'How many ECU do you estimate that A-participants have contributed on average? (note that the amount you enter should be in between 0 and 10 ECU).' ) estimate_a2 = models.IntegerField( ) estimate_c2 = models.IntegerField( ) not_pay = models.IntegerField() release_a = models.FloatField() unrelease = models.IntegerField() unrelease_b = models.FloatField() unrelease_c = models.FloatField() period_payoff = models.FloatField() all_period_payoff = models.FloatField() final_pound = models.FloatField() question1 = models.IntegerField( label="", min=0 ) question2 = models.IntegerField( label="", min=0, ) question3 = models.IntegerField( label="", min=0, ) question4 = models.IntegerField( label="", min=0, ) question5 = models.IntegerField( label="", min=0, ) question6 = models.IntegerField( label="", min=0, ) question7 = models.IntegerField( label="", min=0, ) question8 = models.IntegerField( label="", min=0, ) question9 = models.IntegerField( label="", min=0, ) question10 = models.IntegerField( label="", min=0, ) gender = models.StringField( choices=[ ['1', 'Male'], ['2', 'Female'], ['3', 'Other'], ], label="1. What is your gender?", widget=widgets.RadioSelect ) age = models.IntegerField( label="2. What is your age?", min=0, max=120 ) language = models.StringField( choices=[ ['1', 'Yes'], ['2', 'No'], ], label="3. Is English your first language?", widget=widgets.RadioSelect ) max_income = models.StringField( choices=[ ['1', 'Very important'], ['2', 'Important'], ['3', 'Indifferent'], ['4', 'Not important'], ['5', 'Not important at all'], ], label="4. How important was it for you to maximise your own income during the experiment?", widget=widgets.RadioSelect ) trust = models.StringField( choices=[ ['1', 'Most people can be trusted'], ['2', 'You need to be very careful in dealing with people'], ], label="5. Generally speaking, would you say that most people can be trusted or that you need to be very " "careful in dealing with people?", widget=widgets.RadioSelect ) risk = models.StringField( choices=[ ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) instructions = models.StringField( choices=[ ['1', 'Very difficult'], ['2', 'Difficult'], ['3', 'Neutral'], ['4', 'Easy'], ['5', 'Very easy'], ], label="7. How did you find the instructions?", widget=widgets.RadioSelect ) econ_exp = models.IntegerField( label="8. How many economics experiments have you participated in before this one? ", ) feedback = models.StringField( blank=True, label="9. Do you have any other comments or feedback regarding this experiment?", ) def question1_error_message(player, value): correct_q1 = 10 if value != correct_q1: error_q1 = "Answer: (10 - 0) + (4 x 0 x 3 – 0)/4 = 10 ECU" return error_q1 def question2_error_message(player, value): correct_q2 = 30 if value != correct_q2: error_q2 = "Answer: 30 ECU" return error_q2 def question3_error_message(player, value): correct_q3 = 30 if value != correct_q3: error_q3 = "Answer: 30 ECU" return error_q3 def question4_error_message(player, value): correct_q4 = 30 if value != correct_q4: error_q4 = "Answer: (10 - 10) + (4 x 10 x 3)/4 = 30 ECU" return error_q4 def question5_error_message(player, value): correct_q5 = 30 if value != correct_q5: error_q5 = "Answer: 30 ECU" return error_q5 def question6_error_message(player, value): correct_q6 = 30 if value != correct_q6: error_q6 = "Answer: 30 ECU" return error_q6 def question7_error_message(player, value): correct_q7 = 20 if value != correct_q7: error_q7 = "Answer: (10 - 0) + 40/4 = 20 ECU" return error_q7 def question8_error_message(player, value): correct_q8 = 10 if value != correct_q8: error_q8 = "Answer: (10 - 10) + 40/4 = 10 ECU" return error_q8 def question9_error_message(player, value): correct_q9 = 40 if value != correct_q9: error_q9 = "Answer: 30+((0+0+10+10) x 3 - 40)/2 = 40 ECU" return error_q9 def question10_error_message(player, value): correct_q10 = 40 if value != correct_q10: error_q10 = "Answer: 30+((0+0+10+10) x 3 - 40)/2 = 40 ECU" return error_q10 def contribution_error_message(player, value): min = 0 max = 10 if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def release_error_message(player, value): min = 0 max = player.multiplied_pool if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def estimate_a_error_message(player, value): min = 0 max = 10 if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def estimate_b_error_message(player, value): min = 0 max = 10 if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def estimate_c_error_message(player, value): min = 0 max = 10 if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def estimate_a2_error_message(player, value): min = 0 max = player.estimated_multiplied_pool if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' def estimate_c2_error_message(player, value): min = 0 max = player.multiplied_pool if value < min: return 'The amount of ECU you entered is invalid. Please try again.' elif value > max: return 'The amount of ECU you entered is invalid. Please try again.' class Welcome(Page): def is_displayed(player: Player): return player.round_number == 1 class General(Page): def is_displayed(player: Player): return player.round_number == 1 class Instructions(Page): def is_displayed(player: Player): return player.round_number == 1 class Instructions2(Page): def is_displayed(player: Player): return player.round_number == 1 class Questions(Page): form_model = 'player' form_fields = ['question1', 'question2', 'question3', 'question4', 'question5', 'question6', 'question7', 'question8', 'question9', 'question10', ] def is_displayed(player: Player): return player.round_number == 1 class Contribution(Page): form_model = 'player' form_fields = ['contribution' ] def is_displayed(player: Player): return player.type == "cont" class Estimate1(Page): form_model = 'player' def get_form_fields(player: Player): if player.type == "admin": return ['estimate_b'] elif player.type == "coll": return ['estimate_c'] def is_displayed(player: Player): return player.type != "cont" class ResultsWaitPage(WaitPage): title_text = "Please wait" body_text = "Please wait for the other participants to make their decisions" def after_all_players_arrive(group: Group): players = group.get_players() for p in players: player1 = group.get_player_by_id(1) player2 = group.get_player_by_id(2) player3 = group.get_player_by_id(3) player4 = group.get_player_by_id(4) contributors = [player1, player2, player3, player4] contributions = [p.contribution for p in contributors] p.pool = sum(contributions) p.multiplied_pool = p.pool*C.multiplier class Release(Page): form_model = 'player' form_fields = ['release' ] def is_displayed(player: Player): return player.type == "admin" def vars_for_template(player: Player): return dict( release_label='Please, write below the amount of ECU in the pool you would like to release to A-participants. (note that the amount you enter should be in between 0 and {} ECU).'.format(player.multiplied_pool) ) class Estimate2(Page): form_model = 'player' def get_form_fields(player: Player): if player.type == "cont": return ['estimate_a'] elif player.type == "coll": return ['estimate_c2'] def is_displayed(player: Player): return player.type != "admin" def vars_for_template(player: Player): return dict( estimatec2_label='How many ECU do you estimate that the B-participant has released to all A-participants? (note that the amount you enter should be in between 0 and {} ECU).'.format(player.multiplied_pool) ) def before_next_page(player: Player, timeout_happened): if player.type == "cont": player.estimated_multiplied_pool = C.multiplier * (player.contribution + 3 * player.estimate_a) class Estimate3(Page): form_model = 'player' form_fields = ['estimate_a2'] def is_displayed(player: Player): return player.type == "cont" def vars_for_template(player: Player): return dict( estimatea2_label='How many ECU do you estimate that the B-participant has released to all A-participants? (note that the amount you enter should be in between 0 and {} ECU).'.format(player.estimated_multiplied_pool) ) class ResultsWaitPage2(WaitPage): title_text = "Please wait" body_text = "Please wait for the other participants to make their decisions" def after_all_players_arrive(group: Group): players = group.get_players() for p in players: player1 = group.get_player_by_id(1) player2 = group.get_player_by_id(2) player3 = group.get_player_by_id(3) player4 = group.get_player_by_id(4) player5 = group.get_player_by_id(5) player6 = group.get_player_by_id(6) p.release = player5.release player1.not_pay = 10 - player1.contribution player2.not_pay = 10 - player2.contribution player3.not_pay = 10 - player3.contribution player4.not_pay = 10 - player4.contribution p.release_a = p.release/4 p.unrelease = p.multiplied_pool-p.release p.unrelease_b = p.unrelease/2 p.unrelease_c = p.unrelease/2 player1.period_payoff = round(player1.not_pay + p.release_a, 2) player2.period_payoff = round(player2.not_pay + p.release_a, 2) player3.period_payoff = round(player3.not_pay + p.release_a, 2) player4.period_payoff = round(player4.not_pay + p.release_a, 2) player5.period_payoff = 30+p.unrelease / 2 player6.period_payoff = 30+p.unrelease / 2 class Feedback(Page): form_model = 'player' def vars_for_template(player: Player): if player.round_number > 1: past_rounds = [ {'round_number': i, 'period_payoff': player.in_round(i).period_payoff} for i in range(1, player.round_number) ] elif player.round_number == 1: past_rounds = [] return { 'past_rounds': past_rounds } class ResultsWaitPage3(WaitPage): title_text = "Please wait" body_text = "Please wait for the other participants to make their decisions" def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS class Final_results(Page): form_model = 'player' def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS def vars_for_template(player: Player): player.all_period_payoff = sum([p.period_payoff for p in player.in_all_rounds()]) player.final_pound = round(player.all_period_payoff*C.pounds,2) player.payoff = round(player.final_pound+C.fixed,2) class Questionnaire(Page): form_model = 'player' form_fields = ['gender', 'age', 'language', 'max_income', 'trust', 'risk', 'instructions', 'econ_exp', 'feedback'] def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS class Thanks(Page): def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS page_sequence = [Welcome,General,Instructions, Instructions2,Questions,Contribution,Estimate1,ResultsWaitPage,Release, Estimate2, Estimate3,ResultsWaitPage2, Feedback, ResultsWaitPage3, Final_results,Questionnaire,Thanks]