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