from otree.api import * import random from random import randrange, uniform doc = """ alliance formation with q=90 and majoritarian voting rule """ class Constants(BaseConstants): name_in_url = 'alliance_q90_major' players_per_group = 3 num_rounds = 35 # change to 35 in the real game table_template = __name__ + '/table.html' a = 100 wH = 150 wL = 50 k = 60 class Subsession(BaseSubsession): pass class Group(BaseGroup): position_list = models.StringField( initial="" ) # shown in result page of different positions numbers and output # number_list = models.StringField( initial="" ) shock_list = models.StringField(initial="") output_list = models.StringField(initial="") alliance_output_list = models.StringField(initial="") #winner_id = models.IntegerField(initial=0) #winner_position_id = models.StringField(initial='') highest_output = models.FloatField(initial=0.0) class Player(BasePlayer): number = models.IntegerField( min=0, max=100, label="Please enter your decision number in this period (between 0 to 100):", ) is_winner = models.BooleanField( initial=False, doc="""Indicates whether the player is the winner""" ) alliance_choice = models.StringField( choices=['Alliance', 'Single'], label = "Please indicate which option you would like to play in this period", widget=widgets.RadioSelect, blank=False, ) alliance_form = models.BooleanField( initial=False, doc="""Indicates whether the alliance is formed""" ) round_payoff = models.FloatField(initial=0.0) cost = models.FloatField(initial=0.0) position = models.StringField(initial='') output = models.FloatField(initial=0.0) alliance_output = models.FloatField(initial=0.0) shock = models.FloatField(initial=0.0) guessA = models.IntegerField( min=0, max=100, initial=0, label="Please enter the decision number you think that player A has selected in this period (between 0 to 100):",) guessB = models.IntegerField( min=0, max=100, initial=0, label="Please enter the decision number you think that player B has selected in this period (between 0 to 100):", ) guessC = models.IntegerField( min=0, max=100, initial=0, label="Please enter the decision number you think that player C has selected in this period (between 0 to 100):", ) guessAB = models.IntegerField( min=0, max=100, initial=0, label="Please enter the AVERAGE decision number that you think players A and B have selected in this period (between 0 to 100):", ) guess_payoff = models.FloatField(initial=0.0) raw_responses = models.LongStringField() chose_lottery = models.BooleanField() won_lottery = models.BooleanField(initial=False) part3_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) decision1 = models.LongStringField(initial=None, label="How did you make your decisions in Part 1, when the option Single was played?") decision2 = models.LongStringField(initial=None, label="How did you make your decisions in Part 1, when the option Alliance was played?") decision3 = models.LongStringField(initial=None, label="Were you willing to form an alliance with your peers in Part 2, why?") decision4 = models.LongStringField(initial=None, label="How did you make your decisions in Part 2, when the option Single was played?") decision5 = models.LongStringField(initial=None, label="How did you make your decisions in Part 2, when the option Alliance was played?") 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 role will be fixed throughout the entire experiment.', widget=widgets.RadioSelect) quiz3 = models.IntegerField( min=0, max=100, label='What is your final number (type in your answer).', ) quiz4 = models.StringField( choices=['Player A (You)', 'Player B', 'Player C'], label='4. Who is the winner in this period', widget=widgets.RadioSelect) quiz5 = models.StringField( choices=['150-your decision cost = 150-18 = 132 points', '50-your decision cost = 50-18 = 32 points', '150/2-your decision cost = 75-18 = 57 points', '50/2-your decision cost = 25-18 = 7 points'], label='5. What is your payment in this period', widget=widgets.RadioSelect) quiz6 = models.IntegerField( min=0, max=200, label='6. What is your alliance’s final number (type in your answer).', ) quiz7 = models.StringField( choices=['Your alliance', 'Player C'], label='7. Who is the winner in this period', widget=widgets.RadioSelect) quiz8 = models.StringField( choices=['150-your decision cost = 150-18 = 132 points', '50-your decision cost = 50-18 = 32 points', '150/2-your decision cost = 75-18 = 57 points', '50/2-your decision cost = 25-18 = 7 points'], label='8. What is your payment in this period', 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): session = subsession.session subsession.group_randomly(fixed_id_in_group=True) #same ID in same positions every 20 rounds if subsession.round_number == 1: ## randomly select 5 rounds for payment paying_round1 = random.randint(1, 10) paying_round2 = random.randint(11, 15) paying_round3 = random.randint(16, 25) paying_round4 = random.randint(26, 30) paying_round5 = random.randint(31, 35) 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 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'] stimuli = read_csv() for stim in stimuli: Trial.create(player=p, **stim) def set_winner(group: Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) r2 = random.random() for p in [p1, p2, p3]: p1.position = 'A' p2.position = 'B' p3.position = 'C' if p.round_number in (3,5,6,8,10): ##1-1-1 contest p.shock = random.uniform(-90, 90) p1.output = p1.shock + p1.number p2.output = p2.shock + p2.number p3.output = p3.shock + p3.number + Constants.k p.alliance_output = p.output elif p.round_number in (1,2,4,7,9,11,12,13,14,15): #1-2 contest p.shock = random.uniform(-90, 90) p.alliance_form = True p1.alliance_output = p1.shock + p1.number + p2.shock + p2.number p2.alliance_output = p1.shock + p1.number + p2.shock + p2.number p3.alliance_output = p3.shock + p3.number + Constants.k p1.output = p1.shock + p1.number p2.output = p2.shock + p2.number p3.output = p3.shock + p3.number + Constants.k else: #select whether would like to form an alliance or not if p.alliance_form: p.shock = random.uniform(-90, 90) p1.alliance_output = p1.shock + p1.number + p2.shock + p2.number p2.alliance_output = p1.shock + p1.number + p2.shock + p2.number p3.alliance_output = p3.shock + p3.number + Constants.k p1.output = p1.shock + p1.number p2.output = p2.shock + p2.number p3.output = p3.shock + p3.number + Constants.k else: p.shock = random.uniform(-90, 90) p1.output = p1.shock + p1.number p2.output = p2.shock + p2.number p3.output = p3.shock + p3.number + Constants.k p.alliance_output = p.output if p.alliance_form: #r2 = random.random() if p1.alliance_output > p3.output: p1.is_winner = True p2.is_winner = True p3.is_winner = False elif p1.alliance_output < p3.output: p3.is_winner = True p1.is_winner = False p2.is_winner = False elif p1.alliance_output == p3.alliance_output: if r2>0.5: p1.is_winner = True p2.is_winner = True p3.is_winner = False else: p3.is_winner = True p1.is_winner = False p2.is_winner = False else: if p1.output >= p2.output and p1.output >= p3.output: p1.is_winner = True p2.is_winner = False p3.is_winner = False elif p2.output >= p1.output and p2.output >= p3.output: p2.is_winner = True p1.is_winner = False p3.is_winner = False else: p3.is_winner = True p2.is_winner = False p1.is_winner = False #players = group.get_players() #group.highest_output = max([p.output for p in players]) #players_with_highest_output = [p for p in players if p.output == group.highest_output] #winner = random.choice( # players_with_highest_output #) # if tie, winner is chosen at random #winner.is_winner = True group.position_list = group.position_list + str(p.position) + " " group.number_list = group.number_list + str(p.number) + " " group.shock_list = group.shock_list + str(p.shock) + " " group.output_list = group.output_list + str(p.output) + " " group.alliance_output_list = group.alliance_output_list + str(p.alliance_output) + " " 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]: p.cost = (p.number * p.number)/(2*Constants.a) if p.alliance_form and p1.is_winner: p1.round_payoff = Constants.wH/2 - p1.cost p2.round_payoff = Constants.wH/2 - p2.cost p3.round_payoff = Constants.wL - p3.cost elif p.alliance_form and p3.is_winner: p1.round_payoff = Constants.wL/2 - p1.cost p2.round_payoff = Constants.wL/2 - p2.cost p3.round_payoff = Constants.wH - p3.cost elif p1.is_winner: p1.round_payoff = Constants.wH - p1.cost p2.round_payoff = Constants.wL - p2.cost p3.round_payoff = Constants.wL - p3.cost elif p2.is_winner: p1.round_payoff = Constants.wL - p1.cost p2.round_payoff = Constants.wH - p2.cost p3.round_payoff = Constants.wL - p3.cost else: p1.round_payoff = Constants.wL - p1.cost p2.round_payoff = Constants.wL - p2.cost p3.round_payoff = Constants.wH - p3.cost def close_round(group: Group): set_winner(group) set_payoff(group) set_guesspayoff(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]: p1.position = 'A' p2.position = 'B' p3.position = 'C' def set_alliance(group: Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) r1 = random.random() for p in [p1, p2, p3]: if p.round_number in (1, 2, 4, 7, 9, 11, 12, 13, 14, 15): # 1-2 contest p.alliance_form = True elif p.round_number in (3,5,6,8,10): p.alliance_form = False else: # select whether would like to form an alliance or not #r1 = random.random() if p1.alliance_choice == "Alliance" and p2.alliance_choice == "Alliance": p.alliance_form = True elif p1.alliance_choice == "Single" and p2.alliance_choice == "Single": p.alliance_form = False else: if r1 > 0.5: ## alliance form p.alliance_form = True else: ## alliance not form p.alliance_form = False def set_guesspayoff (group:Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) p3 = group.get_player_by_id(3) if abs(p1.guessB - p2.number)<= 5: p1.guess_payoff = p1.guess_payoff + 1.5 if abs(p1.guessC - p3.number) <= 5: p1.guess_payoff = p1.guess_payoff + 1.5 if abs(p2.guessA - p1.number)<= 5: p2.guess_payoff = p2.guess_payoff + 1.5 if abs(p2.guessC - p3.number)<=5: p2.guess_payoff = p2.guess_payoff + 1.5 if abs(p3.guessAB - (p1.number + p2.number)/2) <=5: p3.guess_payoff = p3.guess_payoff + 3 # PAGES class Welcome(Page): def is_displayed(self): return self.round_number == 1 after_all_players_arrive = creating_session class Quiz(Page): def is_displayed(self): return self.round_number == 1 form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3', 'quiz4', 'quiz5', 'quiz6', 'quiz7', 'quiz8'] @staticmethod def error_message(player, values): solutions = dict( quiz1='Two randomly determined participants', quiz2='True', quiz3=20, quiz4='Player B', quiz5='50-your decision cost = 50-18 = 32 points', quiz6=135, quiz7='Your alliance', quiz8='150/2-your decision cost = 75-18 = 57 points' ) 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 M_Group(Page): @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group set_position(group) def vars_for_template(player: Player): return dict( round_shown=player.round_number, total_shown=Constants.num_rounds ) class Alliance_formation(Page): def is_displayed(player): return player.round_number > 15 and player.position !="C" def vars_for_template(player: Player): return dict( round_shown=player.round_number - 15, total_shown=Constants.num_rounds - 15 ) form_model = 'player' form_fields = ['alliance_choice'] class AllianceWaitPage(WaitPage): def is_displayed(player): return player.round_number > 15 after_all_players_arrive = set_alliance class Alliance_formation_results(Page): def is_displayed(player): return player.round_number > 15 def vars_for_template(player: Player): choice1 = player.group.get_player_by_id(1).alliance_choice choice2 = player.group.get_player_by_id(2).alliance_choice return dict( round_shown=player.round_number - 15, total_shown=Constants.num_rounds - 15, choice1 = choice1, choice2 = choice2 ) class Pre_choice (Page): def is_displayed(player): return player.round_number <= 15 def vars_for_template(player: Player): return dict( round_shown=player.round_number, total_shown=Constants.num_rounds - 20 ) class Part2_instruction(Page): def is_displayed(player): return player.round_number == 16 class Effort_choice(Page): def vars_for_template(player: Player): return dict( round_shown=player.round_number, round_shown2=player.round_number-15, ) form_model = 'player' form_fields = ['number'] class ResultsWaitPage(WaitPage): after_all_players_arrive = close_round class Results(Page): def vars_for_template(player: Player): position_list = player.group.position_list.split(" ") number_list = player.group.number_list.split(" ") shock_list = player.group.shock_list.split(" ") output_list = player.group.output_list.split(" ") alliance_output_list = player.group.alliance_output_list.split(" ") position_list.pop() number_list.pop() shock_list.pop() output_list.pop() alliance_output_list.pop() # participants = ["Participant " + str(i + 1) for i in range(Constants.players_per_group) number1 = player.group.get_player_by_id(1).number number2 = player.group.get_player_by_id(2).number number3 = player.group.get_player_by_id(3).number shock1 = player.group.get_player_by_id(1).shock shock2 = player.group.get_player_by_id(2).shock shock3 = player.group.get_player_by_id(3).shock output1 = player.group.get_player_by_id(1).output output2 = player.group.get_player_by_id(2).output output3 = player.group.get_player_by_id(3).output alliance_output1 = player.group.get_player_by_id(1).alliance_output alliance_output2 = player.group.get_player_by_id(2).alliance_output alliance_output3 = player.group.get_player_by_id(3).alliance_output winner1 = player.group.get_player_by_id(1).is_winner winner2 = player.group.get_player_by_id(2).is_winner winner3 = player.group.get_player_by_id(3).is_winner return dict( position_list=position_list, number_list=number_list, shock_list=shock_list, output_list=output_list, number1=number1, number2=number2, number3=number3, shock1=shock1, shock2=shock2, shock3=shock3, output1=output1, output2=output2, output3=output3, alliance_output1 = alliance_output1, alliance_output2=alliance_output2, alliance_output3=alliance_output3, winner1 = winner1, winner2 = winner2, winner3 = winner3, round_shown=player.round_number, total_shown=Constants.num_rounds ) class 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.part3_payoff = risk_payoff class 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 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 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']) 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, part1_payoff= 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, part3_payoff=player.part3_payoff, part1_payoff_currency=((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) / 30), total_payoff_currency=7 + ((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)/30) + player.part3_payoff + player.guess_payoff, paying_round1=session.vars['paying_round1'], paying_round2=session.vars['paying_round2'], paying_round3=session.vars['paying_round3'], paying_round4=session.vars['paying_round4'], paying_round5=session.vars['paying_round5'], player_chose_lottery=player.chose_lottery, player_won_lottery=player.won_lottery, guess_payoff = player.guess_payoff ) class Guess_instruction(Page): def is_displayed(player: Player): return player.round_number == Constants.num_rounds def vars_for_template(player: Player): other1 = player.get_others_in_group()[0] other2 = player.get_others_in_group()[1] return dict( round_shown=player.round_number - 15, total_shown=Constants.num_rounds - 15, other1=other1, other2=other2, ) class GuessResults(Page): def is_displayed(player: Player): return player.round_number == Constants.num_rounds def vars_for_template(player: Player): other1 = player.get_others_in_group()[0] other2 = player.get_others_in_group()[1] guess1 = player.group.get_player_by_id(1).guess_payoff guess2 = player.group.get_player_by_id(2).guess_payoff guess3 = player.group.get_player_by_id(3).guess_payoff return dict( round_shown=player.round_number - 15, total_shown=Constants.num_rounds - 15, other1=other1, other2=other2, guess1 = guess1, guess2 = guess2, guess3= guess3 ) class GuessA(Page): def is_displayed(player: Player): return player.round_number == Constants.num_rounds and player.position == 'A' def vars_for_template(player: Player): other1 = player.get_others_in_group()[0] other2 = player.get_others_in_group()[1] return dict( round_shown=player.round_number-15, total_shown=Constants.num_rounds-15, other1 = other1, other2 = other2 ) form_model = 'player' form_fields = [ 'guessB', 'guessC', ] class GuessB(Page): def is_displayed(player: Player): return player.round_number == Constants.num_rounds and player.position == 'B' def vars_for_template(player: Player): other1 = player.get_others_in_group()[0] other2 = player.get_others_in_group()[1] return dict( round_shown=player.round_number-15, total_shown=Constants.num_rounds-15, other1 = other1, other2 = other2 ) form_model = 'player' form_fields = [ 'guessA', 'guessC', ] class GuessC(Page): def is_displayed(player: Player): return player.round_number == Constants.num_rounds and player.position == 'C' def vars_for_template(player: Player): other1 = player.get_others_in_group()[0] other2 = player.get_others_in_group()[1] return dict( round_shown=player.round_number-15, total_shown=Constants.num_rounds-15, other1 = other1, other2 = other2 ) form_model = 'player' form_fields = ['guessAB'] class CommentsAB(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds and player.position != 'C' form_model = 'player' form_fields = ['decision1', 'decision2', 'decision3', 'decision4', 'decision5', 'comments'] class CommentsC(Page): @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds and player.position == 'C' form_model = 'player' form_fields = ['decision1', 'decision2', 'decision4', 'decision5', 'comments'] page_sequence = [Welcome, Quiz, Part2_instruction, M_Group, Pre_choice, Alliance_formation, AllianceWaitPage, Alliance_formation_results, Effort_choice, Guess_instruction, GuessA, GuessB, GuessC, ResultsWaitPage, Results, GuessResults, Stimuli, Stimuli_Results, Demographic, CommentsAB, CommentsC, End_game ]