import itertools import json as json import math as math import random as random import pandas as pd from otree.api import * author = 'Your name here' doc = """Subs can only work on the math task""" def load_math_options(): with open( f'AbilityMath/static/Addition_Increasing_Difficulty/task_list_8_rounds.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_math_ability_field(): return models.IntegerField( blank=True, label='', ) class Constants(BaseConstants): name_in_url = '0hsgW2aBa' players_per_group = None num_rounds = 8 num_participants = 10 timeout = 40 # Payoff Constants payoff_incorrect = cu(0) math_rate = 10 math_piecerate = cu(math_rate) time_rate = 5 time_piecerate = cu(time_rate) example_time = 38 task = 'Addition' num_math_tasks = 10 # Load math tasks addition_task = load_math_options() class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # Selected Task task = models.StringField() ### Cumulated Time needed for one math task ################ math_1_time = models.FloatField(blank=True) math_2_time = models.FloatField(blank=True) math_3_time = models.FloatField(blank=True) math_4_time = models.FloatField(blank=True) math_5_time = models.FloatField(blank=True) math_6_time = models.FloatField(blank=True) math_7_time = models.FloatField(blank=True) math_8_time = models.FloatField(blank=True) math_9_time = models.FloatField(blank=True) math_10_time = models.FloatField(blank=True) math_1 = make_math_ability_field() math_2 = make_math_ability_field() math_3 = make_math_ability_field() math_4 = make_math_ability_field() math_5 = make_math_ability_field() math_6 = make_math_ability_field() math_7 = make_math_ability_field() math_8 = make_math_ability_field() math_9 = make_math_ability_field() math_10 = make_math_ability_field() # Check correct answers math_correct = models.IntegerField(initial=0) # Number of tries math_1_tries = models.IntegerField(blank=True) math_2_tries = models.IntegerField(blank=True) math_3_tries = models.IntegerField(blank=True) math_4_tries = models.IntegerField(blank=True) math_5_tries = models.IntegerField(blank=True) math_6_tries = models.IntegerField(blank=True) math_7_tries = models.IntegerField(blank=True) math_8_tries = models.IntegerField(blank=True) math_9_tries = models.IntegerField(blank=True) math_10_tries = models.IntegerField(blank=True) # Timer timer_task1 = models.FloatField() new_timer_task1 = models.FloatField() math_time = models.FloatField() total_time = models.FloatField() # Time spent Math_Instructions_time_spent = models.FloatField(blank=True) MathTask_time_spent = models.FloatField(blank=True) # Warnings # Time spent Math_Instructions_warnings = models.IntegerField() MathTask_warnings = models.IntegerField() StartRound_warnings = models.IntegerField() # Selected Task task_option_this_round = models.IntegerField() payoff_math = models.CurrencyField() payoff_time = models.CurrencyField() # FUNCTIONS def creating_session(subsession: Subsession): for p in subsession.get_players(): if subsession.round_number == 1: p.participant.vars['math_piecerate'] = Constants.math_piecerate # fixed on subject and session level p.task_option_this_round = subsession.round_number - 1 p.task = Constants.task def set_payoff(player: Player): solutions = Constants.addition_task[player.task_option_this_round][1] math_1 = player.field_maybe_none('math_1') math_2 = player.field_maybe_none('math_2') math_3 = player.field_maybe_none('math_3') math_4 = player.field_maybe_none('math_4') math_5 = player.field_maybe_none('math_5') math_6 = player.field_maybe_none('math_6') math_7 = player.field_maybe_none('math_7') math_8 = player.field_maybe_none('math_8') math_9 = player.field_maybe_none('math_9') math_10 = player.field_maybe_none('math_10') answers = [ math_1, math_2, math_3, math_4, math_5, math_6, math_7, math_8, math_9, math_10, ] player.math_correct = sum([1 for x, y in zip(answers, solutions) if x == y]) player.payoff_math = player.math_correct * Constants.math_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 math_10_time = player.field_maybe_none('math_10_time') if ( math_10_time != None and math_10_time < Constants.timeout and math_10_time > 0 and player.math_correct == Constants.num_math_tasks ): player.payoff_time = ( Constants.timeout - math.ceil(math_10_time) ) * Constants.time_piecerate else: player.payoff_time = 0 * Constants.time_piecerate player.payoff = player.payoff_math + player.payoff_time # Put it into the ether player.participant.vars[f'math_ability_round_{player.round_number}'] = player.math_correct player.participant.vars[f'math_ability_payoff_round_{player.round_number}'] = player.payoff def save_data(player: Player): p_vars = player.participant.vars if player.round_number == 1: p_vars[f'math_t_1'] = [] p_vars[f'math_t_2'] = [] p_vars[f'math_t_3'] = [] p_vars[f'math_t_4'] = [] p_vars[f'math_t_5'] = [] p_vars[f'math_t_6'] = [] p_vars[f'math_t_7'] = [] p_vars[f'math_t_8'] = [] p_vars[f'math_t_9'] = [] p_vars[f'math_t_10'] = [] elif player.round_number == Constants.num_rounds: p_vars['num_math_tasks_math_ability'] = Constants.num_math_tasks p_vars['num_rounds_math_ability'] = Constants.num_rounds else: pass # Put it into the ether p_vars[f'math_t_1'].append(player.field_maybe_none('math_1_time')) p_vars[f'math_t_2'].append(player.field_maybe_none('math_2_time')) p_vars[f'math_t_3'].append(player.field_maybe_none('math_3_time')) p_vars[f'math_t_4'].append(player.field_maybe_none('math_4_time')) p_vars[f'math_t_5'].append(player.field_maybe_none('math_5_time')) p_vars[f'math_t_6'].append(player.field_maybe_none('math_6_time')) p_vars[f'math_t_7'].append(player.field_maybe_none('math_7_time')) p_vars[f'math_t_8'].append(player.field_maybe_none('math_8_time')) p_vars[f'math_t_9'].append(player.field_maybe_none('math_9_time')) p_vars[f'math_t_10'].append(player.field_maybe_none('math_10_time')) # PAGES class StartRound(Page): # oTree Timer timer_text = 'Time left until the round starts:' timeout_seconds = 5 @staticmethod def vars_for_template(player: Player): return dict(round_num=player.round_number) @staticmethod def js_vars(player: Player): return dict( page_name='StartRound', ) form_model = 'player' form_fields = ['StartRound_warnings'] class Math_Instructions(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ['Math_Instructions_time_spent', 'Math_Instructions_warnings'] @staticmethod def js_vars(player: Player): return dict( page_name='Math_Instructions', ) @staticmethod def vars_for_template(player: Player): example_diff = Constants.timeout - Constants.example_time example_payoff = example_diff * Constants.time_rate full_payoff = Constants.math_rate * Constants.num_math_tasks return dict( example_diff=example_diff, example_payoff=example_payoff, full_payoff=full_payoff ) class MathMemory(Page): pass class MathTask(Page): # oTree Timer timer_text = 'Time left in this round:' timeout_seconds = Constants.timeout @staticmethod def before_next_page(player: Player, timeout_happened): set_payoff(player) save_data(player) @staticmethod def vars_for_template(player: Player): p = player label = Constants.addition_task[player.round_number - 1][0] filler = ' = ' return dict( math_1_label=label[0] + filler, math_2_label=label[1] + filler, math_3_label=label[2] + filler, math_4_label=label[3] + filler, math_5_label=label[4] + filler, math_6_label=label[5] + filler, math_7_label=label[6] + filler, math_8_label=label[7] + filler, math_9_label=label[8] + filler, math_10_label=label[9] + filler, ) @staticmethod def js_vars(player: Player): p = player sol = Constants.addition_task[player.round_number - 1][1] return dict( math_solutions_array=sol, page_name='MathTask', num_math_tasks=Constants.num_math_tasks ) form_model = 'player' form_fields = [ 'timer_task1', 'new_timer_task1', 'math_time', 'total_time', 'math_1', 'math_2', 'math_3', 'math_4', 'math_5', 'math_6', 'math_7', 'math_8', 'math_9', 'math_10', 'math_time', 'math_1_time', 'math_2_time', 'math_3_time', 'math_4_time', 'math_5_time', 'math_6_time', 'math_7_time', 'math_8_time', 'math_9_time', 'math_10_time', 'math_1_tries', 'math_2_tries', 'math_3_tries', 'math_4_tries', 'math_5_tries', 'math_6_tries', 'math_7_tries', 'math_8_tries', 'math_9_tries', 'math_10_tries', 'MathTask_time_spent', 'MathTask_warnings', ] class Concave_Math(MathMemory): pass page_sequence = [Math_Instructions, StartRound, MathTask]