def admin_fetchgames(): """ Return a JSON representation of all finished games """ q = GameModel.query(GameModel.over == True).order(GameModel.ts_last_move) gamelist = [] for gm in q.fetch(): gamelist.append(dict( id = gm.key.id(), ts = Alphabet.format_timestamp(gm.timestamp), lm = Alphabet.format_timestamp(gm.ts_last_move or gm.timestamp), p0 = None if gm.player0 is None else gm.player0.id(), p1 = None if gm.player1 is None else gm.player1.id(), rl = gm.robot_level, s0 = gm.score0, s1 = gm.score1, pr = gm.prefs )) return jsonify(gamelist = gamelist)
def admin_fetchgames(): """ Return a JSON representation of all finished games """ # noinspection PyPep8 q = GameModel.query(GameModel.over == True).order(GameModel.ts_last_move) gamelist = [] for gm in q.fetch(): gamelist.append( dict(id=gm.key.id(), ts=Alphabet.format_timestamp(gm.timestamp), lm=Alphabet.format_timestamp(gm.ts_last_move or gm.timestamp), p0=None if gm.player0 is None else gm.player0.id(), p1=None if gm.player1 is None else gm.player1.id(), rl=gm.robot_level, s0=gm.score0, s1=gm.score1, pr=gm.prefs)) return jsonify(gamelist=gamelist)
def _run_stats(from_time, to_time): """ Runs a process to update user statistics and Elo ratings """ logging.info(u"Generating stats from {0} to {1}".format(from_time, to_time)) if from_time is None or to_time is None: # Time range must be specified return if from_time >= to_time: # Null time range return # Iterate over all finished games within the time span in temporal order q = GameModel.query(GameModel.over == True).order(GameModel.ts_last_move) \ .filter(GameModel.ts_last_move > from_time) \ .filter(GameModel.ts_last_move <= to_time) # The accumulated user statistics users = dict() def _init_stat(user_id, robot_level): """ Returns the newest StatsModel instance available for the given user """ return StatsModel.newest_before(from_time, user_id, robot_level) cnt = 0 ts_last_processed = None try: # Use i as a progress counter for i, gm in enumerate(q): ts = Alphabet.format_timestamp(gm.timestamp) lm = Alphabet.format_timestamp(gm.ts_last_move or gm.timestamp) p0 = None if gm.player0 is None else gm.player0.id() p1 = None if gm.player1 is None else gm.player1.id() robot_game = (p0 is None) or (p1 is None) if robot_game: rl = gm.robot_level else: rl = 0 s0 = gm.score0 s1 = gm.score1 if (s0 == 0) and (s1 == 0): # When a game ends by resigning immediately, # make sure that the weaker player # doesn't get Elo points for a draw; in fact, # ignore such a game altogether in the statistics continue if p0 is None: k0 = "robot-" + str(rl) else: k0 = p0 if p1 is None: k1 = "robot-" + str(rl) else: k1 = p1 if k0 in users: urec0 = users[k0] else: users[k0] = urec0 = _init_stat(p0, rl if p0 is None else 0) if k1 in users: urec1 = users[k1] else: users[k1] = urec1 = _init_stat(p1, rl if p1 is None else 0) # Number of games played urec0.games += 1 urec1.games += 1 if not robot_game: urec0.human_games += 1 urec1.human_games += 1 # Total scores urec0.score += s0 urec1.score += s1 urec0.score_against += s1 urec1.score_against += s0 if not robot_game: urec0.human_score += s0 urec1.human_score += s1 urec0.human_score_against += s1 urec1.human_score_against += s0 # Wins and losses if s0 > s1: urec0.wins += 1 urec1.losses += 1 elif s1 > s0: urec1.wins += 1 urec0.losses += 1 if not robot_game: if s0 > s1: urec0.human_wins += 1 urec1.human_losses += 1 elif s1 > s0: urec1.human_wins += 1 urec0.human_losses += 1 # Find out whether players are established or beginners est0 = urec0.games > ESTABLISHED_MARK est1 = urec1.games > ESTABLISHED_MARK # Save the Elo point state used in the calculation gm.elo0, gm.elo1 = urec0.elo, urec1.elo # Compute the Elo points of both players adj = _compute_elo((urec0.elo, urec1.elo), s0, s1, est0, est1) # When an established player is playing a beginning (provisional) player, # leave the Elo score of the established player unchanged # Adjust player 0 if est0 and not est1: adj = (0, adj[1]) gm.elo0_adj = adj[0] urec0.elo += adj[0] # Adjust player 1 if est1 and not est0: adj = (adj[0], 0) gm.elo1_adj = adj[1] urec1.elo += adj[1] # If not a robot game, compute the human-only Elo if not robot_game: gm.human_elo0, gm.human_elo1 = urec0.human_elo, urec1.human_elo adj = _compute_elo((urec0.human_elo, urec1.human_elo), s0, s1, est0, est1) # Adjust player 0 if est0 and not est1: adj = (0, adj[1]) gm.human_elo0_adj = adj[0] urec0.human_elo += adj[0] # Adjust player 1 if est1 and not est0: adj = (adj[0], 0) gm.human_elo1_adj = adj[1] urec1.human_elo += adj[1] # Save the game object with the new Elo adjustment statistics gm.put() # Save the last processed timestamp ts_last_processed = lm cnt += 1 # Report on our progress if (i + 1) % 1000 == 0: logging.info(u"Processed {0} games".format(i + 1)) except DeadlineExceededError as ex: # Hit deadline: save the stuff we already have and # defer a new task to continue where we left off logging.info(u"Deadline exceeded in stats loop after {0} games and {1} users" .format(cnt, len(users))) logging.info(u"Resuming from timestamp {0}".format(ts_last_processed)) if ts_last_processed is not None: _write_stats(ts_last_processed, users) deferred.defer(deferred_stats, from_time = ts_last_processed or from_time, to_time = to_time) # Normal return prevents this task from being run again return except Exception as ex: logging.info(u"Exception in stats loop: {0}".format(ex)) # Avoid having the task retried raise deferred.PermanentTaskFailure() # Completed without incident logging.info(u"Normal completion of stats for {1} games and {0} users".format(len(users), cnt)) _write_stats(to_time, users)
def _run_stats(from_time, to_time): """ Runs a process to update user statistics and Elo ratings """ logging.info(u"Generating stats from {0} to {1}".format( from_time, to_time)) if from_time is None or to_time is None: # Time range must be specified return if from_time >= to_time: # Null time range return # Iterate over all finished games within the time span in temporal order q = GameModel.query(ndb.AND(GameModel.ts_last_move > from_time, GameModel.ts_last_move <= to_time)) \ .order(GameModel.ts_last_move) \ .filter(GameModel.over == True) # The accumulated user statistics users = dict() def _init_stat(user_id, robot_level): """ Returns the newest StatsModel instance available for the given user """ return StatsModel.newest_before(from_time, user_id, robot_level) cnt = 0 ts_last_processed = None try: # Use i as a progress counter i = 0 for gm in iter_q(q, chunk_size=250): i += 1 lm = Alphabet.format_timestamp(gm.ts_last_move or gm.timestamp) p0 = None if gm.player0 is None else gm.player0.id() p1 = None if gm.player1 is None else gm.player1.id() robot_game = (p0 is None) or (p1 is None) if robot_game: rl = gm.robot_level else: rl = 0 s0 = gm.score0 s1 = gm.score1 if (s0 == 0) and (s1 == 0): # When a game ends by resigning immediately, # make sure that the weaker player # doesn't get Elo points for a draw; in fact, # ignore such a game altogether in the statistics continue if p0 is None: k0 = "robot-" + str(rl) else: k0 = p0 if p1 is None: k1 = "robot-" + str(rl) else: k1 = p1 if k0 in users: urec0 = users[k0] else: users[k0] = urec0 = _init_stat(p0, rl if p0 is None else 0) if k1 in users: urec1 = users[k1] else: users[k1] = urec1 = _init_stat(p1, rl if p1 is None else 0) # Number of games played urec0.games += 1 urec1.games += 1 if not robot_game: urec0.human_games += 1 urec1.human_games += 1 # Total scores urec0.score += s0 urec1.score += s1 urec0.score_against += s1 urec1.score_against += s0 if not robot_game: urec0.human_score += s0 urec1.human_score += s1 urec0.human_score_against += s1 urec1.human_score_against += s0 # Wins and losses if s0 > s1: urec0.wins += 1 urec1.losses += 1 elif s1 > s0: urec1.wins += 1 urec0.losses += 1 if not robot_game: if s0 > s1: urec0.human_wins += 1 urec1.human_losses += 1 elif s1 > s0: urec1.human_wins += 1 urec0.human_losses += 1 # Find out whether players are established or beginners est0 = urec0.games > ESTABLISHED_MARK est1 = urec1.games > ESTABLISHED_MARK # Save the Elo point state used in the calculation gm.elo0, gm.elo1 = urec0.elo, urec1.elo # Compute the Elo points of both players adj = _compute_elo((urec0.elo, urec1.elo), s0, s1, est0, est1) # When an established player is playing a beginning (provisional) player, # leave the Elo score of the established player unchanged # Adjust player 0 if est0 and not est1: adj = (0, adj[1]) gm.elo0_adj = adj[0] urec0.elo += adj[0] # Adjust player 1 if est1 and not est0: adj = (adj[0], 0) gm.elo1_adj = adj[1] urec1.elo += adj[1] # If not a robot game, compute the human-only Elo if not robot_game: gm.human_elo0, gm.human_elo1 = urec0.human_elo, urec1.human_elo adj = _compute_elo((urec0.human_elo, urec1.human_elo), s0, s1, est0, est1) # Adjust player 0 if est0 and not est1: adj = (0, adj[1]) gm.human_elo0_adj = adj[0] urec0.human_elo += adj[0] # Adjust player 1 if est1 and not est0: adj = (adj[0], 0) gm.human_elo1_adj = adj[1] urec1.human_elo += adj[1] # Save the game object with the new Elo adjustment statistics gm.put() # Save the last processed timestamp ts_last_processed = lm cnt += 1 # Report on our progress if i % 1000 == 0: logging.info(u"Processed {0} games".format(i)) except DeadlineExceededError as ex: # Hit deadline: save the stuff we already have and # defer a new task to continue where we left off logging.info( u"Deadline exceeded in stats loop after {0} games and {1} users". format(cnt, len(users))) logging.info(u"Resuming from timestamp {0}".format(ts_last_processed)) if ts_last_processed is not None: _write_stats(ts_last_processed, users) deferred.defer(deferred_stats, from_time=ts_last_processed or from_time, to_time=to_time) # Normal return prevents this task from being run again return except Exception as ex: logging.info(u"Exception in stats loop: {0}".format(ex)) # Avoid having the task retried raise deferred.PermanentTaskFailure() # Completed without incident logging.info( u"Normal completion of stats for {1} games and {0} users".format( len(users), cnt)) _write_stats(to_time, users)