include information strategy bot

This commit is contained in:
Maximilian Keßler 2023-11-20 16:45:43 +01:00
parent a59119c0c4
commit 1484d0d90f
Signed by: max
GPG key ID: BCC5A619923C0BA5
3 changed files with 67 additions and 53 deletions

View file

@ -1,10 +1,10 @@
import json import json
import re import re
import subprocess import subprocess
from typing import Dict from typing import Dict, Optional
from games import GAMES_PATH from games import GAMES_PATH
from bots import ensure_cheat_game_exists from bots import ensure_bot_game_exists
from pathlib import Path from pathlib import Path
DATA_FILE = Path('endgame-data.json') DATA_FILE = Path('endgame-data.json')
@ -20,7 +20,7 @@ with open(DATA_FILE, 'r') as f:
def analyze_game(filename: str): def analyze_game(filename: str):
max_draw_pile_size = 15 max_draw_pile_size = 15
try: try:
result = subprocess.run(['./endgame-analyzer', '-f', filename, '-d', str(max_draw_pile_size), '--interactive', '0', '--quiet', '-r'], stdout=subprocess.PIPE, timeout=60*15) result = subprocess.run(['./endgame-analyzer', '-f', filename, '-d', str(max_draw_pile_size), '--interactive', '0', '--quiet', '-r'], stdout=subprocess.PIPE, timeout=30)
raw_output = result.stdout raw_output = result.stdout
except subprocess.TimeoutExpired as time_err: except subprocess.TimeoutExpired as time_err:
raw_output = time_err.stdout raw_output = time_err.stdout
@ -44,7 +44,7 @@ def analyze_game(filename: str):
def full_analyze_game(filename: str): def full_analyze_game(filename: str):
max_draw_pile_size = 10 max_draw_pile_size = 10
try: try:
result = subprocess.run(['./endgame-analyzer', '-f', filename, '-d', str(max_draw_pile_size), '-i', '0', '--all-clues', '-r', '--quiet'], stdout=subprocess.PIPE, timeout=180) result = subprocess.run(['./endgame-analyzer', '-f', filename, '-d', str(max_draw_pile_size), '-i', '0', '--all-clues', '-r', '--quiet'], stdout=subprocess.PIPE, timeout=30)
raw_output = result.stdout raw_output = result.stdout
except subprocess.TimeoutExpired as time_err: except subprocess.TimeoutExpired as time_err:
raw_output = time_err.stdout raw_output = time_err.stdout
@ -71,14 +71,14 @@ def full_analyze_game(filename: str):
return probabilities return probabilities
def full_analyze_game_cached(game_id: int, cheat: bool = False): def full_analyze_game_cached(game_id: int, strategy: Optional[str] = None):
key = 'all' if not cheat else 'all-cheat' key = 'all' if strategy is None else 'all-{}'.format(strategy)
if cheat: if strategy is not None:
ensure_cheat_game_exists(game_id) ensure_bot_game_exists(game_id, strategy)
cached = DATA.get(key, {}).get(str(game_id), None) cached = DATA.get(key, {}).get(str(game_id), None)
if cached is not None: if cached is not None:
return cached return cached
result = full_analyze_game(str(GAMES_PATH / str(game_id)) + '-cheat' if cheat else '') result = full_analyze_game(str(GAMES_PATH / str(game_id)) + '-{}'.format(strategy) if strategy is not None else '')
if key not in DATA.keys(): if key not in DATA.keys():
DATA[key] = {} DATA[key] = {}
DATA[key][game_id] = result DATA[key][game_id] = result
@ -86,14 +86,14 @@ def full_analyze_game_cached(game_id: int, cheat: bool = False):
return result return result
def analyze_game_cached(game_id: int, cheat: bool = False): def analyze_game_cached(game_id: int, strategy: Optional[str] = None):
key = 'normal' if not cheat else 'normal-cheat' key = 'normal' if strategy is None else 'normal-{}'.format(strategy)
if cheat: if strategy is not None:
ensure_cheat_game_exists(game_id) ensure_bot_game_exists(game_id, strategy)
cached = DATA.get(key, {}).get(str(game_id), None) cached = DATA.get(key, {}).get(str(game_id), None)
if cached is not None: if cached is not None:
return cached return cached
result = analyze_game(str(GAMES_PATH / str(game_id)) + '-cheat' if cheat else '') result = analyze_game(str(GAMES_PATH / str(game_id)) + '-{}'.format(strategy) if strategy is not None else '')
if key not in DATA.keys(): if key not in DATA.keys():
DATA[key] = {} DATA[key] = {}
DATA[key][game_id] = result DATA[key][game_id] = result

