from otree.api import * import time doc = """ Part 2: creating a group + timeout on wait page. """ class C(BaseConstants): NAME_IN_URL = 'smaller_group_2' PLAYERS_PER_GROUP = 5 NUM_ROUNDS = 1 matching_timeout_mins = 0.5 # max time on the waiting page min_group = 2 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): group_size = models.IntegerField() def waiting_too_long(player): return time.time() - player.participant.wait_page_arrival > C.matching_timeout_mins * 60 # Functions for the waiting page def waiting_seconds(player): participant = player.participant wait = int(time.time() - participant.wait_page_arrival) print('Player', player.id_in_subsession, 'waiting for', wait, 'seconds') return wait def ranked_waiting_seconds(waiting_players): waits = [waiting_seconds(p) for p in waiting_players] waits.sort(reverse=False) print(waits) return waits def group_by_arrival_time_method(subsession, waiting_players): num_waiting = len(waiting_players) subsession.session.vars['num_waiting'] = num_waiting print("number of waiting players:", num_waiting, " ", time.strftime('%X %x %Z')) if len(waiting_players) >= C.PLAYERS_PER_GROUP: for p in waiting_players: p.group_size = len(waiting_players) print('group size is', p.group_size) return waiting_players[:C.PLAYERS_PER_GROUP] waits = ranked_waiting_seconds(waiting_players) # Fallback to a smaller group if len(waits) == (C.PLAYERS_PER_GROUP-1) and waits[(C.PLAYERS_PER_GROUP-2)] > 60*C.matching_timeout_mins: for p in waiting_players: p.group_size = len(waits) print('group size is', p.group_size) return waiting_players if len(waits) == (C.PLAYERS_PER_GROUP-2) and waits[(C.PLAYERS_PER_GROUP-3)] > 60*C.matching_timeout_mins: for p in waiting_players: p.group_size = len(waits) print('group size is', p.group_size) return waiting_players if len(waits) == (C.PLAYERS_PER_GROUP-3) and waits[(C.PLAYERS_PER_GROUP-4)] > 60*C.matching_timeout_mins: for p in waiting_players: p.group_size = len(waits) print('group size is', p.group_size) return waiting_players # PAGES class Grouping_page(WaitPage): title_text = ("Please remain on this page - the task starts soon") body_text = "" group_by_arrival_time = True template_name = 'smaller_group_2/Grouping_page.html' @staticmethod def js_vars(player): return dict(arrival_time=player.participant.wait_page_arrival, current_time=time.time(), timeout_mins=C.matching_timeout_mins) @staticmethod def app_after_this_page(player: Player, upcoming_apps): if player.waiting_too_long() and player.group_size < C.min_group: return 'smaller_group_5' @staticmethod def after_all_players_arrive(group: Group): # save each participant's current group ID so it can be # accessed in the next app. for p in group.get_players(): participant = p.participant participant.past_group_id = group.id class Task(Page): @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.group_size = player.group_size player.participant.wait_page_arrival = time.time() # print(participant.wait_page_arrival) page_sequence = [Grouping_page, Task]