from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import csv author = 'Your name here' doc = """ Your app description """ class Constants(BaseConstants): import csv, io name_in_url = 'bangla_st0_BNG_tr3_t1' players_per_group = 10 # E X P E R I M E N T _ P A R A M E T E R S test_round = 1 # # # # # # # # # treatment = 3 #credit det. = 1; eq det. = 2; credit uncert = 3; eq uncert = 4 # # # # # # # # # start_endowment = 100 # # # # # # # # # B = 1000 # # # # # # # # # D = 100 # # # # # # # # # r = 0.1 # # # # # # # # # s= 0.3 # # # # # # # # # points_conversion_rate = 0.03 # # # # # # # # # part_reward = 500 # # # # # # # # # #number of questions #Todo: Read this from some config file! num_rounds = 10 num_questions_module = int(num_rounds / 2) do_backups = True # Load question pool with io.open('bangla_st0/190914_questions.csv', "r", encoding='utf-8-sig') as questions_file: questions = list(csv.DictReader(questions_file)) class Subsession(BaseSubsession): def before_session_starts(self): # Transfer important constants to session vars to keep constant across apps self.session.vars['treatment'] = Constants.treatment self.session.vars['B'] = Constants.B self.session.vars['D'] = Constants.D self.session.vars['r'] = Constants.r self.session.vars['s'] = Constants.s self.session.vars['test_round'] = Constants.test_round self.session.vars['points_conversion_rate'] = Constants.points_conversion_rate self.session.vars['part_reward'] = Constants.part_reward #self.session.vars['task_number_questions'] = Constants.task_number_questions for p in self.get_players(): p.treatment = self.session.vars['treatment'] p.test_round = self.session.vars['test_round'] p.B = self.session.vars['B'] p.D = self.session.vars['D'] p.s = self.session.vars['s'] p.r = self.session.vars['r'] p.conversion_rate = self.session.vars['points_conversion_rate'] self.session.vars['megaRound'] = 0 self.session.vars['do_backups'] = Constants.do_backups for p in self.get_players(): p.participant.vars['score'] = Constants.start_endowment #Todo: Explicitly write to record: EXTERNAL session code, treatment (take from config) for p in self.get_players(): p.participant.vars['ability1'] = None p.participant.vars['ability2'] = None def creating_session(self): if self.round_number == 1: self.session.vars['questions'] = Constants.questions.copy() import random type1_questions = [q for q in Constants.questions if q['type'] == '1'] type2_questions = [q for q in Constants.questions if q['type'] == '2'] random.shuffle(type1_questions) random.shuffle(type2_questions) randomized_questions1 = random.sample(type1_questions, Constants.num_questions_module ) randomized_questions2 = random.sample(type2_questions, Constants.num_questions_module ) #print(randomized_questions2) self.session.vars['questions1'] = randomized_questions1 self.session.vars['questions2'] = randomized_questions2 #print(self.session.vars['questions1']) #print(self.session.vars['questions2']) # 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(): #print("Test") question_data = p.current_question() p.question_id = int(question_data['id']) p.question = question_data['question'] p.solution = question_data['solution'] p.qtype = int(question_data['type']) p.qsubtype = int(question_data['subtype']) def migrate_to_session(self): # move all relevant subsession variables to the session level to keep info on app switch #print('[MAIN]\t\tMigrating App0 variables') # ! # ! # ! # Participant/session vars are not recorded and lost after end of the experiod! # SUBSESSION -> SESSION #None for now # PLAYER -> PARTICIPANT for p in self.get_players(): # abilities this_ab1, this_ab2 = p.get_ability() p.participant.vars['ability1'] = this_ab1 p.participant.vars['ability2'] = this_ab2 def migrate_understanding(self): for p in self.get_players(): p.participant.vars['understand_answer_1'] = p.understand_answer_1 p.participant.vars['understand_answer_2'] = p.understand_answer_2 p.participant.vars['understand_answer_3'] = p.understand_answer_3 p.participant.vars['understand_answer_4'] = p.understand_answer_4 p.participant.vars['understand_answer_5'] = p.understand_answer_5 def migrate_participant(self): for p in self.get_players(): p.participant.vars['part_code'] = p.part_code p.participant.vars['part_age'] = p.part_age p.participant.vars['part_gender'] = p.part_gender p.participant.vars['part_occup'] = p.part_occup p.participant.vars['part_share_free'] = p.part_share_free def back_up(self): if self.session.vars['do_backups'] == False: return None import smtplib, ssl, time, json this_savepoint_id = 'svpt0001' # title_row = [ 'timestamp', 'player_uid', 'part_otree_id', 'this_app'] # 'CONT_ranking_submitted'] #Todo: Include: global round, sessionID, treatment, player_cash save_data = [] for p in self.get_players(): this_row = [] # save metadata: date, player uid, player otree id, this_app this_row.append( time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) ) # this_row.append(p.uid) this_row.append( p.participant.id_in_session ) this_row.append( p.participant.code ) this_row.append('app0_assessment') # save content: this_row.append([ p.participant.vars['ability1'], p.participant.vars['ability2'], # p.understand_answer_1, # p.understand_answer_2, # p.understand_answer_3, # p.understand_answer_4, # p.understand_answer_5, p.part_code , p.part_age, p.part_gender, p.part_occup , p.part_income , p.part_share_free, p.part_jobs_attempt, p.part_jobs_complete , ]) save_data.append(this_row) save_data.append([ self.session.vars['questions1'], self.session.vars['questions2'], self.session.vars['megaRound'] ]) try: this_dat = json.dumps(save_data) message = str(this_savepoint_id) + "\n " + this_dat from_address = "bangladeshi.experimentor@gmail.com" password = "YcDjgzQv44JD9a6R" context = ssl.create_default_context() with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server: server.login(from_address, password) server.sendmail( from_address, "bangladeshi.experimentor@gmail.com", message) except: print("ERR message not sent") #Todo: Record how answered each question? class Group(BaseGroup): pass class Player(BasePlayer): question_id = models.IntegerField() question = models.StringField() solution = models.StringField() qtype = models.IntegerField() qsubtype = models.IntegerField() submitted_answer = models.StringField(widget=widgets.RadioSelect) is_correct = models.BooleanField() ability1 = models.FloatField() ability2 = models.FloatField() part_code = models.IntegerField() part_age = models.IntegerField() part_gender = models.IntegerField( choices=[ [1, 'Male'], [2, 'Female'],]) part_income = models.FloatField() part_occup = models.StringField() part_share_free = models.IntegerField() part_jobs_attempt = models.IntegerField() part_jobs_complete = models.IntegerField() part_risk_quest = models.FloatField(min=0, max=100) actual_endowment = models.IntegerField() treatment = models.FloatField() test_round = models.FloatField() B = models.FloatField() D = models.FloatField() s = models.FloatField() r = models.FloatField() conversion_rate = models.FloatField() def submitted_answer_choices(self): qd = self.current_question() if int(qd['type']) == 1 and int(qd['subtype']) in [1,] : return [ qd['choice1'], qd['choice2'], qd['choice3'], ] elif int(qd['type']) == 1 and int(qd['subtype']) in [2,] : return [ qd['choice1'], qd['choice2'], qd['choice3'], ] elif int(qd['type']) == 2 and int(qd['subtype']) in [1,] : return [ qd['choice1'], qd['choice2'], ] elif int(qd['type']) == 2 and int(qd['subtype']) in [2,]: return [ qd['choice1'], qd['choice2'], qd['choice3'], qd['choice4'], ] def current_question(self): if self.round_number <= Constants.num_questions_module: return self.session.vars['questions1'][self.round_number - 1] #print(self.session.vars['questions1'], self.round_number) else: return self.session.vars['questions2'][self.round_number - 1 - Constants.num_questions_module] #print(self.session.vars['questions1'], self.round_number - Constants.num_questions_module) def check_correct(self): self.is_correct = (self.submitted_answer == self.solution) def get_ability(self): player_in_all_rounds = self.in_all_rounds() # print( [p.is_correct for p in player_in_all_rounds if int(p.qtype) == 1] ) self.ability1 = sum([p.is_correct for p in player_in_all_rounds if int(p.qtype) == 1]) self.ability2 = sum([p.is_correct for p in player_in_all_rounds if int(p.qtype) == 2]) self.ability1 = round( self.ability1 / Constants.num_rounds * 2 ,ndigits=2 ) self.ability2 = round( self.ability2 / Constants.num_rounds * 2 ,ndigits=2 ) return self.ability1, self.ability2 def calculate_endowment(self): import random a = random.randint(1,2) if a == 1: self.actual_endowment = int( round( 2.5*(self.part_risk_quest/100) * Constants.start_endowment + (1 - self.part_risk_quest/100)*Constants.start_endowment, 0 )) elif a == 2: self.actual_endowment = int( round( (1 - self.part_risk_quest/100)*Constants.start_endowment, 0 )) self.participant.vars['actual_endowment'] = self.actual_endowment self.participant.vars['score'] = max(0, self.actual_endowment )