from otree.api import * import random import itertools import time from random import choice doc = """ """ class C(BaseConstants): NAME_IN_URL = 'whistle_imperfect_old' PLAYERS_PER_GROUP = 6 NUM_ROUNDS = 3 multiplier = 3 fixed = 2.5 pounds = 0.0125 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" class Group(BaseGroup): pass class Player(BasePlayer): type = 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 increments of 5).' ) release = models.IntegerField( 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 increments of 5).' ) pool = models.IntegerField() multiplied_pool = models.IntegerField() estimate_a = models.IntegerField( label= 'How many ECU do you estimate that the other three A-participants have contributed in total? (note that the amount you enter should be in increments of 5).' ) estimate_c = models.IntegerField( label= 'How many ECU do you estimate that A-participants have contributed in total? (note that the amount you enter should be in increments of 5).' ) estimated_pool = models.IntegerField() estimate_a2 = models.IntegerField( 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 increments of 5).' ) estimate_c2 = models.IntegerField( 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 increments of 5).' ) release_show = models.IntegerField() not_pay = models.IntegerField() release_a = models.FloatField() release_a_show = models.FloatField() unrelease = models.IntegerField() unrelease_show = models.IntegerField() unrelease_b = models.FloatField() unrelease_b_show = models.FloatField() unrelease_c = models.FloatField() unrelease_c_show = models.FloatField() period_payoff = models.FloatField() period_payoff_show = models.FloatField() all_period_payoff = models.FloatField() final_pound = models.FloatField() question1 = models.FloatField( label="", min=0 ) question2 = models.FloatField( label="", min=0, ) question3 = models.FloatField( label="", min=0, ) question4 = models.FloatField( label="", min=0, ) question5 = models.FloatField( label="", min=0, ) question6 = models.FloatField( label="", min=0, ) question7 = models.FloatField( label="", min=0, ) question8 = models.FloatField( label="", min=0, ) question9 = models.FloatField( label="", min=0, ) question10 = models.FloatField( 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 = 20 if value != correct_q1: error_q1 = "Answer: (20 - 0) + (3 x 4 x 0 – 0)/4 = 20 ECU" return error_q1 def question2_error_message(player, value): correct_q2 = 0 if value != correct_q2: error_q2 = "Answer: 0 ECU" return error_q2 def question3_error_message(player, value): correct_q3 = 0 if value != correct_q3: error_q3 = "Answer: 0 ECU" return error_q3 def question4_error_message(player, value): correct_q4 = 60 if value != correct_q4: error_q4 = "Answer: (20 - 20) + (3 x 4 x 20)/4 = 60 ECU" return error_q4 def question5_error_message(player, value): correct_q5 = 0 if value != correct_q5: error_q5 = "Answer: 0 ECU" return error_q5 def question6_error_message(player, value): correct_q6 = 0 if value != correct_q6: error_q6 = "Answer: 0 ECU" return error_q6 def question7_error_message(player, value): correct_q7 = 30 if value != correct_q7: error_q7 = "Answer: (20 - 5) + (3 x (5+5+15+15) – 60)/4 = 30 ECU" return error_q7 def question8_error_message(player, value): correct_q8 = 20 if value != correct_q8: error_q8 = "Answer: (20 - 15) + (3 x (5+5+15+15) – 60)/4 = 20 ECU" return error_q8 def question9_error_message(player, value): correct_q9 = 30 if value != correct_q9: error_q9 = "Answer: 60/2 = 30 ECU" return error_q9 def question10_error_message(player, value): correct_q10 = 30 if value != correct_q10: error_q10 = "Answer: 60/2 = 30 ECU" return error_q10 def contribution_error_message(player, value): min = 0 max = 20 if value % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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 % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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 = 60 if value % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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 = 80 if value % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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_pool if value % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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.estimated_pool if value % 5 != 0: return 'The amount of ECU you entered is invalid. Please try again.' elif 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 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 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" class Estimate1(Page): form_model = 'player' def get_form_fields(player: Player): if player.type == "cont": return ['estimate_a'] elif player.type == "coll": return ['estimate_c'] def is_displayed(player: Player): return player.type != "admin" class Estimate2(Page): form_model = 'player' def get_form_fields(player: Player): if player.type == "cont": return ['estimate_a2'] elif player.type == "coll": return ['estimate_c2'] def is_displayed(player: Player): return player.type != "admin" def vars_for_template(player: Player): if player.id_in_group in [1, 2, 3, 4]: player.estimated_pool = (player.contribution + player.estimate_a) * C.multiplier elif player.id_in_group == 6: player.estimated_pool = (player.estimate_c) * C.multiplier 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) player1.release = player5.release player2.release = player5.release player3.release = player5.release player4.release = player5.release player6.release = player5.release pls = [player1, player2, player3, player4] for p in pls: if p.release <= 5: possible_values = [0, 5, 10, 15, 20] elif p.release >= p.multiplied_pool - 5: possible_values = [p.multiplied_pool - 20, p.multiplied_pool - 15, p.multiplied_pool - 10, p.multiplied_pool - 5, p.multiplied_pool] else: possible_values = [p.release - 10, p.release - 5, p.release, p.release + 5, p.release + 10] player1.release_show = random.choice(possible_values) player2.release_show = random.choice(possible_values) player3.release_show = random.choice(possible_values) player4.release_show = random.choice(possible_values) player1.release_a_show = player1.release_show / 4 player2.release_a_show = player2.release_show / 4 player3.release_a_show = player3.release_show / 4 player4.release_a_show = player4.release_show / 4 player1.unrelease_show = p.multiplied_pool - player1.release_show player2.unrelease_show = p.multiplied_pool - player2.release_show player3.unrelease_show = p.multiplied_pool - player3.release_show player4.unrelease_show = p.multiplied_pool - player4.release_show player1.unrelease_b_show = player1.unrelease_show / 2 player2.unrelease_b_show = player2.unrelease_show / 2 player3.unrelease_b_show = player3.unrelease_show / 2 player4.unrelease_b_show = player4.unrelease_show / 2 player1.unrelease_c_show = player1.unrelease_show / 2 player2.unrelease_c_show = player2.unrelease_show / 2 player3.unrelease_c_show = player3.unrelease_show / 2 player4.unrelease_c_show = player4.unrelease_show / 2 player1.not_pay = 20 - player1.contribution player2.not_pay = 20 - player2.contribution player3.not_pay = 20 - player3.contribution player4.not_pay = 20 - player4.contribution player1.period_payoff_show = round(player1.not_pay + player1.release_a_show, 2) player2.period_payoff_show = round(player2.not_pay + player2.release_a_show, 2) player3.period_payoff_show = round(player3.not_pay + player3.release_a_show, 2) player4.period_payoff_show = round(player4.not_pay + player4.release_a_show, 2) all = [player1, player2, player3, player4, player5, player6] for p in all: 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 = p.unrelease / 2 player6.period_payoff = p.unrelease / 2 class Feedback(Page): form_model = 'player' 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,Questions, Contribution,ResultsWaitPage,Release, Estimate1,Estimate2, ResultsWaitPage2, Feedback, ResultsWaitPage3, Final_results,Questionnaire,Thanks]