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): self.player.distancing = self.session.config.get('distancing',False) self.player.sym = self.session.config.get('symmetric_game',True) self.player.termination = self.session.config.get('voluntary_termination', False) 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): game = 'sym' if self.player.sym else 'asym' ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[game] 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): game = 'sym' if self.player.sym else 'asym' ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[game] possible_payoffs = list(set([P11, P12, P21, P22, P11o, P12o, P21o, P22o])) questions = [ { 'question': "What is your payoff if you choose T and the other participant chooses T?", 'options': possible_payoffs, 'correct': P11, }, { 'question': "What is the other participant's payoff if you choose S and the other participant chooses T?", 'options': possible_payoffs, 'correct': P12o, }, { 'question': "What is your payoff if you choose T and the other participant chooses S?", 'options': possible_payoffs, 'correct': P12, }, { 'question': "What is the other participant's payoff if you choose S and the other participant chooses S?", '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 T, the other chooses T', 'I choose T, the other chooses S', 'I choose S, the other chooses T', 'I choose S, the other chooses S', ] 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()], # }, # ]) if self.player.termination: questions.extend([ { 'question': 'Suppose the interaction is currently in round 53, what is the chance that the interaction will end after this round if no participants choose to terminate the interaction?', '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 if no participants choose to terminate the interaction?', 'options': ['1%','10%','47%','53%','90%','99%'], 'correct': '1%', }, { 'question': 'Which of the following statement is True:', 'options': ['The interaction will terminate only if both players choose to terminate the interaction.', 'If the interaction is terminated, the existing earnings from this interaction will be lost.', 'Either player can choose to terminate the interaction if they are unsatisfied with the behavior of the other player', 'The interaction will terminate if one player choose to terminate and the other player accepts the termination' ], 'correct': 'Either player can choose to terminate the interaction if they are unsatisfied with the behavior of the other player', }, ]) else: questions.extend([ { '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%', }, ]) 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): game = 'sym' if self.player.sym else 'asym' ((P11, P12, P21, P22), (P11o, P12o, P21o, P22o)) = Constants.payoff_matrix[game] 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, ]