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/quiz1.csv') as questions_file: questions = list(csv.DictReader(questions_file)) num_rounds = len(questions) instructions_template = 'my_quiz1/Instructions.html' cost0 = c(4.00) cost1 = c(3.50) cost2 = c(3.00) cost3 = c(2.50) cost4 = c(2.00) cost5 = c(1.50) cost6 = c(1.00) cost7 = c(0.50) cost8 = c(0.00) cost9 = c(-0.50) cost10 = c(-1.00) costs = [cost0, cost1, cost2, cost3, cost4, cost5, cost6, cost7, cost8, cost9, cost10] 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] 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 ## 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 = int(question_data['id']) p.question = question_data['question'] p.solution = question_data['solution'] class Group(BaseGroup): pass class Player(BasePlayer): num_guess = models.IntegerField( min=0, max=20, label='How many questions do you think you answered correctly?' ) prob_guess = models.IntegerField( min=0, max=100, widget=widgets.Slider(attrs={'step': '1'}), label='What do you think the probability (between 0 and 100%) is for the guessed scenario to occur?' ) 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 $4.') s1 = make_field('If you ask for a regrade, you pay $3.5.') s2 = make_field('If you ask for a regrade, you pay $3.') s3 = make_field('If you ask for a regrade, you pay $2.5.') s4 = make_field('If you ask for a regrade, you pay $2.') s5 = make_field('If you ask for a regrade, you pay $1.5.') s6 = make_field('If you ask for a regrade, you pay $1.') s7 = make_field('If you ask for a regrade, you pay $0.5.') s8 = make_field('If you ask for a regrade, you pay $0.') s9 = make_field('If you ask for a regrade, you get paid $0.5.') s10 = make_field('If you ask for a regrade, you get paid $1.') 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() exp_payoff = models.CurrencyField() lottery_bonus = models.CurrencyField() total_payoff = models.CurrencyField() 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 = np.array(random.sample(range(1, Constants.num_rounds), 2)) rand = random.sample(range(1, Constants.num_rounds), 2) print('rand', rand) rand1 = rand[0] rand2 = rand[1] print('rand1', rand1) print('rand2', rand2) p1 = self.in_round(rand1) p1.orig_grading = bool(random.getrandbits(1)) p1.fn_grading = p1.orig_grading print('p1', p1) print('p1 is correct', p1.is_correct) print('p1_orig_grading', p1.orig_grading) p2 = self.in_round(rand2) p2.orig_grading = bool(random.getrandbits(2)) p2.fn_grading = p2.orig_grading print('p2', p2) print('p2 is correct', p2.is_correct) print('p2_orig_grading', p2.orig_grading) 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, self.s10] rand_scenario = random.randint(0, 10) print('rand scenario', rand_scenario) request = scenarios[rand_scenario] print('request', request) cost = Constants.costs[rand_scenario] 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 player_in_all_rounds = self.in_all_rounds() print('request', request) answers_correct = sum([p.is_correct for p in player_in_all_rounds]) fn_correct = sum([p.fn_grading for p in player_in_all_rounds]) print('fn_correct', fn_correct) prob = self.prob_guess/100 print('prob', prob) if self.num_guess == answers_correct: guess_bonus1 = 1 else: guess_bonus1 = 0 guess_bonus2 = 1-(prob - guess_bonus1)**2 print('guess_bonus1', guess_bonus1) print('guess_bonus2',guess_bonus2) bonus = guess_bonus1 + guess_bonus2 print('bonus', bonus) if request is True: if fn_correct <= 5: self.exp_payoff = 0.5 * fn_correct - cost + bonus elif fn_correct <= 10: self.exp_payoff = (0.5 * 5) + 0.75 * (fn_correct - 5) - cost + bonus elif fn_correct <= 15: self.exp_payoff = (0.5 * 5) + 0.75 * (fn_correct - 5) + 2 - cost + bonus else: self.exp_payoff = (0.5 * 5) + (0.75 * 10) + 1 * (fn_correct - 15) + 5 - cost + bonus else: if fn_correct <= 5: self.exp_payoff = 0.5 * fn_correct + bonus elif fn_correct <= 10: self.exp_payoff = (0.5 * 5) + 0.75 * (fn_correct - 5) + bonus elif fn_correct <= 15: self.exp_payoff = (0.5 * 5) + 0.75 * (fn_correct - 5) + 2 + bonus else: self.exp_payoff = (0.5 * 5) + (0.75 * 10) + 1 * (fn_correct - 15) + 5 + bonus if self.exp_payoff < 0: self.exp_payoff = 0 else: self.exp_payoff = self.exp_payoff def get_lottery(self): lottery_draw = bool(random.getrandbits(2)) print('lottery_draw', lottery_draw) if lottery_draw is True: self.lottery_bonus = Constants.lottery1[self.lottery_choice] else: self.lottery_bonus = Constants.lottery0[self.lottery_choice] def set_payoff(self): self.total_payoff = self.exp_payoff + self.lottery_bonus