def _score_entries_tribe_aggregate(self, tribe: Tribe, challenge: Challenge, gamedb: Database, engine: Engine): score_dict = {'score': 0} players = gamedb.count_players(from_tribe=tribe) entries = gamedb.stream_entries(from_tribe=tribe, from_challenge=challenge) with ThreadPoolExecutor(max_workers=self._options. engine_worker_thread_count) as executor: executor.submit(self._score_entries_tribe_aggregate_fn, entries=entries, challenge=challenge, score_dict=score_dict, gamedb=gamedb, engine=engine) # tribe score = avg score of all tribe members log_message(message="_score_entries_tribe_agg = {}.".format( score_dict['score']), game_id=self._game_id) if players > 0: return score_dict['score'] / players return 0
def _score_entries_top_k_teams( self, k: float, tribe: Tribe, challenge: Challenge, gamedb: Database, engine: Engine) -> Tuple[List[Team], List[Team]]: team_scores = {} top_scores = list() winning_teams = list() losing_teams = list() entries = gamedb.stream_entries(from_tribe=tribe, from_challenge=challenge) with ThreadPoolExecutor(max_workers=self._options. engine_worker_thread_count) as executor: executor.submit(self._score_entries_top_k_teams_fn, entries=entries, challenge=challenge, score_dict=team_scores, gamedb=gamedb, engine=engine) for team_id, score in team_scores.items(): heapq.heappush( top_scores, (score / gamedb.count_players(from_team=gamedb.team_from_id(team_id)), team_id)) rank_threshold = float(k * len(top_scores)) log_message(message="Rank threshold = {}".format(rank_threshold), game_id=self._game_id) # note that the default python heap pops in ascending order, # so the rank here is actually worst to best. num_scores = len(top_scores) if num_scores == 1: score, team_id = heapq.heappop(top_scores) log_message(message="Winner {}.".format(team_id), game_id=self._game_id) winning_teams = [gamedb.team_from_id(team_id)] else: for rank in range(num_scores): score, team_id = heapq.heappop(top_scores) log_message(message="Team {} rank {} with score {}.".format( team_id, rank, score), game_id=self._game_id) if rank >= rank_threshold: log_message(message="Winner {}.".format(team_id), game_id=self._game_id) winning_teams.append(gamedb.team_from_id(team_id)) else: log_message(message="Loser {}.".format(team_id), game_id=self._game_id) losing_teams.append(gamedb.team_from_id(team_id)) return (winning_teams, losing_teams)
def messages(self, gamedb: Database) -> List[SMSEventMessage]: player_messages = [] count_players = gamedb.count_players( from_tribe=gamedb.tribe_from_id(self.winning_player.tribe_id)) # TODO(brandon): unclear why this can't be done in a single bulk message. for player in self.losing_players: options_map = messages.players_as_formatted_options_map( players=self.losing_players, exclude_player=player) # NOTE(brandon): we perform this synchronously to guarantee that ballots are # created in the DB before SMS messages go out to users. gamedb.ballot(player_id=player.id, options=options_map.options, challenge_id=None) player_messages.append( SMSEventMessage( content=messages. NOTIFY_SINGLE_TEAM_COUNCIL_EVENT_LOSING_MSG_FMT.format( header=messages.game_sms_header(gamedb=gamedb), winner=messages.format_tiktok_username( self.winning_player.tiktok), players=count_players, time=self.game_options.game_schedule. localized_time_string(self.game_options.game_schedule. daily_challenge_end_time), options=options_map.formatted_string), recipient_phone_numbers=[player.phone_number])) options_map = messages.players_as_formatted_options_map( players=self.losing_players, exclude_player=self.winning_player) gamedb.ballot(player_id=self.winning_player.id, options=options_map.options, challenge_id=None) player_messages.append( SMSEventMessage( content=messages. NOTIFY_SINGLE_TEAM_COUNCIL_EVENT_WINNING_MSG_FMT.format( header=messages.game_sms_header(gamedb=gamedb), players=count_players, time=self.game_options.game_schedule.localized_time_string( self.game_options.game_schedule. daily_challenge_end_time), options=options_map.formatted_string), recipient_phone_numbers=[self.winning_player.phone_number])) return player_messages
def messages(self, gamedb: Database) -> List[SMSEventMessage]: player_messages = [] count_players = gamedb.count_players( from_tribe=gamedb.tribe_from_id(self.winning_player.tribe_id)) for player in self.losing_players: player_messages.append( SMSEventMessage( content=messages.NOTIFY_SINGLE_TEAM_COUNCIL_EVENT_LOSING_MSG_FMT.format( header=messages.VIR_US_SMS_HEADER, winner=messages.format_tiktok_username( self.winning_player.tiktok), players=count_players, time=self.game_options.game_schedule.localized_time_string( self.game_options.game_schedule.daily_challenge_end_time), options=messages.players_as_formatted_options_list( players=self.losing_players, exclude_player=player) ), recipient_phone_numbers=player.phone_number ) ) player_messages.append( SMSEventMessage( content=messages.NOTIFY_SINGLE_TEAM_COUNCIL_EVENT_WINNING_MSG_FMT.format( header=messages.VIR_US_SMS_HEADER, players=count_players, time=self.game_options.game_schedule.localized_time_string( self.game_options.game_schedule.daily_challenge_end_time), options=messages.players_as_formatted_options_list( players=self.losing_players) ), recipient_phone_numbers=self.winning_player.phone_number ) ) return player_messages