oTree Forum >

Resetting the timer between rounds

#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!

Write a reply

Set forum username