from otree.api import * c = Currency doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = '_Task' PLAYERS_PER_GROUP = None NUM_ROUNDS = 100 PAYROWS = 1 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # saves number of rows num_payrows = models.IntegerField( label='Please select how many sequences you want to count in the next task:', initial=0, choices=[6, 9, 12], widget=widgets.RadioSelect, blank=True, ) num_payrows_assign = models.IntegerField( label="Please select how many digits (of '0' and '1') each sequence will contain in the next task:", initial=0, choices=[9, 14, 18], widget=widgets.RadioSelect, blank=True, ) Row_1 = models.IntegerField(min=0, max=18, label='', blank=True) Easy_Rows = models.IntegerField(initial=0) Difficult_Rows = models.IntegerField(initial=0) Sum_Easy_Rows = models.IntegerField(initial=0) Sum_Difficult_Rows = models.IntegerField(initial=0) StartTime = models.FloatField(initial=0) EndTime = models.IntegerField(initial=0) TaskTime = models.FloatField(initial=0) correct_answers = models.IntegerField(initial=0) answer = models.IntegerField() num_answers = models.IntegerField(initial=0) num_payrounds = models.IntegerField(initial=0) difficulty = models.IntegerField() def Task_difficulty(player: Player): participant = player.participant if player.round_number == 1: player.difficulty = 18 player.Difficult_Rows = 1 return 18 else: # Sum_Easy_Rows = 0 # Sum_Difficult_Rows = 0 payrows = participant.NumPayrows previous_players = player.in_previous_rounds() Sum_Easy_Rows = sum([p.Easy_Rows for p in previous_players]) Sum_Difficult_Rows = sum([p.Difficult_Rows for p in previous_players]) # for temp_player in previous_players: # Sum_Easy_Rows += temp_player.Easy_Rows # Sum_Difficult_Rows += temp_player.Difficult_Rows if player.round_number == participant.PayRounds: if Sum_Difficult_Rows > Sum_Easy_Rows: player.Easy_Rows = 1 player.difficulty = 9 return 9 else: player.Difficult_Rows = 1 player.difficulty = 18 return 18 else: prev_player = player.in_round(participant.PayRounds - payrows) player.difficulty = prev_player.difficulty if player.difficulty == 18: player.Difficult_Rows = 1 else: player.Easy_Rows = 1 return prev_player.difficulty def create_task(seed, player: Player): import random random.seed(seed + (player.round_number*7)) # Generate a list of random integers between 0 and 1 - 9 Numbers random_numbers = [random.randint(0, 1) for _ in range(Task_difficulty(player))] # Convert the list of integers to a string numbers_string = ''.join(map(str, random_numbers)) # Count the number of times '1' appears in the string solution = numbers_string.count('1') return numbers_string, solution # Global definition of Timer def get_timeout_seconds(player): participant = player.participant return participant.expiry - participant.pagetime def Row_1_error_message(player, value): if value is None: return 'Field must be filled!' def num_payrows_error_message(player, value): if player.participant.treatment == 'SelfSelection' and value == 0: return 'Field must be filled!' def num_payrows_assign_error_message(player, value): if player.round_number > 1 and value == 0 and player.participant.treatment != 'SelfSelection': return 'Field must be filled!' class TaskRow: task = '' formfield = '' index = '' def __init__(self, task, formfield, index): self.task = task self.formfield = formfield self.index = index # PAGES class Introduction(Page): # Show page only in the first round @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player, timeout_happened): participant = player.participant participant.expiry = 5 * 60 participant.pagetime = 0 def vars_for_template(player): return { 'treatment': player.participant.treatment, } class Explanation(Page): form_model = 'player' form_fields = ['num_payrows', 'num_payrows_assign'] def vars_for_template(player): participant = player.participant if player.round_number > 1: num_payrows_prev = participant.NumPayrows else: num_payrows_prev = 1 if participant.treatment != 'SelfSelection': import random Payrows = [6, 9, 12] player.num_payrows = random.choice(Payrows) difficulty = Task_difficulty(player) if difficulty == 18: return {'Task_Difficulty': 'a difficult task (with long sequences)', 'display_finished_tasks': player.round_number > 1, 'num_payrows_prev': num_payrows_prev, 'num_payrows': player.num_payrows, 'treatment': participant.treatment, } else: return {'Task_Difficulty': 'an easy task (with short sequences)', 'display_finished_tasks': player.round_number > 1, 'num_payrows_prev': num_payrows_prev, 'num_payrows': player.num_payrows, 'treatment': participant.treatment, } def is_displayed(player): if player.round_number > 1: return player.round_number == player.participant.PayRounds and get_timeout_seconds(player) > 3 else: return get_timeout_seconds(player) > 3 def before_next_page(player, timeout_happened): participant = player.participant participant.PayRounds = player.round_number + player.num_payrows participant.NumPayrows = player.num_payrows class Task(Page): form_model = 'player' form_fields =['Row_1'] # End the task by Closing the Page if less than 3 seconds before timeout @staticmethod def is_displayed(player): return get_timeout_seconds(player) > 3 timer_text = 'Time left for all tasks:' # Only necessary to visualize the timer in template def get_timeout_seconds(player): participant = player.participant return participant.expiry - participant.pagetime def vars_for_template(player: Player): tasks = [] solutions = [] import time player.StartTime = int(time.time()) participant = player.participant for row in range(1): task, solution = create_task(row, player) tasks.append(TaskRow(task, 'Row_%s'%int(row+1), row+1)) solutions.append(solution) CurrentRow = 1 + participant.NumPayrows + player.round_number - participant.PayRounds participant.solution = solutions return (dict(tasks=tasks, formstrings=['Row_%s' % i for i in range(1, C.PAYROWS + 1)], num_payrows=participant.NumPayrows, CurrentRow=CurrentRow, treatment=participant.treatment)) # check correct answers each round by comparing rows and solutions def before_next_page(player: Player, timeout_happened): participant = player.participant if player.Row_1 == participant.solution[0]: player.correct_answers = 1 if player.Row_1 is not None: player.answer = 1 import time player.EndTime = int(time.time()) SumPagetimeRoundOne = player.EndTime - player.StartTime player.TaskTime = SumPagetimeRoundOne previous_players = player.in_previous_rounds() SumCurrentPagetime = SumPagetimeRoundOne for temp_player in previous_players: SumCurrentPagetime += temp_player.EndTime - temp_player.StartTime participant.pagetime = SumCurrentPagetime combined_correct_task = player.correct_answers num_answers = player.answer for temp_player in previous_players: combined_correct_task += temp_player.correct_answers num_answers += temp_player.answer participant.combined_correct_task = combined_correct_task participant.total_answers = num_answers class ThankYou(Page): # Show page after the last round @staticmethod def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS def before_next_page(player: Player, timeout_happened): participant = player.participant player_all_rounds = player.in_all_rounds() participant.avg_TaskTime = sum([p.TaskTime for p in player_all_rounds]) / participant.total_answers player.Sum_Easy_Rows = sum([p.Easy_Rows for p in player_all_rounds]) player.Sum_Difficult_Rows = sum([p.Difficult_Rows for p in player_all_rounds]) class CombinedResults(Page): pass class ResultsWaitPage(WaitPage): pass class Results(Page): pass page_sequence = [Introduction, Explanation, Task, ThankYou]