from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import time from global_utilities.utils import GlobalConstant import random author = 'Sharon Peled' doc = """ Participants waiting room that guarantees that only when enough active participants are available they move together to the next phase of the experiment. """ class Constants(BaseConstants): name_in_url = 'Heads/Tails_Game_WaitPage' players_per_group = None num_rounds = 1 seconds_to_passive = GlobalConstant.seconds_to_passive passive_allowed_time = GlobalConstant.passive_allowed_time group_size = GlobalConstant.group_size active_players_per_group = GlobalConstant.active_players_per_group completion_code = GlobalConstant.completion_code basic_payment = GlobalConstant.basic_payment class Subsession(BaseSubsession): game_number = models.IntegerField(initial=1) tot_playing_players = models.IntegerField(initial=0) # number of users that made it to the game. def group_by_arrival_time_method(self, waiting_players): users_to_game = [] # users to move to the game users_to_end = [] # users to move to end active_players = [player for player in waiting_players if player.is_active][:Constants.active_players_per_group] # enough active players to form a game if len(active_players) == Constants.active_players_per_group: self.set_game(active_players, self.game_number) # rest players are forced to be passive self.force_passive([player for player in waiting_players if player not in active_players]) users_to_game += active_players rest_players = [player for player in waiting_players if player not in users_to_game] # don't move to game # if all users playing or waiting (but arrived) OR there aren't enough links to form a group if (self.tot_playing_players + len(waiting_players) == Constants.group_size) \ or (Constants.group_size - self.tot_playing_players < Constants.active_players_per_group): self.remove_players(rest_players) users_to_end += rest_players if len(users_to_game) > 0: # new game is formed self.tot_playing_players += len(active_players) self.session.vars["paying_round_"+str(self.game_number)] = self.get_paying_round() self.game_number += 1 return users_to_game+users_to_end if len(users_to_game+users_to_end) > 0 else None @staticmethod def remove_players(players): for player in players: player.is_in = False @staticmethod def set_game(active_players,game_number): for player in active_players: player.set_game(game_number,len(active_players)) player.is_in = True @staticmethod def force_passive(players): for player in players: player.force_passive = True @staticmethod def get_paying_round(): if random.choice(["1st round", "random_round"]) == "1st round": return 1 else: return random.randint(1,GlobalConstant.game_rounds) class Group(BaseGroup): pass class Player(BasePlayer): is_active = models.BooleanField(initial=False) # if the player is active or not is_in = models.BooleanField(initial=True) # if the player can enter a game force_passive = models.BooleanField(initial=False) beg_passive_time = models.FloatField(initial=time.time()) def set_game(self,game_number,num_participants): self.participant.vars["game_number"] = game_number self.participant.vars["num_participants_in_game"] = num_participants def set_status(self): if self.force_passive: self.is_active = False self.force_passive = False self.beg_passive_time = time.time() return self.is_active if not self.is_active: # was passive and come to get change if Constants.passive_allowed_time <= (time.time() - self.beg_passive_time): # he was passive more time then allowed - # should remain passive, in the next reload he'd be changed to active. self.beg_passive_time = time.time() return self.is_active # False self.is_active = not self.is_active self.beg_passive_time = time.time() return self.is_active