from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import random from random import randrange import numpy as np import itertools doc = """ """ class Constants(BaseConstants): name_in_url = 'ellsberg' players_per_group = None num_rounds = 5 num_choices = 11 instructions_template = 'ellsberg/instructions.html' probability = 0 step_size1 = 10 step_size2 = 1 num_balls = 60 samplesize = [3,3,30,30] winningamount = 5 textA = "one by one with replacement" textB = "together from the bag at once" class Subsession(BaseSubsession): # initiate lists before session starts in round 1 # ---------------------------------------------------------------------------------------------------------------- def creating_session(self): if self.round_number == 1: # randomly assign players to the treatment if self.session.config['color'] == 'swr': for p in self.get_players(): p.participant.vars['replacement'] = 1 elif self.session.config['color'] == 'swor': for p in self.get_players(): p.participant.vars['replacement'] = 0 else: replacement = itertools.cycle([1,0]) for p in self.get_players(): p.participant.vars['replacement'] = next(replacement) paying_round = random.randint(1, Constants.num_rounds) self.session.vars['paying_round'] = paying_round print("paying_round is " + str(paying_round)) n = Constants.num_choices for p in self.get_players(): # create list of lottery indices # ---------------------------------------------------------------------------------------------------- indices = [j for j in range(1, n + 1)] # create list corresponding to form_field variables including all choices # ---------------------------------------------------------------------------------------------------- form_fields = ['firstchoice_' + str(k) for k in indices] # create list of probabilities # ---------------------------------------------------------------------------------------------------- probabilities = [Constants.probability + (k - 1) * Constants.step_size1 for k in indices] # create list of choices # ---------------------------------------------------------------------------------------------------- p.participant.vars['firstchoice'] = list( zip( indices, form_fields, probabilities, ) ) # randomly determine index/choice of binary decision to pay # ---------------------------------------------------------------------------------------------------- p.participant.vars['choice_to_pay'] = None p.participant.vars['index_to_pay'] = None round_number = [j for j in range(1, Constants.num_rounds + 1)] x = [[] for _ in range(1, Constants.num_rounds + 1)] p.participant.vars['secondchoice_allrounds'] = list( zip( round_number, x, ) ) # initiate list for choices made # ---------------------------------------------------------------------------------------------------- p.participant.vars['firstchoice_made'] = [None for j in range(1, n + 1)] p.participant.vars['secondchoice_made'] = [None for j in range(1, n + 1)] # generate random switching point for PlayerBot in tests.py # -------------------------------------------------------------------------------------------------------- for participant in self.session.get_participants(): participant.vars['cem-bot_switching_point'] = random.randint(1, n) class Group(BaseGroup): pass class Player(BasePlayer): # add model fields to class player # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: for j in range(1, Constants.num_choices + 1): locals()['firstchoice_' + str(j)] = models.StringField() del j # add model fields to class player # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: for j in range(1, Constants.num_choices - 1): locals()['secondchoice_' + str(j)] = models.StringField() del j # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: for j in range(1, 3): locals()['quiz_' + str(j)] = models.IntegerField() del j for j in range(1, 3): locals()['switching_row_' + str(j)] = models.IntegerField() del j random_draw = models.IntegerField() index_to_pay = models.IntegerField() choice_to_pay = models.StringField() option_to_pay = models.StringField() quiz = models.BooleanField() color = models.IntegerField() samplesize = models.IntegerField() winningcolor = models.StringField() replacement = models.BooleanField() gender = models.CharField( choices=['Male', 'Female'], ) age = models.PositiveIntegerField(min=18, max=99) prolific = models.StringField() payinground = models.IntegerField() finalpayoff = models.CurrencyField() ## get parameters def getcolor(self): if self.participant.vars['replacement'] == 1: replacement_all = [1,1,1,1] else: replacement_all = [0,0,0,0] bags = [j for j in range(1, 5)] if self.color == 1: wincolor = ['red','green or blue'] * 2 elif self.color == 2: wincolor = ['green','red or blue'] * 2 else: wincolor = ['blue','red or green'] * 2 self.participant.vars['bags'] = list( zip( bags, Constants.samplesize, wincolor, replacement_all, ) ) self.participant.vars['bags'].extend(random.sample(self.participant.vars['bags'], 1)) # randomize order of bags random.shuffle(self.participant.vars['bags']) # set player's payoff # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: def set_payoffs2(self): # dirichlet size, for replacement ds = round(1 + self.samplesize / 3) dirichlet_p = np.random.dirichlet((ds, ds, ds), )[0] if self.winningcolor == 'red' or self.winningcolor == 'blue' or self.winningcolor == 'green': dirichlet_pro = dirichlet_p else: dirichlet_pro = 1-dirichlet_p # uniform prior, for without replacement low = round(self.samplesize / 3 ) high = round(Constants.num_balls - self.samplesize * 2 / 3) noreplacement_p = random.randint(low,high)/Constants.num_balls if self.winningcolor == 'red' or self.winningcolor == 'blue' or self.winningcolor == 'green': noreplacement_pro = noreplacement_p else: noreplacement_pro = 1-noreplacement_p # random draw part A or B to determine the payoff self.random_draw = random.randint(1, 2) # set player's payoff # ------------------------------------------------------------------------------------------------------------ if self.random_draw == 1: # set to participant.var['choice_to_pay'] determined creating_session # ------------------------------------------------------------------------------------------------------------ self.index_to_pay= random.randint(1,Constants.num_choices) self.participant.vars['index_to_pay'] = self.index_to_pay self.participant.vars['choice_to_pay'] = 'firstchoice_' + str(self.participant.vars['index_to_pay']) self.choice_to_pay = self.participant.vars['choice_to_pay'] # determine whether the lottery (option "A") or the sure payoff (option "B") was chosen # ------------------------------------------------------------------------------------------------------------ self.option_to_pay = getattr(self, self.choice_to_pay) probabilities = [list(t) for t in zip(*self.participant.vars['firstchoice'])][2] if self.option_to_pay == 'B': probability_to_pay = (probabilities[self.index_to_pay - 1]) / 100 self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount else: if self.replacement == True: probability_to_pay = dirichlet_pro self.payoff = np.random.binomial(1, probability_to_pay)* Constants.winningamount else: probability_to_pay = noreplacement_pro self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount else: self.index_to_pay = random.randint(1, Constants.num_choices - 2) self.participant.vars['index_to_pay'] = self.index_to_pay self.participant.vars['choice_to_pay'] = 'secondchoice_' + str(self.participant.vars['index_to_pay']) self.choice_to_pay = self.participant.vars['choice_to_pay'] # determine whether the lottery (option "A") or the sure payoff (option "B") was chosen # ------------------------------------------------------------------------------------------------------------ self.option_to_pay = getattr(self, self.choice_to_pay) probabilities = [list(t) for t in zip(*self.participant.vars['secondchoice'])][2] probability_to_pay = (probabilities[self.index_to_pay - 1]) / 100 if self.option_to_pay == 'B': self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount else: if self.replacement == True: probability_to_pay = dirichlet_pro self.payoff = np.random.binomial(1, probability_to_pay)* Constants.winningamount else: probability_to_pay = noreplacement_pro self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount # set payoff as global variable # ------------------------------------------------------------------------------------------------------------ self.participant.vars['payoff'] = self.payoff print("probablity to pay is " + str(probability_to_pay)) print("participant var choice to pay is " + str(self.participant.vars['choice_to_pay'])) print("random_draw is " + str(self.random_draw)) print("switching row is " + str(self.switching_row_1)) def set_payoffs1(self): if self.switching_row_1 == 1 or self.switching_row_1 == 12: # dirichlet size, for replacement ds = round(1 + self.samplesize / 3) dirichlet_p = np.random.dirichlet((ds, ds, ds), )[0] if self.winningcolor == 'red' or self.winningcolor == 'blue' or self.winningcolor == 'green': dirichlet_pro = dirichlet_p else: dirichlet_pro = 1-dirichlet_p # uniform prior, for without replacement low = round(self.samplesize / 3 ) high = round(Constants.num_balls - self.samplesize * 2 / 3) noreplacement_p = random.randint(low,high)/Constants.num_balls if self.winningcolor == 'red' or self.winningcolor == 'blue' or self.winningcolor == 'green': noreplacement_pro = noreplacement_p else: noreplacement_pro = 1-noreplacement_p # set to participant.var['choice_to_pay'] determined creating_session # ------------------------------------------------------------------------------------------------------------ self.index_to_pay = random.randint(1, Constants.num_choices) self.participant.vars['index_to_pay'] = self.index_to_pay self.participant.vars['choice_to_pay'] = 'firstchoice_' + str(self.participant.vars['index_to_pay']) self.choice_to_pay = self.participant.vars['choice_to_pay'] # determine whether the lottery (option "A") or the sure payoff (option "B") was chosen # ------------------------------------------------------------------------------------------------------------ self.option_to_pay = getattr(self, self.choice_to_pay) probabilities = [list(t) for t in zip(*self.participant.vars['firstchoice'])][2] if self.option_to_pay == 'B': probability_to_pay = (probabilities[self.index_to_pay - 1]) / 100 self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount else: if self.replacement == True: probability_to_pay = dirichlet_pro self.payoff = np.random.binomial(1, probability_to_pay)* Constants.winningamount else: probability_to_pay = noreplacement_pro self.payoff = np.random.binomial(1, probability_to_pay) * Constants.winningamount # set payoff as global variable # ------------------------------------------------------------------------------------------------------------ self.participant.vars['payoff'] = self.payoff print("probablity to pay is " + str(probability_to_pay)) print("participant var choice to pay is " + str(self.participant.vars['choice_to_pay'])) print("random_draw is " + str(self.random_draw)) print("switching row is " + str(self.switching_row_1)) else: pass # determine switching row # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: def set_switching_row_1(self): # replace A's by 1's and B's by 0's self.participant.vars['firstchoice_made'] = [ 1 if j == 'A' else 0 for j in self.participant.vars['firstchoice_made'] ] # set switching point to row number of first 'B' choice self.switching_row_1 = sum(self.participant.vars['firstchoice_made']) + 1 if self.switching_row_1 == 1 or self.switching_row_1 == 12: self.participant.vars['noswitch'] = True else: self.participant.vars['noswitch'] = False def set_switching_row_2(self): # replace A's by 1's and B's by 0's self.participant.vars['secondchoice_made'] = [ 1 if j == 'A' else 0 for j in self.participant.vars['secondchoice_made'] ] # set switching point to row number of first 'B' choice self.switching_row_2 = sum(self.participant.vars['secondchoice_made']) + 1 ## check if quiz is correct def check_quiz(self): if self.quiz_1 == 2 and self.quiz_2 == 2: self.quiz = True else: self.quiz = False # set up the second choice based on the first choice def set_secondchoice(self): x = (self.switching_row_1 - 2) * Constants.step_size1 n = Constants.num_choices r = self.subsession.round_number # create list of lottery indices # ---------------------------------------------------------------------------------------------------- indices = [j for j in range(1, n - 1)] # create list corresponding to form_field variables including all choices # ---------------------------------------------------------------------------------------------------- form_fields = ['secondchoice_' + str(k) for k in indices] # create list of probabilities # ---------------------------------------------------------------------------------------------------- probabilities = [x + k * Constants.step_size2 for k in indices] # create list of choices # ---------------------------------------------------------------------------------------------------- self.participant.vars['secondchoice'] = list( zip( indices, form_fields, probabilities, ) ) self.participant.vars['secondchoice_allrounds'][r-1]=(r,self.participant.vars['secondchoice']) def set_bags(self): x = self.subsession.round_number mybags = self.participant.vars['bags'][x-1] self.samplesize = mybags[1] self.winningcolor = mybags[2] self.replacement = True if mybags[3]==1 else False def set_final_payoff(self): x = self.session.vars['paying_round'] self.finalpayoff = self.in_round(x).payoff self.payinground = self.session.vars['paying_round']