from otree.api import * import random doc = """ All-pay contest without IDE, using the bid cap k=450 """ class Constants(BaseConstants): name_in_url = 'No_Externality_all_pay_k450' players_per_group = 3 num_rounds = 61 # change to 61 in the real game table_template = __name__ + '/table.html' class Subsession(BaseSubsession): endowment = models.FloatField( initial=450.0 ) # the value of bid cap class Group(BaseGroup): position_list = models.StringField( initial="" ) # shown in result page of different positions bid# bid_list = models.StringField( initial="" ) winner_id = models.IntegerField(initial=0) winner_position_id = models.StringField(initial='') participants = models.IntegerField(initial=3) highest_bid = models.FloatField(initial=0.0) class Player(BasePlayer): bid = models.FloatField( min=0.0, max=450.0, label="Please enter how much you want to bid this period:", ) is_winner = models.BooleanField( initial=False, doc="""Indicates whether the player is the winner""" ) round_payoff = models.FloatField(initial=0.0) value_11 = models.FloatField(initial=0) value_12 = models.FloatField(initial=0) value_13 = models.FloatField(initial=0) value_22 = models.FloatField(initial=0) value_21 = models.FloatField(initial=0) value_23 = models.FloatField(initial=0) value_33 = models.FloatField(initial=0) value_31 = models.FloatField(initial=0) value_32 = models.FloatField(initial=0) position = models.StringField(initial='') raw_responses = models.LongStringField() chose_lottery = models.BooleanField() won_lottery = models.BooleanField(initial=False) part2_payoff = models.CurrencyField() age = models.IntegerField( label='What is your age?', min=18, max=100) gender = models.StringField( choices=['Male', 'Female', 'Other'], label='What is your gender?', widget=widgets.RadioSelect) citizenship = models.StringField( label='What is your country(s) of citizenship?') major = models.StringField( label='What is your major?') year = models.StringField( choices=['Freshman', 'Sophomore', 'Junior', 'Senior', 'Graduate', 'Other'], label='Which year are you in?', widget=widgets.RadioSelect) risk = models.StringField( choices=['Strongly Disagree', 'Disagree', 'Slightly Disagree', 'Slightly Agree', 'Agree', 'Strongly Agree'], label='You are a person who is fully prepared to take risks.', widget=widgets.RadioSelect) decisionA = models.LongStringField(initial=None, label="How did you make your decisions in Part 1, when you were at position A (when you win, you receive 400 points; when you lose, you receive 0 points)?") decisionB = models.LongStringField(initial=None, label="How did you make your decisions in Part 1, when you were at position B (when you win, you receive 400 points; when you lose, you receive 220 points)?" ) decisionC = models.LongStringField(initial=None, label="How did you make your decisions in Part 1, when you were at position C (when you win, you receive 400 points; when you lose, you receive 0 points)?" ) comments = models.LongStringField(blank=True, initial=None, label="Do you have any comments, questions, or complaints about today's experiment?") quiz1 = models.StringField( choices=['The same participants', 'Two randomly determined participants'], label='1. In each period, you are matched with:', widget=widgets.RadioSelect) quiz2 = models.StringField( choices=['True', 'False'], label='2. Your position will change every 20 periods.', widget=widgets.RadioSelect) quiz3 = models.StringField( choices=['True', 'False'], label='3. In each period, the participant who places the highest bid in a group will win (suppose there is no tie).', widget=widgets.RadioSelect) quiz4 = models.StringField( choices=['True', 'False'], label='4. You can bid up to 450 points.', widget=widgets.RadioSelect) quiz5 = models.StringField( choices=['True', 'False'], label='5. If you are the winner, your payoff in the period is = 400 – your bid.', widget=widgets.RadioSelect) quiz6 = models.StringField( choices=['True', 'False'], label='6. If you are not the winner in a period, you receive 0 points.', widget=widgets.RadioSelect) quiz7 = models.StringField( choices=['True', 'False'], label='7. If you are not the winner in a period, you do not need to pay your bid.', widget=widgets.RadioSelect) class Trial(ExtraModel): player = models.Link(Player) sure_payoff = models.CurrencyField() lottery_high = models.CurrencyField() lottery_low = models.CurrencyField() probability = models.FloatField() chose_lottery = models.BooleanField() randomly_chosen = models.BooleanField(initial=False) #Functions def read_csv(): import csv f = open(__name__ + '/stimuli.csv', encoding='utf-8-sig') rows = list(csv.DictReader(f)) return rows def creating_session(subsession: Subsession): # print('in creating_session') session = subsession.session subsession.group_randomly(fixed_id_in_group=True) #same ID in same positions every 20 rounds if subsession.round_number == 1: paying_round1 = random.randint(2, 11) # change those values to (2,11) later paying_round2 = random.randint(12, 21) # change those values to (12,21) later paying_round3 = random.randint(22, 31) # change those values to (22,31) later paying_round4 = random.randint(32, 41) # change to (32,41) later paying_round5 = random.randint(42, 51) # change to (42,51) later paying_round6 = random.randint(52, 61) # change to (52,61) later session.vars['paying_round1'] = paying_round1 session.vars['paying_round2'] = paying_round2 session.vars['paying_round3'] = paying_round3 session.vars['paying_round4'] = paying_round4 session.vars['paying_round5'] = paying_round5 session.vars['paying_round6'] = paying_round6 session.vars['endowment'] = subsession.endowment for p in subsession.get_players(): p.round_chosen1 = session.vars['paying_round1'] p.round_chosen2 = session.vars['paying_round2'] p.round_chosen3 = session.vars['paying_round3'] p.round_chosen4 = session.vars['paying_round4'] p.round_chosen5 = session.vars['paying_round5'] p.round_chosen6 = session.vars['paying_round6'] stimuli = read_csv() for stim in stimuli: Trial.create(player=p, **stim) # Decide who is the winner and gather all the required data def set_winner(group: Group): import random #set the positions for players p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) for p in [p1, p2, p3]: if p.round_number <= 21: #change 3 to 21 in real-game p1.position = 'A' p2.position = 'B' p3.position = 'C' elif p.round_number <= 41: # change 5 to 41 in real-game, p1.position = 'B' p2.position = 'C' p3.position = 'A' else: p1.position = 'C' p2.position = 'A' p3.position = 'B' players = group.get_players() group.highest_bid = max([p.bid for p in players]) players_with_highest_bid = [p for p in players if p.bid == group.highest_bid] winner = random.choice( players_with_highest_bid ) # if tie, winner is chosen at random winner.is_winner = True group.winner_id = winner.id_in_group group.winner_position_id=winner.position # Collect the list of positions and bids to display at the feedback screen for p in [p1, p2, p3]: # Collect the list of values and bids to display at the feedback screen group.position_list = group.position_list + str(p.position) + " " group.bid_list = group.bid_list + str(p.bid) + " " def set_payoff(group: Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) for p in [p1, p2, p3]: if p.round_number <= 21: # change 3 to 21 in real-game, 1 and 3 are extremist, 2 is centrist p1.position = 'A' p2.position = 'B' p3.position = 'C' p1.value_11 = 400 p1.value_12 = 0 # no ide, value_ij=0 p1.value_13 = 0 p2.value_23 = 220 p2.value_22 = 400 p2.value_21 = 220 p3.value_31 = 0 p3.value_32 = 0 p3.value_33 = 400 elif p.round_number <= 41: # change 5 to 41 in real-game, 2 and 3 are extremist, 1 is centrist p1.position = 'B' p2.position = 'C' p3.position = 'A' p1.value_11 = 400 p1.value_12 = 220 p1.value_13 = 220 p2.value_23 = 0 p2.value_22 = 400 p2.value_21 = 0 p3.value_31 = 0 p3.value_32 = 0 p3.value_33 = 400 else: #1 and 2 are extremist, 3 is centrist p1.position = 'C' p2.position = 'A' p3.position = 'B' p1.value_11 = 400 p1.value_12 = 0 p1.value_13 = 0 p2.value_23 = 0 p2.value_22 = 400 p2.value_21 = 0 p3.value_31 = 220 p3.value_32 = 220 p3.value_33 = 400 if p1.is_winner: p1.round_payoff = p1.value_11 - p1.bid p2.round_payoff = p2.value_21 - p2.bid p3.round_payoff = p3.value_31 - p3.bid elif p2.is_winner: p1.round_payoff = p1.value_12 - p1.bid p2.round_payoff = p2.value_22 - p2.bid p3.round_payoff = p3.value_32 - p3.bid elif p3.is_winner: p1.round_payoff = p1.value_13 - p1.bid p2.round_payoff = p2.value_23 - p2.bid p3.round_payoff = p3.value_33 - p3.bid def close_round(group: Group): set_winner(group) set_payoff(group) def set_position(group:Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) for p in [p1, p2, p3]: if p.round_number <= 21: # change 3 to 21 in real-game p1.position = 'A' p2.position = 'B' p3.position = 'C' elif p.round_number <= 41: # change 5 to 41 in real-game, p1.position = 'B' p2.position = 'C' p3.position = 'A' else: p1.position = 'C' p2.position = 'A' p3.position = 'B' #PAGES class P1_Welcome(Page): def is_displayed(self): return self.round_number == 1 after_all_players_arrive = creating_session class P2_Quiz(Page): def is_displayed(self): return self.round_number == 1 form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4', 'quiz5', 'quiz6', 'quiz7'] @staticmethod def error_message(player, values): solutions = dict( quiz1='Two randomly determined participants', quiz2='True', quiz3='True', quiz4='True', quiz5='True', quiz6='False', quiz7='False' ) error_messages = dict() for field_name in solutions: if values[field_name] != solutions[field_name]: error_messages[field_name] = 'Wrong answer' return error_messages class P3_Group(Page): @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group set_position(group) def vars_for_template(player: Player): endowment = player.subsession.endowment return dict( endowment=endowment, round_shown=player.round_number - 1, total_shown=Constants.num_rounds - 1 ) class P4_Practice_round_instruction(Page): def is_displayed(self): return self.round_number == 1 class P5_Notice (Page): def is_displayed(self): return self.round_number in (22, 42) #in real game change to (22,42) class P6_Contest_A (Page): def is_displayed(player): return player.position == 'A' form_model = 'player' form_fields = ['bid'] @staticmethod def vars_for_template(player: Player): endowment = player.subsession.endowment return dict( endowment=endowment, round_shown=player.round_number - 1, total_shown=Constants.num_rounds - 1 ) class P6_Contest_B(Page): def is_displayed(player): return player.position == 'B' form_model = 'player' form_fields = ['bid'] @staticmethod def vars_for_template(player: Player): endowment = player.subsession.endowment return dict( endowment=endowment, round_shown=player.round_number - 1, total_shown=Constants.num_rounds - 1 ) class P6_Contest_C (Page): def is_displayed(player): return player.position == 'C' form_model = 'player' form_fields = ['bid'] @staticmethod def vars_for_template(player: Player): endowment = player.subsession.endowment return dict( endowment=endowment, round_shown=player.round_number - 1, total_shown=Constants.num_rounds - 1 ) class P7_Round_result(Page): def vars_for_template(player: Player): winner_position_id = player.group.winner_position_id endowment = player.subsession.endowment position_list = player.group.position_list.split(" ") bid_list = player.group.bid_list.split(" ") position_list.pop() bid_list.pop() #participants = ["Participant " + str(i + 1) for i in range(Constants.players_per_group) bid1 = player.group.get_player_by_id(1).bid bid2 = player.group.get_player_by_id(2).bid bid3 = player.group.get_player_by_id(3).bid return dict( winner_position_id=winner_position_id, endowment=endowment, position_list=position_list, bid_list=bid_list, bid1=bid1, bid2=bid2, bid3=bid3, round_shown=player.round_number - 1, total_shown=Constants.num_rounds - 1 ) class P8_Practice_round_summary (Page): def is_displayed(self): return self.round_number == 1 class P9_Part1_end(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds class P10_Stimuli(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds form_model = 'player' form_fields = ['raw_responses'] @staticmethod def vars_for_template(player: Player): return dict(trials=Trial.filter(player=player)) @staticmethod def before_next_page(player: Player, timeout_happened): import json import random trials = Trial.filter(player=player) # you could adjust this code to handle timeout_happened. responses = json.loads(player.raw_responses) for trial in trials: trial.chose_lottery = responses[str(trial.id)] trial = random.choice(trials) trial.randomly_chosen = True player.chose_lottery = trial.chose_lottery if player.chose_lottery: #player.won_lottery = trial.probability > random.random() if trial.probability > (random.random()): player.won_lottery = True else: player.won_lottery = False if player.won_lottery: risk_payoff = trial.lottery_high else: risk_payoff = trial.lottery_low else: risk_payoff = trial.sure_payoff player.part2_payoff = risk_payoff class P11_Stimuli_Results(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds @staticmethod def vars_for_template(player: Player): trials = Trial.filter(player=player, randomly_chosen=True) return dict(trials=trials) class P12_Demographic(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds form_model = 'player' form_fields = ['age', 'gender', 'citizenship', 'major', 'year', 'risk'] class P13_Comments(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds form_model = 'player' form_fields = ['decisionA', 'decisionB', 'decisionC', 'comments'] class End_game(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds @staticmethod def vars_for_template(player: Player): session = player.session player_in_round1 = player.in_round(session.vars['paying_round1']) player_in_round2 = player.in_round(session.vars['paying_round2']) player_in_round3 = player.in_round(session.vars['paying_round3']) player_in_round4 = player.in_round(session.vars['paying_round4']) player_in_round5 = player.in_round(session.vars['paying_round5']) player_in_round6 = player.in_round(session.vars['paying_round6']) return dict( round1_payoff=player_in_round1.round_payoff, round2_payoff=player_in_round2.round_payoff, round3_payoff=player_in_round3.round_payoff, round4_payoff=player_in_round4.round_payoff, round5_payoff=player_in_round5.round_payoff, round6_payoff=player_in_round6.round_payoff, part1_payoff= 1000 + player_in_round1.round_payoff + player_in_round2.round_payoff + player_in_round3.round_payoff + player_in_round4.round_payoff + player_in_round5.round_payoff + player_in_round6.round_payoff, part2_payoff=player.part2_payoff, part1_payoff_currency=((1000 + player_in_round1.round_payoff + player_in_round2.round_payoff + player_in_round3.round_payoff + player_in_round4.round_payoff + player_in_round5.round_payoff + player_in_round6.round_payoff) / 100), total_payoff_currency=7 + ((1000 + player_in_round1.round_payoff + player_in_round2.round_payoff + player_in_round3.round_payoff + player_in_round4.round_payoff + player_in_round5.round_payoff + player_in_round6.round_payoff) / 100) + player.part2_payoff, paying_round1=session.vars['paying_round1'] - 1, paying_round2=session.vars['paying_round2'] - 1, paying_round3=session.vars['paying_round3'] - 1, paying_round4=session.vars['paying_round4'] - 1, paying_round5=session.vars['paying_round5'] - 1, paying_round6=session.vars['paying_round6'] - 1, player_chose_lottery=player.chose_lottery, player_won_lottery=player.won_lottery ) #Waitpages class ResultsWaitPage(WaitPage): after_all_players_arrive = close_round page_sequence = [ P1_Welcome, P2_Quiz, P3_Group, P4_Practice_round_instruction, P5_Notice, P6_Contest_A, P6_Contest_B, P6_Contest_C, ResultsWaitPage, P7_Round_result, P8_Practice_round_summary, P9_Part1_end, P10_Stimuli, P11_Stimuli_Results, P12_Demographic, P13_Comments, End_game ]