from otree.api import * import time doc = """ Part 3: continue with another task, but - in case of dropout(s) - fallback to smaller group. """ class C(BaseConstants): NAME_IN_URL = 'smaller_group_3' PLAYERS_PER_GROUP = None 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 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=True) # return waits def group_by_arrival_time_method(subsession: Subsession, waiting_players): # Users are placed into different baskets, according to their group in the previous app. # The dict 'd' will contain all these baskets. d = {} for p in waiting_players: group_id = p.participant.past_group_id if group_id not in d: # Since 'd' is initially empty, we need to initialize an empty list (basket) # each time we see a new group ID. d[group_id] = [] players_in_my_group = d[group_id] players_in_my_group.append(p) num_waiting = len(players_in_my_group) subsession.session.vars['num_waiting'] = num_waiting print('in my group there are', players_in_my_group) if len(players_in_my_group) >= p.participant.group_size: # for p in players_in_my_group: # p.group_size = len(players_in_my_group) # print('group size is', p.group_size) return players_in_my_group[:p.participant.group_size] waits = [waiting_seconds(p) for p in players_in_my_group] waits.sort(reverse=False) print(waits) # if len(waits) == (p.participant.group_size-1) and waits[p.participant.group_size-2] > 60*C.matching_timeout_mins: # return players_in_my_group # # if len(waits) == (p.participant.group_size-2) and waits[(p.participant.group_size-3)] > 60*C.matching_timeout_mins: # return players_in_my_group # # if len(waits) == (p.participant.group_size-3) and waits[(p.participant.group_size-4)] > 60*C.matching_timeout_mins: # return players_in_my_group # # if len(waits) == (p.participant.group_size-4) and waits[(p.participant.group_size-5)] > 60*C.matching_timeout_mins: # return players_in_my_group # PAGES class Grouping_page(WaitPage): title_text = ("Please remain on this page - the study continues soon") body_text = "" group_by_arrival_time = True template_name = 'smaller_group_3/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 after_all_players_arrive(group: Group): for p in group.get_players(): p.group_size = len(group.get_players()) print('group size is', p.group_size) @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' class Task(Page): pass page_sequence = [ Grouping_page, Task ]