from otree.api import Currency as c, currency_range from . import models from ._builtin import Page, WaitPage from .models import Constants from otreeutils.pages import AllGroupsWaitPage, ExtendedPage, UnderstandingQuestionsPage, APPS_DEBUG import time import settings import numpy as np import boto3 def vars_for_all_templates(self): matrix_rep = self.session.config.get('matrix',True) ## read games to be played from the session config quiz_attempts = self.session.config.get('quiz_attempts', 0) quiz_minutes = self.session.config.get('quiz_minutes', 3) raffle_bonus = self.session.config.get('raffle_bonus', 0) quiz_payment = self.session.config.get('quiz_payment', 2) participation_fee = self.session.config.get('participation_fee', 0) termination_prob = round((1 - self.session.config.get('continuation_prob', 0.9))*1000)/10 if termination_prob == 1: termination_prob = 1 return { 'matrix_rep': matrix_rep, 'quiz_attempts': quiz_attempts, 'quiz_minutes': quiz_minutes, 'quiz_payment': quiz_payment, 'raffle_bonus': raffle_bonus, 'points100' : self.session.config.get('real_world_currency_per_point', 1)*100, 'exchange_rate': c(int(round(1 / self.session.config['real_world_currency_per_point']))), 'participation_fee': participation_fee, 'termination_prob': termination_prob, 'experimental_currency': getattr(settings, 'POINTS_CUSTOM_NAME', 'tokens'), 'real_currency': getattr(settings, 'REAL_WORLD_CURRENCY_CODE', '$') } class Instructions(Page): timeout_seconds = 600 def is_displayed(self): pmats = self.session.config.get('pmats',[]) self.player.pmat = pmats if isinstance(pmats,str) else 'ex' return (not self.participant.vars.get('finished',0)) #and (not self.session.config['debug']) def before_next_page(self): self.participant.vars['decision_start_time'] = time.time() def vars_for_template(self): ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[self.player.pmat] return { 'P11': P11, 'P12': P12, 'P21': P21, 'P22': P22, 'P11o': P11o, 'P12o': P12o, 'P21o': P21o, 'P22o': P22o, } class SomeUnderstandingQuestions(UnderstandingQuestionsPage): page_title = '' extra_info = Constants.instructions_template quiz_info = Constants.quiz_info set_correct_answers = True # this is the default setting # set_correct_answers = False # do not fill out the correct answers in advance (this is for fast skipping through pages) form_model = 'player' form_field_n_wrong_attempts = 'wrong_attempts' live_method = 'live_attempt' def get_timeout_seconds(self): return self.session.config.get('quiz_minutes', 5)*60 def get_questions(self): ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[self.player.pmat] possible_payoffs = list(set([P11, P12, P21, P22, P11o, P12o, P21o, P22o])) questions = [ { 'question': "What is your payoff if you choose Y and the other participant chooses Y?", 'options': possible_payoffs, 'correct': P11, }, { 'question': "What is the other participant's payoff if you choose Y and the other participant chooses W?", 'options': possible_payoffs, 'correct': P21o, }, { 'question': "What is your payoff if you choose W and the other participant chooses Y?", 'options': possible_payoffs, 'correct': P21, }, { 'question': "What is the other participant's payoff if you choose W and the other participant chooses W?", 'options': possible_payoffs, 'correct': P22o, }, # { # 'question': "What is the other participant's payoff if you choose W and the other participant chooses W?", # 'options': possible_payoffs, # 'correct': P22o, # }, # { # 'question': "What is the other participant's payoff if you choose Y and the other chooses W?", # 'options': possible_payoffs, # 'correct': P21o, # }, # { # 'question': 'What is the smallest possible number of rounds in the interaction?', # 'options': ['1','3','9','10','99'], # 'correct': '1', # }, ] # own max payoff options = ['I choose Y, the other chooses Y', 'I choose Y, the other chooses W', 'I choose W, the other chooses Y', 'I choose W, the other chooses W', ] payoffs1 = np.array([P11, P12, P21, P22]) payoffs2 = np.array([P11o, P21o, P12o, P22o]) payoffs = payoffs1 + payoffs2 # print(options,payoffs1,payoffs2,payoffs) # print(payoffs1.argmax(),payoffs2.argmax(),payoffs.argmax()) # print(type(options[payoffs2.argmax()])) if np.sum(payoffs1 == payoffs1.max()) == 1: questions.extend([ { 'question': "When do you receive the highest possible payoff?", 'options': options, 'correct': options[payoffs1.argmax()], }, ]) # other max payoff if np.sum(payoffs2 == payoffs2.max()) == 1: questions.extend([ { 'question': "When does the other participant receive the highest possible payoff?", 'options': options, 'correct': options[payoffs2.argmax()], }, ]) # joint max payoff if np.sum(payoffs == payoffs.max()) == 1: questions.extend([ { 'question': "When do the two of you receive the highest joint payoff?", 'options': options, 'correct': options[payoffs.argmax()], }, ]) continuation_prob = self.session.config.get('continuation_prob', 0.99) if continuation_prob == 0.99: questions.extend([ # { # 'question': "The interaction is currently in round 53 and you have correctly guessed the other participant's choice 27 times. How many raffle tickets have you earned in this match?", # 'options': ['10','27','47','53','63'], # 'correct': '27', # }, { 'question': 'Suppose the interaction is currently in round 53, what is the chance that the interaction will end after this round?', 'options': ['1%','10%','47%','53%','90%','99%'], 'correct': '1%', }, { 'question': 'Suppose the interaction is currently in round 71, what is the chance that the interaction will end after this round?', 'options': ['1%','10%','47%','53%','90%','99%'], 'correct': '1%', }, ]) elif continuation_prob == 0.995: questions.extend([ # { # 'question': "The interaction is currently in round 113 and you have correctly guessed the other participant's choice 53 times. How many raffle tickets have you earned in this interaction?", # 'options': ['5','27','47','53','113'], # 'correct': '53', # }, { 'question': 'Suppose the interaction is currently in round 98, what is the chance that the interaction will end after this round?', 'options': ['0.5%','1%','5%','50%','95%','99.5%'], 'correct': '%.1f'%((1 - continuation_prob)*100)+'%', }, { 'question': 'Suppose the interaction is currently in round 162, what is the chance that the interaction will end after this round?', 'options': ['0.5%','1%','5%','50%','95%','99.5%'], 'correct': '%.1f'%((1 - continuation_prob)*100)+'%', }, ]) return questions def before_next_page(self): ## the variable matched is used to determine whether the participant will play a one-shot game ## in case matching is not reached if not self.timeout_happened: quiz_attempts = self.session.config.get('quiz_attempts', 0) self.player.qualified = (quiz_attempts==0)or(self.player.wrong_attempts < quiz_attempts) if self.player.qualified: self.participant.vars['qualified'] = 1 # quiz_payment = self.session.config.get('quiz_payment', 0) # self.player.payoff = quiz_payment/self.session.config['real_world_currency_per_point'] # if qualified, grant qualification 4 -- successfully completed the experiment # In case not matched (1) or dropout (2 or 3), reset the value later if not self.session.config.get('debug', False): access_key_id = self.session.config['access_key_id'] secret_access_key = self.session.config['secret_access_key'] if self.session.config.get('sandbox', False): # sandbox Qid = self.session.config['Qid_sandbox'] mturk = boto3.client( service_name='mturk', aws_access_key_id=access_key_id, aws_secret_access_key=secret_access_key, region_name='us-east-1', endpoint_url="https://mturk-requester-sandbox.us-east-1.amazonaws.com", ) else: # live production Qid = self.session.config['Qid'] mturk = boto3.client( service_name='mturk', aws_access_key_id=access_key_id, aws_secret_access_key=secret_access_key, region_name='us-east-1', ) try: mturk.associate_qualification_with_worker( QualificationTypeId=Qid, WorkerId=self.participant.label, IntegerValue=4, SendNotification=False ) print('qualification 4 granted for player ', self.participant.id_in_session) except Exception as e: print(e) if not self.player.qualified: self.participant.vars['finished'] = 1 ## indicator whether the game should end -- occurs if one or one's partners drop out self.player.decision_time = round((time.time() - self.participant.vars['decision_start_time'])) def is_displayed(self): return (not self.participant.vars.get('finished',0)) #and (not self.session.config['debug']) def extra_vars_for_template(self): ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[self.player.pmat] return { 'P11': P11, 'P12': P12, 'P21': P21, 'P22': P22, 'P11o': P11o, 'P12o': P12o, 'P21o': P21o, 'P22o': P22o, } class QuizResults(Page): def get_timeout_seconds(self): if self.player.qualified: return 30 else: return None def vars_for_template(self): return { 'qualified': self.player.qualified, 'dropout': self.participant.vars.get('dropout',0), } def before_next_page(self): # time.time() returns the number of seconds passed since epoch (January 1, 1970, 00:00:00) # this variable is used to initialize the countdown in the matching waitpage self.participant.vars['waitpage_arrival_time'] = time.time() self.participant.vars['qualified'] = self.player.qualified # record the number of timeouts. # in the next app, two consecutive timeouts would count as dropouts self.participant.vars['timeout'] = 0 ## number of times one has been timed out page_sequence = [ Instructions, SomeUnderstandingQuestions, QuizResults, ]