#1 by Fred
Hello everyone, I am programming a translation task interface (word -> numbers) using Otree. Currently, my project is to generate the table and word after each time subjects submit a number, within a time limit of 90 seconds each round. However, I have encountered two major problems using the following lines of code: 1. The first major problem is that the function that subjects see a new table and a word each time they submit a number, which is not feasible in the current codes (as I am not sure which way is much better: replacing the tables within a single page, or each table/word in a new page) 2. The second problem is that the timer does not reset between rounds. I am struggling to figure out what is the cause of this problem. I have attached the code below. Any advice and help would be greatly appreciated. Thanks so much! from otree.api import * import time import random import string doc = """ word translation with double randomization, repeated for five rounds """ class Constants(BaseConstants): name_in_url = 'translation_task' players_per_group = None num_rounds = 5 # Updated to 5 rounds letters_per_word = 3 use_timeout = True seconds_per_period = 90 points_per_correct_entry = 10 # Points for each correct entry class Subsession(BaseSubsession): def creating_session(subsession): for p in subsession.get_players(): p.participant.expiry = time.time() + Constants.seconds_per_period class Group(BaseGroup): pass class Player(BasePlayer): translated_number = models.StringField(blank=True) submitted_number = models.StringField(blank=True) # Added field points = models.IntegerField(initial=0) num_entries = models.IntegerField(initial=0) num_correct_entries = models.IntegerField(initial=0) estimated_performance = models.IntegerField( choices=[[1, "Top 10%"], [2, "Between top 20% and top 10% "], [3, "Between top 30% and top 20%"], [4, "Between top 40% and top 30%"], [5, "Between top 50% and top 40%"], [6, "Between top 60% and top 50%"], [7, "Between top 70% and top 60%"], [8, "Between top 80% and top 70%"], [9, "Between top 90% and top 80% "], [10, "Bottom 10%"]], widget=widgets.RadioSelect, label='Among all 30 participants in my session, I think my rank in this round would be in') def set_translation_table_and_word(player): letters = list(string.ascii_uppercase) random.shuffle(letters) numbers = random.sample(range(10, 100), 9) translation_table = dict(zip(letters[:9], numbers)) player.participant.vars['current_translation_table'] = translation_table player.participant.vars['word'] = ''.join(random.sample(letters[:9], Constants.letters_per_word)) player.participant.vars['correct_translation'] = ''.join(str(translation_table[letter]) for letter in player.participant.vars['word']) print(f"Translation table set: {translation_table}") print(f"Word generated: {player.participant.vars['word']}") def calculate_score(player): player.num_entries += 1 correct_translation = player.participant.vars['correct_translation'] if player.submitted_number == correct_translation: player.points += Constants.points_per_correct_entry player.num_correct_entries += 1 print("Correct submission") else: print("Incorrect submission") player.set_translation_table_and_word() def get_timeout_seconds(player): participant = player.participant import time return participant.expiry - time.time() def is_displayed1(player): """only returns True if there is time left.""" return player.get_timeout_seconds() > 0 #Pages class formal_round(Page): form_model = 'player' form_fields = ['submitted_number'] timer_text = 'Time left: ' @staticmethod def vars_for_template(player: Player): if 'round_start_time' not in player.participant.vars: player.participant.vars['round_start_time'] = time.time() player.participant.vars['current_time_limit'] = Constants.seconds_per_period player.set_translation_table_and_word() print("Round start time initialized and translation table set.") current_time = time.time() elapsed_time = current_time - player.participant.vars['round_start_time'] remaining_time = player.participant.vars['current_time_limit'] - elapsed_time return { 'round_number': player.round_number, 'translation_table': player.participant.vars.get('current_translation_table', {}), 'word': player.participant.vars.get('word', ''), 'time_limit': remaining_time, 'points': player.points, 'num_entries': player.num_entries, 'num_correct_entries': player.num_correct_entries, } @staticmethod def get_timeout_seconds(player: Player): current_time = time.time() elapsed_time = current_time - player.participant.vars['round_start_time'] remaining_time = player.participant.vars['current_time_limit'] - elapsed_time return max(remaining_time, 0) @staticmethod def live_method(player: Player, data): player.submitted_number = data['submitted_number'] # Store the submitted number print(f"Received submission: {player.submitted_number}") player.calculate_score() print( f"Score calculated: {player.points} points, {player.num_entries} entries, {player.num_correct_entries} correct entries") # Update remaining time after submission current_time = time.time() elapsed_time = current_time - player.participant.vars['round_start_time'] remaining_time = player.participant.vars['current_time_limit'] - elapsed_time return { player.id_in_group: { 'points': player.points, 'num_entries': player.num_entries, 'num_correct_entries': player.num_correct_entries, 'word': player.participant.vars['word'], 'translation_table': player.participant.vars['current_translation_table'], } } @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.expiry = time.time() + Constants.seconds_per_period class predict_performance(Page): form_model = 'player' form_fields = ['estimated_performance'] page_sequence = [] for _ in range(Constants.num_rounds): page_sequence += [formal_round] * 10 # Add 10 formal_round pages per round page_sequence.append(predict_performance)
#2
by
ErikdeKwaadsteniet
If your store the timer as a participant var, it will remain over rounds. If you store it as a player variable, it should reset every round. This might be the problem.
#3 by Fred
Thanks, it works!