from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import csv import random # import numpy as np USE_POINTS = False author = 'Your name here' doc = """ A quiz app that reads its questions from a spreadsheet (see quiz.csv in this directory). There is 1 question per page; the number of pages in the game is determined by the number of questions in the CSV. See the comment below about how to randomize the order of pages. """ class Constants(BaseConstants): name_in_url = 'my_quiz1' players_per_group = None with open('my_quiz1/MCquestions.csv') as questions_file: questions = list(csv.DictReader(questions_file)) num_rounds = len(questions) bonus = 5 beta = 0.5 cost0 = c(-3.50) cost1 = c(-3.00) cost2 = c(-2.50) cost3 = c(-2.00) cost4 = c(-1.50) cost5 = c(-1.00) cost6 = c(-0.50) cost7 = c(-0.00) cost8 = c(+0.50) cost9 = c(+1.00) costs = [cost0, cost1, cost2, cost3, cost4, cost5, cost6, cost7, cost8, cost9] lottery00 = c(2.00) lottery01 = c(1.50) lottery02 = c(1.00) lottery03 = c(0.50) lottery04 = c(0.00) lottery0 = [lottery00, lottery01, lottery02, lottery03, lottery04] lottery10 = c(2.00) lottery11 = c(3.00) lottery12 = c(4.00) lottery13 = c(5.00) lottery14 = c(6.00) lottery1 = [lottery10, lottery11, lottery12, lottery13, lottery14] error1 = -2 error2 = -1 error3 = 0 error4 = 1 error5 = 2 guaranty = c(5.00) class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: self.session.vars['questions'] = Constants.questions.copy() ## ALTERNATIVE DESIGN: ## to randomize the order of the questions, you could instead do: # import random # randomized_questions = random.sample(Constants.questions, len(Constants.questions)) # self.session.vars['questions'] = randomized_questions # paying_round = random.randint(1, Constants.num_rounds) # self.session.vars['paying_round'] = paying_round ## and to randomize differently for each participant, you could use ## the random.sample technique, but assign into participant.vars ## instead of session.vars. for p in self.get_players(): question_data = p.current_question() p.question_id = question_data['id'] p.question = question_data['question'] p.solution = question_data['solution'] class Group(BaseGroup): pass class Player(BasePlayer): prior_num_guess = models.IntegerField( min=0, max=20, label='How many questions do you think you answered correctly?' ) prior_prob_guess1 = models.IntegerField( min=0, max=100, initial=0, blank=True ) prior_prob_guess2 = models.IntegerField( min=0, max=100, initial=0, blank=True ) prior_prob_guess3 = models.IntegerField( min=0, max=100, initial=0, blank=True ) prior_prob_guess4 = models.IntegerField( min=0, max=100, initial=0, blank=True ) prior_prob_guess5 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_num_guess = models.IntegerField( min=0, max=20, label='How many questions do you think you answered correctly?' ) post_prob_guess0 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess1 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess2 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess3 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess4 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess5 = models.IntegerField( min=0, max=100, initial=0, blank=True ) post_prob_guess6 = models.IntegerField( min=0, max=100, initial=0, blank=True ) lottery_choice = models.IntegerField( choices=[ (0, 'A: 50% chance of receiving $2; B: 50% chance of receiving $2.00.'), (1, 'A: 50% chance of receiving $3; B: 50% chance of receiving $1.50.'), (2, 'A: 50% chance of receiving $4; B: 50% chance of receiving $1.00.'), (3, 'A: 50% chance of receiving $5; B: 50% chance of receiving $0.50.'), (4, 'A: 50% chance of receiving $6; B: 50% chance of receiving $0.00.'), ], widget=widgets.RadioSelect, label='Among the five choices listed below, which one do you prefer the most?' ) def make_field(label): return models.BooleanField( choices=[(True, 'Request Regrade'), (False, 'Do Not Request Regrade')], label=label, widget=widgets.RadioSelectHorizontal, ) s0 = make_field('If you ask for a regrade, you pay $3.5.') s1 = make_field('If you ask for a regrade, you pay $3.') s2 = make_field('If you ask for a regrade, you pay $2.5.') s3 = make_field('If you ask for a regrade, you pay $2.') s4 = make_field('If you ask for a regrade, you pay $1.5.') s5 = make_field('If you ask for a regrade, you pay $1.') s6 = make_field('If you ask for a regrade, you pay $0.5.') s7 = make_field('If you ask for a regrade, you pay $0.') s8 = make_field('If you ask for a regrade, you GET PAID $0.5.') s9 = make_field('If you ask for a regrade, you GET PAID $1.') stdchoice = models.IntegerField( choices=[ (1, '$11.50'), (2, '$14.00'), (3, '$14.50'), (4, '$15.00'), ], widget=widgets.RadioSelect, label="" ) practice_guess1 = models.IntegerField( choices=[ (1, '$5.00'), (2, '$4.50'), (3, '$3.00'), (4, '$0.50'), (5, '$0.00'), ], widget=widgets.RadioSelect, label="" ) practice1 = models.IntegerField( choices=[ (1, '1/3'), (2, '2/3'), ], widget=widgets.RadioSelect, label="" ) practice2 = models.IntegerField( choices=[ (1, '1/3'), (2, '2/3'), ], widget=widgets.RadioSelect, label="" ) question_id = models.IntegerField() question = models.StringField() solution = models.StringField() submitted_answer = models.StringField(widget=widgets.RadioSelect) is_correct = models.BooleanField() orig_grading = models.BooleanField() fn_grading = models.BooleanField() orig_correct = models.IntegerField() orig_payoff = models.CurrencyField() orig_payoff0 = models.CurrencyField() orig_payoff1 = models.CurrencyField() orig_payoff2 = models.CurrencyField() orig_payoff3 = models.CurrencyField() orig_payoff4 = models.CurrencyField() orig_payoff5 = models.CurrencyField() orig_payoff6 = models.CurrencyField() orig_bonus = models.CurrencyField(min=c(0.00)) orig_bonus0 = models.CurrencyField(min=c(0.00)) orig_bonus1 = models.CurrencyField(min=c(0.00)) orig_bonus2 = models.CurrencyField(min=c(0.00)) orig_bonus3 = models.CurrencyField(min=c(0.00)) orig_bonus4 = models.CurrencyField(min=c(0.00)) orig_bonus5 = models.CurrencyField(min=c(0.00)) orig_bonus6 = models.CurrencyField(min=c(0.00)) orig_comp = models.CurrencyField(min=c(0.00)) orig_comp0 = models.CurrencyField(min=c(0.00)) orig_comp1 = models.CurrencyField(min=c(0.00)) orig_comp2 = models.CurrencyField(min=c(0.00)) orig_comp3 = models.CurrencyField(min=c(0.00)) orig_comp4 = models.CurrencyField(min=c(0.00)) orig_comp5 = models.CurrencyField(min=c(0.00)) orig_comp6 = models.CurrencyField(min=c(0.00)) lottery_draw = models.BooleanField() lottery_bonus = models.CurrencyField(min=c(0.00)) total_payoff = models.CurrencyField(min=c(0.00)) num_correct = models.IntegerField() regrade_cost = models.CurrencyField(min=c(0.00)) prior_prob_true = models.IntegerField() post_prob_true = models.IntegerField() probability = models.IntegerField( min=0, max=100, initial=0, widget=widgets.Slider( # attrs={'step': '1'} ), label='What is the percent chance (between 0 and 100%) you think your answer is correct?' ) def get_lottery(self): self.session.vars['lottery_choice'] = self.in_round(1).lottery_choice lottery_draw = bool(random.getrandbits(1)) self.lottery_draw = lottery_draw self.session.vars['lottery_draw'] = self.lottery_draw if lottery_draw is True: self.lottery_bonus = Constants.lottery1[self.lottery_choice] else: self.lottery_bonus = Constants.lottery0[self.lottery_choice] self.session.vars['lottery_bonus'] = self.lottery_bonus print('lottery_choice', self.lottery_choice) print('lottery_draw', lottery_draw) print('lottery_bonus', self.lottery_bonus) print('sessionvars_lotterychoice_app1', self.session.vars['lottery_choice']) print('sessionvars_lotterydraw_app1', self.session.vars['lottery_draw']) print('sessionvars_lotterybonus_app1', self.session.vars['lottery_bonus']) def current_question(self): return self.session.vars['questions'][self.round_number - 1] def check_correct(self): self.is_correct = (self.submitted_answer == self.solution) self.orig_grading = self.is_correct self.fn_grading = self.orig_grading def get_random_questions(self): rand = random.sample(range(1, Constants.num_rounds), 3) print('rand', rand) rand1 = rand[0] rand2 = rand[1] rand3 = rand[2] print('rand1', rand1) print('rand2', rand2) print('rand3', rand3) p1 = self.in_round(rand1) randnum1 = random.random() if p1.is_correct is True: p1.orig_grading = bool(randnum1 < 1/3) else: p1.orig_grading = bool(randnum1 < 1/3) p1.fn_grading = p1.orig_grading print('p1', p1) print('randnum1', randnum1) print('p1 is correct', p1.is_correct) print('p1_orig_grading', p1.orig_grading) p2 = self.in_round(rand2) randnum2 = random.random() if p2.is_correct is True: p2.orig_grading = bool(randnum2 < 1/3) else: p2.orig_grading = bool(randnum2 < 1/3) p2.fn_grading = p2.orig_grading print('p2', p2) print('randnum2', randnum2) print('p2 is correct', p2.is_correct) print('p2_orig_grading', p2.orig_grading) p3 = self.in_round(rand3) randnum3 = random.random() if p3.is_correct is True: p3.orig_grading = bool(randnum3 < 1/3) else: p3.orig_grading = bool(randnum3 < 1/3) p3.fn_grading = p3.orig_grading print('p3', p3) print('randnum3', randnum3) print('p3 is correct', p3.is_correct) print('p3_orig_grading', p3.orig_grading) def set_orig_payoff(self): if self.num_correct <= 5: bonus = 0 elif self.num_correct <= 10: bonus = 2 elif self.num_correct <= 15: bonus = 4 else: bonus = 6 payoff = 0.5 * self.num_correct comp = payoff + bonus return payoff, bonus, comp rand_scenario = models.IntegerField() request = models.BooleanField() cost = models.CurrencyField() fn_correct = models.IntegerField() fn_payoff = models.CurrencyField(min=c(0.00)) fn_bonus = models.CurrencyField(min=c(0.00)) fn_extra = models.CurrencyField(min=c(0.00), max=c(1.00)) pick = models.IntegerField() pick_correct = models.BooleanField() prior_guess_bonus1 = models.CurrencyField(min=c(0.00)) prior_guess_bonus2 = models.CurrencyField(min=c(0.00)) post_guess_bonus1 = models.CurrencyField(min=c(0.00)) post_guess_bonus2 = models.CurrencyField(min=c(0.00)) rand_guess = models.IntegerField() guess_bonus = models.CurrencyField(min=c(0.00)) def get_random_scenario(self): scenarios = [self.s0, self.s1, self.s2, self.s3, self.s4, self.s5, self.s6, self.s7, self.s8, self.s9] rand_scenario = random.randint(0, 9) self.rand_scenario = rand_scenario request = scenarios[rand_scenario] self.request = request self.session.vars['request'] = self.request cost = Constants.costs[rand_scenario] self.cost = cost print('rand scenario', rand_scenario) print('request', request) print('sessionvar_request_app1', self.session.vars['request']) print('cost', self.cost) # Regrade results: if request is True: for i in range(1, Constants.num_rounds): self.in_round(i).fn_grading = self.in_round(i).is_correct else: self.fn_grading = self.orig_grading def get_guess_bonus(self): player_in_all_rounds = self.in_all_rounds() orig_correct = sum([p.orig_grading for p in player_in_all_rounds]) fn_correct = sum([p.fn_grading for p in player_in_all_rounds]) self.fn_correct = fn_correct answers_correct = sum([p.is_correct for p in player_in_all_rounds]) self.session.vars['orig_correct'] = sum([p.orig_grading for p in player_in_all_rounds]) self.session.vars['fn_correct'] = sum([p.fn_grading for p in player_in_all_rounds]) self.session.vars['answers_correct'] = sum([p.is_correct for p in player_in_all_rounds]) print('orig_correct', orig_correct) print('fn_correct', fn_correct) print('answers_correct', answers_correct) print('sessionvar_orig_correct_app1', self.session.vars['orig_correct'] ) print('sessionvar_fn_correct_app1', self.session.vars['fn_correct']) print('sessionvar_answers_correct_app1', self.session.vars['answers_correct']) # 1. Participant Guess (Prior): ## 1) number of correct answers: self.session.vars['prior_num_guess'] = self.prior_num_guess print('sessionvar_prior_num_guess_app1', self.session.vars['prior_num_guess']) if abs(self.prior_num_guess - answers_correct) <= 3: prior_guess_bonus1 = Constants.bonus - Constants.beta * (self.prior_num_guess - answers_correct)**2 else: prior_guess_bonus1 = 0 ## 2) Probability of the actual event: prior_prob1 = self.prior_prob_guess1 / 100 prior_prob2 = self.prior_prob_guess2 / 100 prior_prob3 = self.prior_prob_guess3 / 100 prior_prob4 = self.prior_prob_guess4 / 100 prior_prob5 = self.prior_prob_guess5 / 100 prior_probs = [prior_prob1, prior_prob2, prior_prob3, prior_prob4, prior_prob5] print('prior_probs', prior_probs) if answers_correct <= self.prior_num_guess - 5: prior_guess_bonus2 = 5 * (1-((prior_prob1 - 1)**2)) self.prior_prob_true = self.prior_prob_guess1 elif answers_correct >= self.prior_num_guess - 4 and answers_correct <= self.prior_num_guess - 2: prior_guess_bonus2 = 5 * (1 - ((prior_prob2 - 1) ** 2)) self.prior_prob_true = self.prior_prob_guess2 elif answers_correct >= self.prior_num_guess - 1 and answers_correct <= self.prior_num_guess + 1: prior_guess_bonus2 = 5 * (1 - ((prior_prob3 - 1) ** 2)) self.prior_prob_true = self.prior_prob_guess3 elif answers_correct >= self.prior_num_guess + 2 and answers_correct <= self.prior_num_guess + 4: prior_guess_bonus2 = 5 * (1 - ((prior_prob4 - 1) ** 2)) self.prior_prob_true = self.prior_prob_guess4 else: prior_guess_bonus2 = 5 * (1 - ((prior_prob5 - 1) ** 2)) self.prior_prob_true = self.prior_prob_guess5 self.session.vars['prior_prob_true'] = self.prior_prob_true print('sessionvar_prior_prob_true_app1', self.session.vars['prior_prob_true']) self.prior_guess_bonus1 = prior_guess_bonus1 self.prior_guess_bonus2 = prior_guess_bonus2 print('prior_guess_bonus1', prior_guess_bonus1) print('prior_guess_bonus2', prior_guess_bonus2) self.session.vars['prior_bonus1'] = self.prior_guess_bonus1 self.session.vars['prior_bonus2'] = self.prior_guess_bonus2 print('sessionvar_prior_bonus1_app1', self.session.vars['prior_bonus1']) print('sessionvar_prior_bonus2_app1', self.session.vars['prior_bonus2']) # 2. Participant Guess (Posterior): ## 1) number of correct answers: self.session.vars['post_num_guess'] = self.post_num_guess if abs(self.post_num_guess - answers_correct) <= 3: post_guess_bonus1 = Constants.bonus - Constants.beta * (self.post_num_guess - answers_correct)**2 else: post_guess_bonus1 = 0 ## 2) Probability of the actual event: possible0 = sum([p.orig_grading for p in player_in_all_rounds]) - 3 possible1 = sum([p.orig_grading for p in player_in_all_rounds]) - 2 possible2 = sum([p.orig_grading for p in player_in_all_rounds]) - 1 possible3 = sum([p.orig_grading for p in player_in_all_rounds]) - 0 possible4 = sum([p.orig_grading for p in player_in_all_rounds]) + 1 possible5 = sum([p.orig_grading for p in player_in_all_rounds]) + 2 possible6 = sum([p.orig_grading for p in player_in_all_rounds]) + 3 possibles = [possible0, possible1, possible2, possible3, possible4, possible5, possible6] print('possibles', possibles) post_prob0 = self.post_prob_guess0 / 100 post_prob1 = self.post_prob_guess1 / 100 post_prob2 = self.post_prob_guess2 / 100 post_prob3 = self.post_prob_guess3 / 100 post_prob4 = self.post_prob_guess4 / 100 post_prob5 = self.post_prob_guess5 / 100 post_prob6 = self.post_prob_guess6 / 100 post_probs = [post_prob0, post_prob1, post_prob2, post_prob3, post_prob4, post_prob5, post_prob6] print('post_probs', post_probs) if possible0 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob0 - 1) ** 2)) self.post_prob_true = self.post_prob_guess0 elif possible1 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob1 - 1) ** 2)) self.post_prob_true = self.post_prob_guess1 elif possible2 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob2 - 1) ** 2)) self.post_prob_true = self.post_prob_guess2 elif possible3 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob3 - 1) ** 2)) self.post_prob_true = self.post_prob_guess3 elif possible4 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob4 - 1) ** 2)) self.post_prob_true = self.post_prob_guess4 elif possible5 == answers_correct: post_guess_bonus2 = 5 * (1 - ((post_prob5 - 1) ** 2)) self.post_prob_true = self.post_prob_guess5 else: post_guess_bonus2 = 5 * (1 - ((post_prob6 - 1) ** 2)) self.post_prob_true = self.post_prob_guess6 self.session.vars['post_prob_true'] = self.post_prob_true print('sessionvar_post_prob_true_app1', self.session.vars['post_prob_true']) print('answer_correct', answers_correct) print('possibles_0', possibles[0]) print('post_prob_0', post_probs[0]) print('possibles_1', possibles[1]) print('post_prob_1', post_probs[1]) print('possibles_2', possibles[2]) print('post_prob_2', post_probs[2]) print('possibles_3', possibles[3]) print('post_prob_3', post_probs[3]) print('possibles_4', possibles[4]) print('post_prob_4', post_probs[4]) print('possibles_5', possibles[5]) print('post_prob_5', post_probs[5]) print('possibles_6', possibles[6]) print('post_prob_6', post_probs[6]) self.post_guess_bonus1 = post_guess_bonus1 self.post_guess_bonus2 = post_guess_bonus2 print('post_guess_bonus1', post_guess_bonus1) print('post_guess_bonus2', post_guess_bonus2) self.session.vars['post_bonus1'] = self.post_guess_bonus1 self.session.vars['post_bonus2'] = self.post_guess_bonus2 print('sessionvar_post_bonus1_app1', self.session.vars['post_bonus1']) print('sessionvar_post_bonus2_app1', self.session.vars['post_bonus2']) self.rand_guess = random.randint(1, 4) if self.rand_guess == 1: self.guess_bonus = self.prior_guess_bonus1 elif self.rand_guess == 2: self.guess_bonus = self.prior_guess_bonus2 elif self.rand_guess == 3: self.guess_bonus = self.post_guess_bonus1 else: self.guess_bonus = self.post_guess_bonus2 print('rand_guess', self.rand_guess) print('guess_bonus', self.guess_bonus) self.session.vars['rand_guess'] = self.rand_guess self.session.vars['guess_bonus'] = self.guess_bonus print('sessionvar_rand_guess_app1', self.session.vars['rand_guess']) print('sessionvar_guess_bonus_app1', self.session.vars['guess_bonus']) def set_fn_payoff(self): player_in_all_rounds = self.in_all_rounds() answers_correct = sum([p.is_correct for p in player_in_all_rounds]) print('answers_correct', answers_correct) fn_correct = sum([p.fn_grading for p in player_in_all_rounds]) print('fn_correct', fn_correct) if fn_correct <= 5: self.fn_bonus = 0 elif fn_correct <= 10: self.fn_bonus = 2 elif fn_correct <= 15: self.fn_bonus = 4 else: self.fn_bonus = 6 if self.request is True: self.regrade_cost = self.cost else: self.regrade_cost = 0 self.session.vars['cost'] = self.cost self.session.vars['regrade_cost'] = self.regrade_cost print('sessionvar_cost_app1', self.session.vars['cost']) print('sessionvar_regradecost_app1', self.session.vars['regrade_cost']) self.fn_payoff = 0.5 * fn_correct pick = random.randint(1, Constants.num_rounds) self.pick = pick self.session.vars['pick'] = pick if self.in_round(pick).is_correct is True: self.session.vars['pick_correct'] = True self.pick_correct = True self.session.vars['fn_extra'] = 1-((self.in_round(pick).probability/100 - 1) ** 2) self.fn_extra = 1-((self.in_round(pick).probability/100 - 1) ** 2) else: self.session.vars['pick_correct'] = False self.pick_correct = True self.session.vars['fn_extra'] = 1 - ((self.in_round(pick).probability/100 - 0) ** 2) self.fn_extra = 1 - ((self.in_round(pick).probability / 100 - 0) ** 2) self.session.vars['fn_payoff'] = 0.5 * fn_correct self.session.vars['fn_bonus'] = self.fn_bonus self.session.vars['probability'] = self.in_round(pick).probability self.session.vars['rand_correct'] = self.in_round(pick).is_correct print('pick', pick) print('probability', self.in_round(pick).probability) print('session_var_extra', self.session.vars['fn_extra']) print('fn_correct', fn_correct) print('fn_payoff', self.fn_payoff) print('fn_bonus', self.fn_bonus) print('session_var_fn_payoff_app1', self.session.vars['fn_payoff']) print('session_var_fn_bonus_app1', self.session.vars['fn_bonus']) def set_payoff(self): print('regrade_cost', self.regrade_cost) print('prior bonus1', self.prior_guess_bonus1) print('prior bonus2', self.prior_guess_bonus2) print('post bonus1', self.post_guess_bonus1) print('post bonus2', self.post_guess_bonus2) print('guess_bonus', self.guess_bonus) print('lottery_draw', self.lottery_draw) print('lottery_choice', self.in_round(1).lottery_choice) print('lottery_bonus', self.in_round(1).lottery_bonus) print('total_payoff', self.total_payoff) self.total_payoff = self.fn_payoff + self.fn_bonus + self.session.vars['fn_extra'] \ + self.regrade_cost \ + self.guess_bonus \ + self.in_round(1).lottery_bonus + Constants.guaranty self.session.vars['total_payoff'] = self.total_payoff