from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random as random import math as math import itertools import json as json import pandas as pd author = 'Your name here' doc = """Subs can only work on the math task""" def load_pwd_tasks(type='LinearDifficulty'): with open(f'AbilityCode/static/Code_{type}/counting_tasks.json', 'r') as read_file: task_list = json.load(read_file) return task_list def make_math_field(): return models.IntegerField( widget=widgets.RadioSelect, blank=True, label='', ) def make_pwd_ability_field(): return models.IntegerField( blank=True, label='', ) class Constants(BaseConstants): name_in_url = '0h254gdG2aBa' players_per_group = None num_rounds = 8 num_participants = 10 timeout = 40 # Payoff Constants payoff_incorrect = c(0) pwd_rate = 10 pwd_piecerate = c(pwd_rate) time_rate = 5 time_piecerate = c(time_rate) example_time = 32 task = 'Codes' production_profile = ['Convex']#['Linear','Convex'] num_pwd_tasks = 10 # Load tasks # Load math tasks linear_task = load_pwd_tasks(type='LinearDifficulty') convex_task = load_pwd_tasks(type='DecreasingDifficulty') class Subsession(BaseSubsession): def creating_session(self): ##### This code is for obtaining a balanced session ############ task_profiles = Constants.production_profile.copy() # shuffle the list random.shuffle(task_profiles) # make a cycle out of the shuffled list profiles = itertools.cycle(task_profiles) for p in self.get_players(): if self.round_number == 1: p.participant.vars['pwd_piecerate'] = Constants.pwd_piecerate p.participant.vars['production_profile'] = next(profiles) # fixed on subject and session level p.task_option_this_round = (self.round_number - 1) p.task = Constants.task p.production_profile = p.participant.vars['production_profile'] class Group(BaseGroup): pass class Player(BasePlayer): # Selected Task task = models.StringField() # Production profile production_profile = models.StringField() ### Cumulated Time needed for one math task ################ pwd_1_time = models.FloatField(blank=True) pwd_2_time = models.FloatField(blank=True) pwd_3_time = models.FloatField(blank=True) pwd_4_time = models.FloatField(blank=True) pwd_5_time = models.FloatField(blank=True) pwd_6_time = models.FloatField(blank=True) pwd_7_time = models.FloatField(blank=True) pwd_8_time = models.FloatField(blank=True) pwd_9_time = models.FloatField(blank=True) pwd_10_time = models.FloatField(blank=True) pwd_1 = make_pwd_ability_field() pwd_2 = make_pwd_ability_field() pwd_3 = make_pwd_ability_field() pwd_4 = make_pwd_ability_field() pwd_5 = make_pwd_ability_field() pwd_6 = make_pwd_ability_field() pwd_7 = make_pwd_ability_field() pwd_8 = make_pwd_ability_field() pwd_9 = make_pwd_ability_field() pwd_10 = make_pwd_ability_field() # Check correct answers pwd_correct = models.IntegerField(initial=0) # Number of tries pwd_1_tries = models.IntegerField(blank=True) pwd_2_tries = models.IntegerField(blank=True) pwd_3_tries = models.IntegerField(blank=True) pwd_4_tries = models.IntegerField(blank=True) pwd_5_tries = models.IntegerField(blank=True) pwd_6_tries = models.IntegerField(blank=True) pwd_7_tries = models.IntegerField(blank=True) pwd_8_tries = models.IntegerField(blank=True) pwd_9_tries = models.IntegerField(blank=True) pwd_10_tries = models.IntegerField(blank=True) # Number of toggles pwd_1_toggles = models.IntegerField(blank=True) pwd_2_toggles = models.IntegerField(blank=True) pwd_3_toggles = models.IntegerField(blank=True) pwd_4_toggles = models.IntegerField(blank=True) pwd_5_toggles = models.IntegerField(blank=True) pwd_6_toggles = models.IntegerField(blank=True) pwd_7_toggles = models.IntegerField(blank=True) pwd_8_toggles = models.IntegerField(blank=True) pwd_9_toggles = models.IntegerField(blank=True) pwd_10_toggles = models.IntegerField(blank=True) # Timer timer_task1 = models.FloatField() new_timer_task1 = models.FloatField() pwd_time = models.FloatField() total_time = models.FloatField() # Time spent Code_Instructions_time_spent = models.FloatField(blank=True) CodeTask_time_spent = models.FloatField(blank=True) # Warnings Code_Instructions_warnings = models.IntegerField() CodeTask_warnings = models.IntegerField() StartRound_warnings = models.IntegerField() # Selected Task task_option_this_round = models.IntegerField() payoff_pwd = models.CurrencyField() payoff_time = models.CurrencyField() def set_payoff(self): if self.production_profile == 'Linear': solutions = Constants.linear_task[self.task_option_this_round][0] elif self.production_profile == 'Convex': solutions = Constants.convex_task[self.task_option_this_round][0] answers = [ self.pwd_1, self.pwd_2, self.pwd_3, self.pwd_4, self.pwd_5, self.pwd_6, self.pwd_7, self.pwd_8, self.pwd_9, self.pwd_10, ] self.pwd_correct = sum([1 for x,y in zip(answers,solutions) if x == y]) self.payoff_pwd = self.pwd_correct * Constants.pwd_piecerate # Also give money for the time finished earlier # This code is robust to: # a) recorded time being not in the range (0,Timeout) # b) Participants proceeds by error/hacking and gets time bonus without completing all tasks if self.pwd_10_time != None and self.pwd_10_time < Constants.timeout and self.pwd_10_time > 0 and self.pwd_correct == Constants.num_pwd_tasks: self.payoff_time = (Constants.timeout - math.ceil(self.pwd_10_time)) * Constants.time_piecerate else: self.payoff_time = 0 * Constants.time_piecerate self.payoff = self.payoff_pwd + self.payoff_time # Put it into the ether self.participant.vars[f'pwd_ability_round_{self.round_number}'] = self.pwd_correct self.participant.vars[f'pwd_ability_payoff_round_{self.round_number}'] = self.payoff def save_data(self): p_vars = self.participant.vars if self.round_number == 1: p_vars[f'pwd_t_1'] = [] p_vars[f'pwd_t_2'] = [] p_vars[f'pwd_t_3'] = [] p_vars[f'pwd_t_4'] = [] p_vars[f'pwd_t_5'] = [] p_vars[f'pwd_t_6'] = [] p_vars[f'pwd_t_7'] = [] p_vars[f'pwd_t_8'] = [] p_vars[f'pwd_t_9'] = [] p_vars[f'pwd_t_10'] = [] elif self.round_number == Constants.num_rounds: p_vars['num_pwd_tasks_pwd_ability'] = Constants.num_pwd_tasks p_vars['num_rounds_pwd_ability'] = Constants.num_rounds else: pass # Put it into the ether p_vars[f'pwd_t_1'].append(self.pwd_1_time) p_vars[f'pwd_t_2'].append(self.pwd_2_time) p_vars[f'pwd_t_3'].append(self.pwd_3_time) p_vars[f'pwd_t_4'].append(self.pwd_4_time) p_vars[f'pwd_t_5'].append(self.pwd_5_time) p_vars[f'pwd_t_6'].append(self.pwd_6_time) p_vars[f'pwd_t_7'].append(self.pwd_7_time) p_vars[f'pwd_t_8'].append(self.pwd_8_time) p_vars[f'pwd_t_9'].append(self.pwd_9_time) p_vars[f'pwd_t_10'].append(self.pwd_10_time)