View file

@ -1,6 +1,6 @@
import json import json
from typing import Dict from typing import Dict, Optional
from pathlib import Path from pathlib import Path
from hanabi.live.site_api import get from hanabi.live.site_api import get
@ -11,14 +11,14 @@ if not GAMES_PATH.exists():
GAMES_PATH.mkdir(parents=True) GAMES_PATH.mkdir(parents=True)
def get_game_json(game_id: int, cheat: bool = False) -> Dict: def get_game_json(game_id: int, strategy: Optional[str] = None) -> Dict:
filename = GAMES_PATH / (str(game_id) + ('-cheat' if cheat else '')) filename = GAMES_PATH / (str(game_id) + ('-{}'.format(strategy) if strategy is not None else ''))
if filename.exists(): if filename.exists():
with open(filename, 'r') as f: with open(filename, 'r') as f:
return json.load(f) return json.load(f)
if cheat: if strategy is not None:
print('Failed to load replay of cheating game with id {}'.format(game_id)) print('Failed to load replay of {} strategy version of game with id {}'.format(strategy, game_id))
return {} return {}
game = get("export/" + str(game_id)) game = get("export/" + str(game_id))

View file

@ -3,7 +3,7 @@ import requests_cache
import json import json
import csv import csv
import pandas import pandas
from typing import List from typing import List, Optional
from pathlib import Path from pathlib import Path
from hanabi.database import global_db_connection_manager from hanabi.database import global_db_connection_manager
@ -111,20 +111,20 @@ def analyze_games(games):
return retval return retval
def analyze_endgames(games, cheat): def analyze_endgames(games, strategy: Optional[str] = None):
retval = {} retval = {}
for game_id in games: for game_id in games:
print('Analysing endgames {} of game {}'.format('with cheating' if cheat else '', game_id)) print('Analysing endgames {} of game {}'.format('with strategy {}'.format(strategy) if strategy is not None else '', game_id))
result = analyze_game_cached(game_id, cheat) result = analyze_game_cached(game_id, strategy)
retval[game_id] = result retval[game_id] = result
return retval return retval
def full_analyze_endgames(games, cheat): def full_analyze_endgames(games, strategy: Optional[str] = None):
retval = {} retval = {}
for game_id in games: for game_id in games:
print('Analysing all endgames {} of game {}'.format('with cheating' if cheat else '', game_id)) print('Analysing all endgames {} of game {}'.format('with strategy {}'.format(strategy) if strategy is not None else '', game_id))
result = full_analyze_game_cached(game_id, cheat) result = full_analyze_game_cached(game_id, strategy)
retval[game_id] = result retval[game_id] = result
return retval return retval
@ -155,10 +155,10 @@ def lookup_val(endgame_dict, clue_modifier) -> str:
return retval return retval
def make_endgame_tables(ids: List[int], cheat: bool): def make_endgame_tables(ids: List[int], strategy: Optional[str] = None):
endgames = analyze_endgames(ids, cheat) endgames = analyze_endgames(ids, strategy)
postfix = '-cheat' if cheat else '' postfix = '-{}'.format(strategy) if strategy is not None else ''
main_fname = OUT_PATH / ('endgames' + postfix + '.csv') main_fname = OUT_PATH / ('endgames' + postfix + '.csv')
fieldnames = ['Game ID'] + [str(i) for i in range(1, 16)] fieldnames = ['Game ID'] + [str(i) for i in range(1, 16)]
@ -176,7 +176,7 @@ def make_endgame_tables(ids: List[int], cheat: bool):
x = pandas.read_csv(main_fname) x = pandas.read_csv(main_fname)
x.to_html(main_fname.with_suffix('.html'), escape=False) x.to_html(main_fname.with_suffix('.html'), escape=False)
all_endgames = full_analyze_endgames(ids, cheat) all_endgames = full_analyze_endgames(ids, strategy)
fieldnames = ['Game ID'] + [str(i) for i in range(1, 11)] fieldnames = ['Game ID'] + [str(i) for i in range(1, 11)]
for clue_modifier in range(-2, 3): for clue_modifier in range(-2, 3):
filename = special_fname.format(clue_modifier) filename = special_fname.format(clue_modifier)
@ -201,26 +201,9 @@ def make_endgame_tables(ids: List[int], cheat: bool):
x.to_html(Path(filename).with_suffix('.html'), escape=False) x.to_html(Path(filename).with_suffix('.html'), escape=False)
def create_cheating_replay_links(ids: List[int]): def make_results_table(games):
outfile = Path('out/cheating_links.csv')
with open(outfile, 'w') as f:
writer = csv.writer(f)
writer.writerow(["Game ID", "Cheating Replay Link"])
for game_id in ids:
replay = get_game_json(game_id, True)
instance, actions = parse_json_game(replay)
game = HanabLiveGameState(instance)
for action in actions:
game.make_action(action)
writer.writerow([game_id, link(game)])
x = pandas.read_csv(outfile)
x.to_html(outfile.with_suffix('.html'), render_links=True)
def main():
games = collect_player_games()
analysis = analyze_games(games) analysis = analyze_games(games)
streaks = {} streaks = {}
fieldnames = ['Game ID', 'Seed', 'Player #', 'Result', 'BDR'] fieldnames = ['Game ID', 'Seed', 'Player #', 'Result', 'BDR']
fieldnames += sort_players_by_num_games(games) fieldnames += sort_players_by_num_games(games)
@ -259,11 +242,42 @@ def main():
a = pandas.read_csv("out/games.csv") a = pandas.read_csv("out/games.csv")
a.to_html("out/games.html", escape=False) a.to_html("out/games.html", escape=False)
game_ids = [int(key) for key in games.keys()]
make_endgame_tables(game_ids, False)
create_cheating_replay_links(game_ids)
make_endgame_tables(game_ids, True)
def create_replay_links(ids: List[int], strategy: str):
outfile = Path('out/{}_links.csv'.format(strategy))
with open(outfile, 'w') as f:
writer = csv.writer(f)
writer.writerow(["Game ID", "{} Replay Link".format(strategy)])
for game_id in ids:
replay = get_game_json(game_id, strategy)
instance, actions = parse_json_game(replay)
game = HanabLiveGameState(instance)
for action in actions:
game.make_action(action)
writer.writerow([game_id, link(game)])
x = pandas.read_csv(outfile)
x.to_html(outfile.with_suffix('.html'), render_links=True)
def main():
games = collect_player_games()
game_ids = sorted(int(key) for key in games.keys())
# This is the main table, tracking streaks, loss reasons, BDRs
make_results_table(games)
# Additional endgame analysis stats:
# For the real games
make_endgame_tables(game_ids, None)
# For the cheating strategy
make_endgame_tables(game_ids, 'cheat')
# For the information strategy
make_endgame_tables(game_ids, 'info')
# Create JSON replay links to the bot games to watch
create_replay_links(game_ids, 'cheat')
create_replay_links(game_ids, 'info')
if __name__ == "__main__": if __name__ == "__main__":