import random from otree.api import * import random as rd from copy import deepcopy doc = """ This is a 30-shot game. One player is asked separately whether they want to choose option 1, 2, or 3. Their choices directly determine the payoffs. """ def randq(qlist): seed = rd.random() for item in qlist: rd.Random(seed).shuffle(item) def contactlist(list1, list2, list3): list0 = [] for i in range(0, len(list1)): q = list1[i] + list2[i] + list3[i] list0.append(q) return list0 # models class C(BaseConstants): NAME_IN_URL = 'money_game2' PLAYERS_PER_GROUP = None INSTRUCTIONS_TEMPLATE = 'strategyLearningControl/instructions.html' INSTRUCTIONREST_TEMPLATE = 'strategyLearningControl/instructionsRest.html' # session1 PAYOFF_A11_1 = [79, 56, 67, 64, 38, 43, 52, 30, 39, 52] PAYOFF_A12_1 = [60, 46, 43, 36, 17, 16, 78, 56, 67, 85] PAYOFF_A13_1 = [0, 0, 0, 0, 51, 65, 54, 0, 0, 0] PAYOFF_A21_1 = [70, 51, 55, 74, 58, 45, 67, 44, 54, 70] PAYOFF_A22_1 = [44, 36, 22, 54, 38, 34, 32, 19, 28, 38] PAYOFF_A23_1 = [0, 0, 0, 0, 36, 14, 94, 0, 0, 0] PAYOFF_A31_1 = [0, 0, 0, 0, 19, 32, 69, 0, 0, 0] PAYOFF_A32_1 = [0, 0, 0, 0, 72, 52, 54, 0, 0, 0] PAYOFF_A33_1 = [0, 0, 0, 0, 49, 34, 30, 0, 0, 0] PAYOFF_B11_1 = [37, 32, 13, 82, 35, 32, 84, 42, 52, 67] PAYOFF_B12_1 = [74, 53, 61, 26, 49, 11, 83, 17, 25, 35] PAYOFF_B13_1 = [0, 0, 0, 0, 55, 20, 48, 0, 0, 0] PAYOFF_B21_1 = [86, 60, 76, 29, 63, 49, 52, 32, 42, 55] PAYOFF_B22_1 = [35, 31, 10, 69, 33, 31, 26, 23, 31, 43] PAYOFF_B23_1 = [0, 0, 0, 0, 64, 43, 37, 0, 0, 0] PAYOFF_B31_1 = [0, 0, 0, 0, 14, 57, 74, 0, 0, 0] PAYOFF_B32_1 = [0, 0, 0, 0, 23, 56, 51, 0, 0, 0] PAYOFF_B33_1 = [0, 0, 0, 0, 36, 29, 67, 0, 0, 0] OtherChoice_1 = [2, 2, 2, 2, 3, 1, 1, 1, 1, 1] CorrectChoice_1 = [1, 1, 1, 2, 1, 2, 3, 2, 2, 2] # session2 PAYOFF_A11_2 = [42, 29, 48, 71, 78, 44, 60, 50, 63, 76] PAYOFF_A12_2 = [72, 66, 29, 53, 52, 61, 69, 35, 38, 31] PAYOFF_A13_2 = [95, 50, 31, 55, 0, 0, 0, 0, 0, 0] PAYOFF_A21_2 = [81, 42, 31, 39, 88, 29, 52, 42, 49, 13] PAYOFF_A22_2 = [59, 27, 42, 63, 68, 52, 65, 57, 75, 56] PAYOFF_A23_2 = [61, 51, 13, 82, 0, 0, 0, 0, 0, 0] PAYOFF_A31_2 = [61, 56, 15, 55, 0, 0, 0, 0, 0, 0] PAYOFF_A32_2 = [74, 42, 40, 65, 0, 0, 0, 0, 0, 0] PAYOFF_A33_2 = [40, 41, 60, 38, 0, 0, 0, 0, 0, 0] PAYOFF_B11_2 = [37, 25, 52, 74, 95, 56, 67, 43, 51, 9] PAYOFF_B12_2 = [59, 32, 53, 75, 42, 22, 48, 37, 42, 52] PAYOFF_B13_2 = [46, 41, 26, 50, 0, 0, 0, 0, 0, 0] PAYOFF_B21_2 = [86, 40, 28, 35, 44, 20, 47, 49, 61, 19] PAYOFF_B22_2 = [87, 50, 45, 53, 83, 67, 73, 34, 36, 35] PAYOFF_B23_2 = [56, 54, 40, 43, 0, 0, 0, 0, 0, 0] PAYOFF_B31_2 = [58, 59, 10, 52, 0, 0, 0, 0, 0, 0] PAYOFF_B32_2 = [78, 38, 29, 68, 0, 0, 0, 0, 0, 0] PAYOFF_B33_2 = [72, 60, 18, 63, 0, 0, 0, 0, 0, 0] OtherChoice_2 = [2, 3, 2, 2, 2, 1, 1, 1, 1, 2] CorrectChoice_2 = [3, 2, 2, 3, 2, 1, 1, 1, 1, 2] # session3 PAYOFF_A11_3 = [65, 65, 50, 38, 45, 20, 95, 49, 26, 38] PAYOFF_A12_3 = [74, 53, 33, 75, 55, 43, 54, 77, 69, 66] PAYOFF_A13_3 = [50, 33, 31, 0, 0, 0, 0, 0, 0, 0] PAYOFF_A21_3 = [79, 51, 17, 62, 52, 34, 37, 91, 90, 80] PAYOFF_A22_3 = [64, 72, 62, 89, 59, 51, 76, 61, 45, 50] PAYOFF_A23_3 = [65, 53, 42, 0, 0, 0, 0, 0, 0, 0] PAYOFF_A31_3 = [52, 63, 33, 0, 0, 0, 0, 0, 0, 0] PAYOFF_A32_3 = [73, 35, 15, 0, 0, 0, 0, 0, 0, 0] PAYOFF_A33_3 = [89, 85, 44, 0, 0, 0, 0, 0, 0, 0] PAYOFF_B11_3 = [63, 69, 54, 25, 41, 12, 33, 53, 32, 42] PAYOFF_B12_3 = [77, 50, 28, 99, 62, 57, 72, 64, 49, 53] PAYOFF_B13_3 = [73, 63, 55, 0, 0, 0, 0, 0, 0, 0] PAYOFF_B21_3 = [82, 77, 12, 82, 57, 47, 42, 46, 22, 35] PAYOFF_B22_3 = [83, 76, 20, 28, 42, 14, 57, 75, 65, 64] PAYOFF_B23_3 = [61, 48, 31, 0, 0, 0, 0, 0, 0, 0] PAYOFF_B31_3 = [48, 51, 30, 0, 0, 0, 0, 0, 0, 0] PAYOFF_B32_3 = [64, 30, 42, 0, 0, 0, 0, 0, 0, 0] PAYOFF_B33_3 = [55, 39, 47, 0, 0, 0, 0, 0, 0, 0] OtherChoice_3 = [2, 1, 3, 1, 1, 1, 2, 2, 2, 2] CorrectChoice_3 = [1, 1, 3, 2, 2, 2, 2, 1, 1, 1] # random Qlist1 = [PAYOFF_A11_1, PAYOFF_A12_1, PAYOFF_A13_1, PAYOFF_A21_1, PAYOFF_A22_1, PAYOFF_A23_1, PAYOFF_A31_1, PAYOFF_A32_1, PAYOFF_A33_1, PAYOFF_B11_1, PAYOFF_B12_1, PAYOFF_B13_1, PAYOFF_B21_1, PAYOFF_B22_1, PAYOFF_B23_1, PAYOFF_B31_1, PAYOFF_B32_1, PAYOFF_B33_1, OtherChoice_1, CorrectChoice_1] Qlist2 = [PAYOFF_A11_2, PAYOFF_A12_2, PAYOFF_A13_2, PAYOFF_A21_2, PAYOFF_A22_2, PAYOFF_A23_2, PAYOFF_A31_2, PAYOFF_A32_2, PAYOFF_A33_2, PAYOFF_B11_2, PAYOFF_B12_2, PAYOFF_B13_2, PAYOFF_B21_2, PAYOFF_B22_2, PAYOFF_B23_2, PAYOFF_B31_2, PAYOFF_B32_2, PAYOFF_B33_2, OtherChoice_2, CorrectChoice_2] Qlist3 = [PAYOFF_A11_3, PAYOFF_A12_3, PAYOFF_A13_3, PAYOFF_A21_3, PAYOFF_A22_3, PAYOFF_A23_3, PAYOFF_A31_3, PAYOFF_A32_3, PAYOFF_A33_3, PAYOFF_B11_3, PAYOFF_B12_3, PAYOFF_B13_3, PAYOFF_B21_3, PAYOFF_B22_3, PAYOFF_B23_3, PAYOFF_B31_3, PAYOFF_B32_3, PAYOFF_B33_3, OtherChoice_3, CorrectChoice_3] randq(Qlist1) randq(Qlist2) randq(Qlist3) # get together Qlist = contactlist(Qlist1, Qlist2, Qlist3) PAYOFF_A11, PAYOFF_A12, PAYOFF_A13, PAYOFF_A21, PAYOFF_A22 = Qlist[0], Qlist[1], Qlist[2], Qlist[3], Qlist[4] PAYOFF_A23, PAYOFF_A31, PAYOFF_A32, PAYOFF_A33, PAYOFF_B11 = Qlist[5], Qlist[6], Qlist[7], Qlist[8], Qlist[9] PAYOFF_B12, PAYOFF_B13, PAYOFF_B21, PAYOFF_B22, PAYOFF_B23 = Qlist[10], Qlist[11], Qlist[12], Qlist[13], Qlist[14] PAYOFF_B31, PAYOFF_B32, PAYOFF_B33, OtherChoice, CorrectChoice = Qlist[15], Qlist[16], Qlist[17], Qlist[18], Qlist[19] NUM_ROUNDS = len(PAYOFF_A11) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): option1 = models.IntegerField( choices=[[1, 'Option1'], [2, 'Option2'], [3, 'Option3']], doc="""This player's decision""", widget=widgets.RadioSelect, ) payoff_per_trial = models.IntegerField # functions def set_payoff(player: Player): a = models.IntegerField participant = player.participant payoff_matrix = { (1, 1): C.PAYOFF_A11[player.round_number - 1], (1, 2): C.PAYOFF_A12[player.round_number - 1], (1, 3): C.PAYOFF_A13[player.round_number - 1], (2, 1): C.PAYOFF_A21[player.round_number - 1], (2, 2): C.PAYOFF_A22[player.round_number - 1], (2, 3): C.PAYOFF_A23[player.round_number - 1], (3, 1): C.PAYOFF_A31[player.round_number - 1], (3, 2): C.PAYOFF_A32[player.round_number - 1], (3, 3): C.PAYOFF_A33[player.round_number - 1], } player.payoff_per_trial = payoff_matrix[(player.option1, C.OtherChoice[player.round_number - 1])] player.payoff = player.payoff_per_trial # random select if player.round_number == 1: participant.selected_payoff = [] participant.selected_round = [] participant.pays_per_trial = [] participant.correct_choice = [] participant.selected = [] participant.luck = rd.randint(1, 10) participant.pays_per_trial.append(player.payoff_per_trial) participant.correct_choice.append(C.CorrectChoice[player.round_number-1]) if player.round_number % len(C.PAYOFF_A11_1) == 0: ranked_pays_last = sorted(participant.pays_per_trial[-10:]) if participant.luck == 1: selected_trial = rd.randint(0, 9) participant.selected_payoff.append(ranked_pays_last[selected_trial]) participant.selected_round.append(participant.pays_per_trial[-10:].index(ranked_pays_last[selected_trial])+1) else: participant.selected_payoff.append(ranked_pays_last[2]) participant.selected_round.append(participant.pays_per_trial[-10:].index(ranked_pays_last[2])+1) select_round_list = [1 if value == participant.selected_payoff[-1] else 0 for value in participant.pays_per_trial[-10:]] participant.selected.extend(select_round_list) def custom_export(players): yield ['participant.id_in_session', 'participant', 'start_time', 'round_number', 'option', 'equilibrium_choice', 'payoff_per_round', 'selected_pay', 'total_payment', 'session.code'] for p in players: participant = p.participant session = p.session yield [participant.id_in_session, participant.code, participant.time_started_utc, p.round_number, p.option1, participant.correct_choice[p.round_number - 1], participant.pays_per_trial[p.round_number-1], participant.selected[p.round_number-1], sum(participant.selected_payoff), session.code] # PAGES class Introduction(Page): # timeout_seconds = 100 @staticmethod def is_displayed(player): return player.round_number % len(C.PAYOFF_A11_1) == 1 def vars_for_template(self): session_num = self.round_number // len(C.PAYOFF_A11_1) session_num_word = models.StringField if session_num == 1: session_num_word = 'second' elif session_num == 2: session_num_word = 'third' else: session_num_word = 'final' return { 'restInstruct': self.round_number // len(C.PAYOFF_A11_1) >= 1, 'session_number': session_num_word } class Decision(Page): form_model = 'player' form_fields = ['option1'] a = models.IntegerField def vars_for_template(self): hard = models.IntegerField if C.PAYOFF_A13[self.round_number - 1] == 0: hard = 2 round_num = models.IntegerField if self.round_number % len(C.PAYOFF_A11_1) == 0: round_num = len(C.PAYOFF_A11_1) else: round_num = self.round_number % len(C.PAYOFF_A11_1) return { 'frame': hard == 2, 'round_number': round_num, 'payoffA11': C.PAYOFF_A11[self.round_number - 1], 'payoffA12': C.PAYOFF_A12[self.round_number - 1], 'payoffA13': C.PAYOFF_A13[self.round_number - 1], 'payoffB11': C.PAYOFF_B11[self.round_number - 1], 'payoffB12': C.PAYOFF_B12[self.round_number - 1], 'payoffB13': C.PAYOFF_B13[self.round_number - 1], 'payoffA21': C.PAYOFF_A21[self.round_number - 1], 'payoffA22': C.PAYOFF_A22[self.round_number - 1], 'payoffA23': C.PAYOFF_A23[self.round_number - 1], 'payoffB21': C.PAYOFF_B21[self.round_number - 1], 'payoffB22': C.PAYOFF_B22[self.round_number - 1], 'payoffB23': C.PAYOFF_B23[self.round_number - 1], 'payoffA31': C.PAYOFF_A31[self.round_number - 1], 'payoffA32': C.PAYOFF_A32[self.round_number - 1], 'payoffA33': C.PAYOFF_A33[self.round_number - 1], 'payoffB31': C.PAYOFF_B31[self.round_number - 1], 'payoffB32': C.PAYOFF_B32[self.round_number - 1], 'payoffB33': C.PAYOFF_B33[self.round_number - 1] } def before_next_page(player: Player, timeout_happened): set_payoff(player) class Results(Page): @staticmethod def vars_for_template(player: Player): payoff_sum = player.session.config['participation_fee'] + player.session.config[ 'real_world_currency_per_point'] * sum(player.participant.selected_payoff) points = sum(player.participant.selected_payoff) return dict( round1=player.participant.selected_round[0], round2=player.participant.selected_round[1], round3=player.participant.selected_round[2], pay1=player.participant.selected_payoff[0], pay2=player.participant.selected_payoff[1], pay3=player.participant.selected_payoff[2], points=points, payoff_all=payoff_sum ) def is_displayed(player: Player): return player.round_number == len(C.PAYOFF_A11) class Rest(Page): timeout_seconds = 60 @staticmethod def is_displayed(player): return player.round_number % len(C.PAYOFF_A11_1) == 0 and player.round_number < len(C.PAYOFF_A11) def vars_for_template(self): session_num = self.round_number//len(C.PAYOFF_A11_1) session_num_word = models.StringField if session_num == 1: session_num_word = 'first' elif session_num == 2: session_num_word = 'second' return { 'session_number': session_num_word } page_sequence = [Introduction, Decision, Rest, Results]