def evaluate_saved_model(weight_files, num_game, seed, bomb, num_run=1, log_prefix=None, verbose=True): model_lockers = [] greedy_extra = 0 num_player = len(weight_files) assert num_player > 1, "1 weight file per player" for weight_file in weight_files: if verbose: print("evaluating: %s\n\tfor %dx%d games" % (weight_file, num_run, num_game)) if ("GREEDY_EXTRA1" in weight_file or "sad" in weight_file or "aux" in weight_file): player_greedy_extra = 1 greedy_extra = 1 else: player_greedy_extra = 0 device = "cpu" game_info = utils.get_game_info(num_player, player_greedy_extra) input_dim = game_info["input_dim"] output_dim = game_info["num_action"] hid_dim = 512 actor = iql_r2d2.R2D2Agent(1, 0.99, 0.9, device, input_dim, hid_dim, output_dim) state_dict = torch.load(weight_file) if "pred.weight" in state_dict: state_dict.pop("pred.bias") state_dict.pop("pred.weight") actor.online_net.load_state_dict(state_dict) model_lockers.append(rela.ModelLocker([actor], device)) scores = [] perfect = 0 for i in range(num_run): _, _, score, p = evaluate( model_lockers, num_game, num_game * i + seed, 0, num_player, bomb, greedy_extra, ) scores.extend(score) perfect += p mean = np.mean(scores) sem = np.std(scores) / np.sqrt(len(scores)) perfect_rate = perfect / (num_game * num_run) if verbose: print("score: %f +/- %f" % (mean, sem), "; perfect: ", perfect_rate) return mean, sem, perfect_rate
def game(): # read the HTTP parameters if "user" not in request.values or "game" not in request.values: TODO game = int(request.values["game"]) user = request.values["user"] # connect to the database, then read the game state conn = open_db() (players,size,state) = utils.get_game_info(conn, game) (board, nextToPlay,letter) = utils.build_board(conn, game,size) return render_template("game.html", gameID=game, players=players, size=3, nextToPlay=players[nextToPlay], thisPlayer=user, state=state, board=board, canPlay=(nextToPlay == user))
# retrieving set of games we already have retrieved player stats for registered_games = set([pg['game_id'] for pg in player_game_stats]) cnt = 0 for game in games[:]: cnt += 1 # skipping already processed games if game['game_id'] in registered_games: continue # retrieving shots for current game game_shots = list( filter(lambda d: d['game_id'] == game['game_id'], shots)) print("+ Retrieving player stats for game %s" % get_game_info(game)) single_player_game_stats = get_single_game_player_data( game, game_shots) player_game_stats.extend(single_player_game_stats) # collecting stat lines on a per-player basis for stat_line in single_player_game_stats: per_player_game_stats[(stat_line['player_id'], stat_line['team'])].append(stat_line) if limit and cnt >= limit: break # retrieving current timestamp to indicate last modification of dataset current_datetime = datetime.now().timestamp() * 1000 output = [current_datetime, player_game_stats]
def reconstruct_skater_situation(game, verbose=False): """ Reconstruct skater on-ice situation for specified game. """ print("+ Reconstructing on-ice skater situation for game %s" % get_game_info(game)) # building interval tree to query goalies and player situations # receiving a list of times when goals has been scored it, goal_times = build_interval_tree(game) # retrieving all penalties all_penalties = list() for interval in it: if isinstance(interval.data, Penalty): penalty = interval.data all_penalties.append(penalty) # retrieving game end (in seconds) from interval tree game_end = - it.range().begin # retrieving goalies on ice and extra attackers for current game goalies_on_ice, extra_attackers = reconstruct_goalie_situation(it) # setting up dictionary to hold skater situations for each second of the game time_dict = dict() # setting up container to hold goalie/penalty intervals that have been # valid previously last_intervals = '' # setting up sets to hold a) penalties that effectively influence the # skater situation on ice, b) penalties that cancel each other out, c) # penalties that actually have started effective_penalties = set() cancelling_penalties = set() started_penalties = set() # initial setting for skater counts per team skr_count = {'home': 5, 'road': 5} # setting up skater situation at the beginning of the game time_dict[0] = {**skr_count, **goalies_on_ice[0]} for t in range(1, game_end + 1): # setting up containers holding the difference in skater/goalie numbers # in comparison to previous numbers produced by the currently # ongoing intervals curr_delta = {'home': 0, 'road': 0} curr_goalie_delta = {'home': 0, 'road': 0} # checking whether we're in the overtime of a regular season game and # adjusting skater counts accordingly in_ot = adjust_skater_count_in_overtime(game, t, skr_count) # adjusting skater counts according to the goaltenders currently on ice current_goalies = adjust_skater_counts_for_goalies(t, goalies_on_ice, curr_goalie_delta) if t in goal_times and verbose: print("- Goal: %d:%02d (%dv%d)" % (t // 60, t % 60, skr_count['home'], skr_count['road'])) # retrieving all currently valid goalie and penalty intervals, i.e. # on-going goalie shifts and currently served penalties current_intervals = it[-t] current_penalties = defaultdict(list) # doing further processing for the current second of the game only # if currently valid intervals have changed from previous second of # the game if current_intervals != last_intervals: # if verbose: # print("%d:%02d (%d) --> " % (t // 60, t % 60, t), end='') # retaining only penalty intervals penalty_intervals = list(filter(lambda item: (isinstance(item.data, Penalty)), current_intervals)) # collecting currently on-going penalties by team for pi in sorted(penalty_intervals, key=lambda interval: interval.data.from_time): penalty = pi.data if penalty.duration in (120, 300): if verbose: print( "- Penalty: %d:%02d" % (pi.end // -60, -pi.end % 60), "%d:%02d" % (pi.begin // -60, -pi.begin % 60), penalty.duration, penalty.team, penalty.infraction, penalty.actual_duration, penalty.surname) current_penalties[penalty.home_road].append(penalty) # collecting penalties that have been created at the current time penalties = list(filter( lambda penalty: penalty.create_time == (t - 1) and penalty.duration in (120, 300), all_penalties)) # if no penalties have been created at the current time, collect # all penalties that have started at the current time if not penalties: penalties = list(filter( lambda penalty: penalty.from_time == (t - 1) and penalty.duration in (120, 300), all_penalties)) # sorting collected penalties by actual duration and start time penalties = sorted(penalties, key=lambda penalty: (penalty.actual_duration, penalty.from_time)) # retrieving and sorting penalties taken by home team home_penalties = list(filter(lambda penalty: penalty.home_road == 'home', penalties)) home_penalties = sorted(home_penalties, key=lambda penalty: (penalty.actual_duration, penalty.from_time)) # retrieving and sorting penalties taken by road team road_penalties = list(filter(lambda penalty: penalty.home_road == 'road', penalties)) road_penalties = sorted(road_penalties, key=lambda penalty: (penalty.actual_duration, penalty.from_time)) # grouping minor and major penalties taken by home team home_min_penalties = list(filter(lambda penalty: penalty.duration == 120, home_penalties)) home_maj_penalties = list(filter(lambda penalty: penalty.duration == 300, home_penalties)) # grouping minor and major penalties taken by road team road_min_penalties = list(filter(lambda penalty: penalty.duration == 120, road_penalties)) road_maj_penalties = list(filter(lambda penalty: penalty.duration == 300, road_penalties)) # retrieving all teams taking penalties at current time penalty_teams = set([p.home_road for p in penalties]) # continuing if no penalties have been created or started at # the current time of the game if not penalties: pass # if only one team has taken penalties elif len(penalty_teams) == 1: for penalty in penalties: # skipping penalty if it hasn't already started if penalty.from_time > t: continue # checking if current penalty has not started yet or has # been cancelled by other penalties if penalty not in started_penalties.union(cancelling_penalties): team = penalty.home_road # in overtime the other team gets another player if in_ot: curr_delta[switch_team(team)] += 1 # in regulation the current team loses a player else: curr_delta[team] -= 1 # adding current penalty to effective penalties effective_penalties.add(penalty) # adding current penalty to started penalties started_penalties.add(penalty) # if both teams have taken penalties else: # registering major penalties that cancel each other out, i.e. if both teams received the same number # of major penalties at the current time if len(home_maj_penalties) == len(road_maj_penalties): for penalty in home_maj_penalties: cancelling_penalties.add(penalty) for penalty in road_maj_penalties: cancelling_penalties.add(penalty) elif len(home_maj_penalties) > len(road_maj_penalties): pen_cnt_diff = len(home_maj_penalties) - len(road_maj_penalties) pen_cnt = 0 for penalty in home_maj_penalties: if pen_cnt < pen_cnt_diff: # adjusting the number of skaters for corresponding # team starting at current time if penalty not in started_penalties.union(cancelling_penalties): # in regular season overtime the other team usually gets an additional player if in_ot: curr_delta['road'] += 1 else: curr_delta['home'] -= 1 pen_cnt += 1 effective_penalties.add(penalty) started_penalties.add(penalty) else: started_penalties.add(penalty) cancelling_penalties.add(penalty) for penalty in road_maj_penalties: started_penalties.add(penalty) cancelling_penalties.add(penalty) elif len(home_maj_penalties) < len(road_maj_penalties): pen_cnt_diff = len(road_maj_penalties) - len(home_maj_penalties) pen_cnt = 0 for penalty in road_maj_penalties: if pen_cnt < pen_cnt_diff: # adjusting the number of skaters for corresponding # team starting at current time if penalty not in started_penalties.union(cancelling_penalties): # in regular season overtime the other team usually gets an additional player if in_ot: curr_delta['home'] += 1 else: curr_delta['road'] -= 1 pen_cnt += 1 effective_penalties.add(penalty) started_penalties.add(penalty) else: started_penalties.add(penalty) cancelling_penalties.add(penalty) for penalty in home_maj_penalties: started_penalties.add(penalty) cancelling_penalties.add(penalty) # registering minor penalties that cancel each other out, i.e. if both teams received the same number # of major penalties at the current time if len(home_min_penalties) == len(road_min_penalties): # if current skater situation is 5-on-5 and only one minor # penalty was taken by each team we're going to 4-on-4 now if ( len(home_min_penalties) == 1 and len(road_min_penalties) == 1 and # redundant list(skr_count.values()) == [5, 5] ): for pens in [home_min_penalties, road_min_penalties]: for penalty in pens: team = penalty.home_road if penalty not in started_penalties.union(cancelling_penalties): if in_ot: curr_delta[switch_team(team)] += 1 else: curr_delta[team] -= 1 effective_penalties.add(penalty) started_penalties.add(penalty) # otherwise all penalties are cancelling each other out else: for penalty in home_min_penalties: cancelling_penalties.add(penalty) for penalty in road_min_penalties: cancelling_penalties.add(penalty) elif len(home_min_penalties) > len(road_min_penalties): pen_cnt_diff = len(home_min_penalties) - len(road_min_penalties) pen_cnt = 0 for penalty in home_min_penalties: if pen_cnt < pen_cnt_diff: # adjusting the number of skaters for corresponding # team starting at current time if penalty not in started_penalties.union(cancelling_penalties): if in_ot: curr_delta['road'] += 1 else: curr_delta['home'] -= 1 pen_cnt += 1 effective_penalties.add(penalty) started_penalties.add(penalty) else: started_penalties.add(penalty) cancelling_penalties.add(penalty) for penalty in road_min_penalties: started_penalties.add(penalty) cancelling_penalties.add(penalty) elif len(home_min_penalties) < len(road_min_penalties): pen_cnt_diff = len(road_min_penalties) - len(home_min_penalties) pen_cnt = 0 for penalty in road_min_penalties: if pen_cnt < pen_cnt_diff: # adjusting the number of skaters for corresponding # team starting at current time if penalty not in started_penalties.union(cancelling_penalties): if in_ot: curr_delta['home'] += 1 else: curr_delta['road'] -= 1 pen_cnt += 1 effective_penalties.add(penalty) started_penalties.add(penalty) else: started_penalties.add(penalty) cancelling_penalties.add(penalty) for penalty in home_min_penalties: started_penalties.add(penalty) cancelling_penalties.add(penalty) # handling expired penalties expired_penalties = set() for penalty in started_penalties: if t < penalty.from_time: continue # checking whether penalty interval currently registered as # ongoing is in fact still ongoing if penalty not in current_penalties[penalty.home_road]: expired_penalties.add(penalty) if penalty in effective_penalties: if in_ot: # this turned out to be wrong, since it lead to # skater counts below 3, but is it correct now? # curr_delta[switch_team(penalty.home_road)] -= 1 curr_delta[penalty.home_road] += 1 else: curr_delta[penalty.home_road] += 1 # actually removing no longer on-going intervals effective_penalties.difference_update(expired_penalties) started_penalties.difference_update(expired_penalties) if verbose: print("%d:%02d (%d) --> " % (t // 60, t % 60, t), end='') # actually calculating current skater count from previous count # and deltas collected from all current intervals for key in skr_count: skr_count[key] = skr_count[key] + curr_delta[key] + curr_goalie_delta[key] # re-adjusting skater counts in overtime, e.g. after penalties have # expired adjust_skater_count_in_overtime(game, t, skr_count) # testing modified skater counts test_skater_counts(skr_count) if verbose: addendum = '' if any(extra_attackers[t].values()): addendum = '(with extra attacker)' if current_intervals != last_intervals: print("%dv%d %s" % (skr_count['home'], skr_count['road'], addendum)) if t == 3601: print("--> %d:%02d (%d)" % (t // 60, t % 60, t)) print("%dv%d %s" % (skr_count['home'], skr_count['road'], addendum)) time_dict[t] = {**skr_count, **current_goalies} # saving currently valid intervals for comparison at next # second in the game last_intervals = current_intervals for t in time_dict: for key in ['home', 'road']: if time_dict[t][key] < 3: time_dict[t][key] = 3 if time_dict[t][key] > 6: time_dict[t][key] = 6 time_dict[t][game["%s_abbr" % key]] = time_dict[t][key] return time_dict, goal_times
args = parser.parse_args() season = args.season game_id = args.game_id # setting up path to source data file src_dir = os.path.join(CONFIG['tgt_processing_dir'], str(season)) src_path = os.path.join(src_dir, GAME_SRC) # loading games games = json.loads(open(src_path).read()) for game in games: if game_id and game['game_id'] != game_id: continue print(get_game_info(game)) skr_sit, goal_times = reconstruct_skater_situation(game, True) # for x in skr_sit: # print(x, skr_sit[x]) # print() # sits = defaultdict(int) # goals = defaultdict(int) # prev_sit = (5, 5) # for x in skr_sit: # curr_sit = (skr_sit[x]['home'], skr_sit[x]['road']) # if curr_sit != prev_sit: # sits[curr_sit] += 1 # print(x, skr_sit[x])
if __name__ == "__main__": torch.backends.cudnn.benchmark = True args = parse_args() if not os.path.exists(args.save_dir): os.makedirs(args.save_dir) logger_path = os.path.join(args.save_dir, "train.log") sys.stdout = common_utils.Logger(logger_path) saver = common_utils.TopkSaver(args.save_dir, 10) common_utils.set_all_seeds(args.seed) pprint.pprint(vars(args)) game_info = utils.get_game_info(args.num_player, args.greedy_extra) if args.method == "vdn": agent = vdn_r2d2.R2D2Agent( args.multi_step, args.gamma, 0.9, args.train_device, game_info["input_dim"], args.rnn_hid_dim, game_info["num_action"], ) agent_cls = vdn_r2d2.R2D2Agent elif args.method == "iql": agent = iql_r2d2.R2D2Agent( args.multi_step,
plr_status_dict = dict() for plr_game in player_game_stats: plr_status_dict[plr_game['player_id']] = plr_game['status'] for game in games[:]: game_shots = list( filter( lambda d: d['game_id'] == game['game_id'] and d['target_type'] == 'on_goal', shots)) # skipping already processed games if game['game_id'] in registered_games: continue print("+ Retrieving goalie stats for game %s" % get_game_info(game)) # retrieving goalies dressed from game item goalies_dressed = [ (game['home_abbr'], game['home_g1'][0] if 'home_g1' in game else None), (game['home_abbr'], game['home_g2'][0] if 'home_g2' in game else None), (game['home_abbr'], game['home_g3'][0] if 'home_g3' in game else None), (game['road_abbr'], game['road_g1'][0] if 'road_g1' in game else None), (game['road_abbr'], game['road_g2'][0] if 'road_g2' in game else None), (game['road_abbr'], game['road_g3'][0] if 'road_g3' in game else None),
else: all_shots = list() all_pp_situations_goals = dict() # retrieving set of games we already have retrieved player stats for registered_games = set([shot['game_id'] for shot in all_shots]) cnt = 0 for game in games[:]: cnt += 1 # skipping already processed games if game['game_id'] in registered_games: continue print("+ Retrieving shots for game %s " % get_game_info(game)) # collecting skater situation for each second of the game and a list # of times when goals has been scored times, goal_times = reconstruct_skater_situation(game) game_type = get_game_type_from_season_type(game) # retrieving raw shot data shots_src_path = os.path.join(CONFIG['base_data_dir'], 'shots', str(game['season']), str(game_type), "%d.json" % game['game_id']) if not os.path.isfile(shots_src_path): print("+ Skipping game since shot data is unavailable") continue shifts_src_path = os.path.join(CONFIG['base_data_dir'], 'shifts',
def move(): if "user" not in request.values or "game" not in request.values: TODO if "pos" not in request.values and "resign" not in request.values: TODO # connect to the database conn = open_db() game = int(request.values["game"]) (players,size,state) = utils.get_game_info(conn, game) print("game_info:", (players,size,state)) user = request.values["user"] if user not in players: TODO if "resign" in request.values: resign = True else: resign = False pos = request.values["pos"].split(",") assert len(pos) == 2 x = int(pos[0]) y = int(pos[1]) (board,nextPlayer,letter) = utils.build_board(conn, game,size) if user != players[nextPlayer]: TODO if resign: # this user is choosing to resign. Update the game state to reflect that. other_player_name = players[1-nextPlayer] cursor = conn.cursor() cursor.execute("""UPDATE games SET state=%s WHERE id=%s;""", (other_player_name+":resignation",game)) cursor.close() else: assert x >= 0 and x < size assert y >= 0 and y < size assert board[x][y] == "" board[x][y] = "XO"[nextPlayer] # we've done all of our sanity checks. We now know enough to say that # it's safe to add a new move. cursor = conn.cursor() cursor.execute("""INSERT INTO moves(gameID,x,y,letter,time) VALUES(%s,%s,%s,%s,NOW());""", (game,x,y,letter)) if cursor.rowcount != 1: TODO cursor.close() result = utils.analyze_board(board) if result != "": if result == "win": result = players[nextPlayer]+":win" cursor = conn.cursor() cursor.execute("""UPDATE games SET state=%s WHERE id=%s;""", (result,game)) cursor.close() # we've made changes, make sure to commit them! conn.commit() conn.close() # Redirect to a GET operation. This is the POST/REDIRECT/GET pattern. return redirect("%s?game=%d&user=$s" % (url_for("game"), game, user), code=303)
# loading existing player game stats if not initial and os.path.isfile(tgt_path): team_game_stats = json.loads(open(tgt_path).read())[-1] else: team_game_stats = list() # retrieving set of games we already have retrieved player stats for registered_games = set([pg['game_id'] for pg in team_game_stats]) cnt = 0 for game in games[:]: cnt += 1 # skipping already processed games if game['game_id'] in registered_games: continue print("+ Retrieving team stats for game %s" % get_game_info(game)) single_team_game_stats = get_single_game_team_data( game, grouped_shot_data, pp_sit_data.get(str(game['game_id']), dict())) # calculating days of rest between current and previous game for each team involved identify_days_rest_b2b_games(team_game_stats, single_team_game_stats) team_game_stats.extend(single_team_game_stats) if limit and cnt >= limit: break # retrieving current timestamp to indicate last modification of dataset current_datetime = datetime.now().timestamp() * 1000 output = [current_datetime, team_game_stats]