Páginas de espera
Las páginas de espera son necesarias cuando un jugador necesita esperar a que otros realicen alguna acción antes de poder continuar. Por ejemplo, en un juego de ultimátum, el jugador 2 no puede aceptar o rechazar antes de haber visto la oferta del jugador 1.
Si tienes un WaitPage en tu secuencia de páginas, entonces oTree espera hasta que todos los jugadores del grupo hayan llegado a ese punto en la secuencia, y luego se permite que todos los jugadores continúen.
Si tu subsesión tiene múltiples grupos jugando simultáneamente, y deseas una página de espera que espere a todos los grupos (es decir, a todos los jugadores en la subsesión), puedes establecer el atributo wait_for_all_groups = True en la página de espera.
Para más información sobre grupos, consulta Grupos.
after_all_players_arrive
after_all_players_arrive te permite realizar algunos cálculos una vez que todos los jugadores han llegado a la página de espera. Este es un buen lugar para establecer las ganancias de los jugadores o determinar al ganador. Primero debes definir una función de Grupo que realice los cálculos deseados. Por ejemplo:
def set_payoffs(group):
for p in group.get_players():
p.payoff = 100
Luego, activa esta función haciendo:
class MyWaitPage(WaitPage):
after_all_players_arrive = set_payoffs
Si configuras wait_for_all_groups = True, entonces after_all_players_arrive debe ser una función de Subsession.
Si estás utilizando un editor de texto, after_all_players_arrive también se puede definir directamente en la WaitPage:
class MyWaitPage(WaitPage):
@staticmethod
def after_all_players_arrive(group: Group):
for p in group.get_players():
p.payoff = 100
También puede ser una cadena:
class MyWaitPage(WaitPage):
after_all_players_arrive = 'set_payoffs'
is_displayed()
Funciona de la misma manera que con las páginas regulares.
group_by_arrival_time
Si estableces group_by_arrival_time = True en una WaitPage, los jugadores se agruparán en el orden en que lleguen a esa página de espera:
class MyWaitPage(WaitPage):
group_by_arrival_time = True
Por ejemplo, si PLAYERS_PER_GROUP = 2, los primeros 2 jugadores en llegar a la página de espera se agruparán juntos, luego los siguientes 2 jugadores, y así sucesivamente.
Esto es útil en sesiones donde algunos participantes podrían retirarse (por ejemplo, experimentos en línea, o experimentos con páginas de consentimiento que permiten al participante abandonar anticipadamente), o en sesiones donde algunos participantes tardan mucho más que otros.
Una forma típica de usar group_by_arrival_time es colocarlo después de una aplicación que filtra a los participantes. Por ejemplo, si tu sesión tiene una página de consentimiento que da a los participantes la oportunidad de optar por no participar en el estudio, puedes crear una aplicación de «consentimiento» que solo contenga las páginas de consentimiento, y luego tener una app_sequence como ['consent', 'my_game'], donde my_game utiliza group_by_arrival_time. Esto significa que si alguien opta por no participar en consent, será excluido de la agrupación en my_game.
Presence detection
Nota
In oTree 6.0, this behavior has changed. If a participant has not shown any signs of activity within a certain period of time, they are asked if they are still there. If they don’t respond quickly enough, they are sent to an «inactive» page and need to click a button to rejoin.
oTree detects and excludes participants who switched away to another tab or window.
In order to be grouped, a user must be active on the wait page.
There is a colored dot in the tab of their web page (maybe not visible on mobile).
“🟢” means they are considered active. “🟡” means they are considered inactive.
We recommend you put some text in your wait page’s body_text
to tell participants to be aware of this and stay active on the page.
Notes
Si un juego tiene múltiples rondas, es posible que desees agrupar solo por tiempo de llegada en la ronda 1:
class MyWaitPage(WaitPage):
group_by_arrival_time = True
@staticmethod
def is_displayed(player):
return player.round_number == 1
Si haces esto, las rondas posteriores mantendrán la misma estructura de grupo que la ronda 1. De lo contrario, los jugadores serán reagrupados por su tiempo de llegada en cada ronda. (group_by_arrival_time copia la estructura del grupo a las rondas futuras.)
Notas:
id_in_groupno se asigna necesariamente en el orden en que los jugadores llegaron a la página.group_by_arrival_time solo se puede utilizar si la página de espera es la primera página en page_sequence
Si usas is_displayed en una página con group_by_arrival_time, debe basarse únicamente en el número de ronda. No uses is_displayed para mostrar la página a algunos jugadores pero no a otros.
Si group_by_arrival_time = True, entonces en creating_session, todos los jugadores estarán inicialmente en el mismo grupo. Los grupos solo se crean «sobre la marcha» a medida que los jugadores llegan a la página de espera.
Si necesitas un mayor control sobre cómo organizar a los jugadores en grupos, utiliza group_by_arrival_time_method().
group_by_arrival_time_method()
Si estás utilizando group_by_arrival_time y deseas tener más control sobre qué jugadores se asignan juntos, también puedes usar group_by_arrival_time_method().
Supongamos que, además de agrupar por tiempo de llegada, necesitas que cada grupo consista en 2 hombres y 2 mujeres.
Si defines una función llamada group_by_arrival_time_method, se llamará cada vez que un nuevo jugador llegue a la página de espera. El segundo argumento de la función es la lista de jugadores que actualmente están esperando en tu página de espera. Si seleccionas algunos de estos jugadores y los devuelves como una lista, esos jugadores serán asignados a un grupo y avanzarán. Si no devuelves nada, entonces no se produce agrupamiento.
Aquí hay un ejemplo donde cada grupo tiene 2 hombres y 2 mujeres. Se asume que en una aplicación anterior, asignaste participant.category a cada participante.
# note: this function goes at the module level, not inside the WaitPage.
def group_by_arrival_time_method(subsession, waiting_players):
print('in group_by_arrival_time_method')
m_players = [p for p in waiting_players if p.participant.category == 'M']
f_players = [p for p in waiting_players if p.participant.category == 'F']
if len(m_players) >= 2 and len(f_players) >= 2:
print('about to create a group')
return [m_players[0], m_players[1], f_players[0], f_players[1]]
print('not enough players yet to create a group')
Tiempos de espera en las páginas de espera
También puedes usar group_by_arrival_time_method para establecer un tiempo de espera en la página de espera, por ejemplo, para permitir que el participante continúe individualmente si ha estado esperando más de 5 minutos. Primero, debes registrar time.time() en la última página antes de la aplicación con group_by_arrival_time. Almacénalo en un participant field.
Luego define una función Player:
def waiting_too_long(player):
participant = player.participant
import time
# assumes you set wait_page_arrival in PARTICIPANT_FIELDS.
return time.time() - participant.wait_page_arrival > 5*60
Ahora usa esto:
def group_by_arrival_time_method(subsession, waiting_players):
if len(waiting_players) >= 3:
return waiting_players[:3]
for player in waiting_players:
if waiting_too_long(player):
# make a single-player group.
return [player]
Esto funciona porque la página de espera se actualiza automáticamente una o dos veces por minuto, lo que vuelve a ejecutar group_by_arrival_time_method.
Evitar que los jugadores se queden atrapados en las páginas de espera
Un problema común, especialmente en experimentos en línea, es que los jugadores se quedan atascados esperando a otro jugador de su grupo que se ha retirado o es demasiado lento.
Aquí hay algunas cosas que puedes hacer para reducir este problema:
Usa group_by_arrival_time
Como se describió anteriormente, puedes usar group_by_arrival_time para que solo los jugadores que están jugando activamente alrededor del mismo tiempo se agrupen juntos.
group_by_arrival_time funciona bien si se utiliza después de una tarea de «lock-in». En otras palabras, antes de tu juego multijugador, puedes tener una tarea de esfuerzo para un solo jugador. La idea es que si un participante se esfuerza por completar esta tarea inicial, es menos probable que se retire después de ese punto.
Usar tiempos de espera de página
Utiliza timeout_seconds en cada página, para que si un jugador es lento o inactivo, su página avance automáticamente. O, puedes forzar manualmente un tiempo de espera haciendo clic en el botón «Avanzar a los participantes más lentos» en la interfaz de administración.
Verificar timeout_happened
Puedes informar a los usuarios que deben enviar una página antes de su timeout_seconds, o de lo contrario serán considerados como un abandono. Incluso puedes tener una página que solo diga «haz clic en el botón siguiente para confirmar que aún estás jugando». Luego verifica timeout_happened. Si es True, puedes hacer varias cosas, como establecer un campo en ese jugador/grupo para indicar el abandono, y omitir el resto de las páginas en la ronda.
Reemplazar al jugador que abandonó con un bot
Aquí hay un ejemplo que combina algunas de las técnicas anteriores, de modo que incluso si un jugador se retira, continúa jugando automáticamente, como un bot. Primero, define un participant field llamado is_dropout, y establece su valor inicial en False en creating_session. Luego usa get_timeout_seconds y before_next_page en cada página, así:
class Page1(Page):
form_model = 'player'
form_fields = ['contribution']
@staticmethod
def get_timeout_seconds(player):
participant = player.participant
if participant.is_dropout:
return 1 # instant timeout, 1 second
else:
return 5*60
@staticmethod
def before_next_page(player, timeout_happened):
participant = player.participant
if timeout_happened:
player.contribution = cu(100)
participant.is_dropout = True
Notas:
Si el jugador no puede enviar la página a tiempo, establecemos
is_dropoutenTrue.Una vez que
is_dropoutestá establecido, cada página se envía automáticamente al instante.Cuando una página se envía automáticamente, usas
timeout_happenedpara decidir qué valor se envía en nombre del usuario.
Personalizando la apariencia de la página de espera
Puedes personalizar el texto que aparece en una página de espera configurando los atributos title_text y body_text, por ejemplo:
class MyWaitPage(WaitPage):
title_text = "Custom title text"
body_text = "Custom body text"
Ver también: Plantilla de página de espera personalizada.