2023-11-11 01:38:37 +01:00
import json
import re
import subprocess
from typing import Dict
2023-11-20 13:26:40 +01:00
from games import GAMES_PATH
2023-11-11 01:38:37 +01:00
from pathlib import Path
DATA_FILE = Path ( ' endgame-data.json ' )
if not DATA_FILE . exists ( ) :
DATA_FILE . write_text ( ' {} ' )
with open ( DATA_FILE , ' r ' ) as f :
DATA : Dict = json . loads ( f . read ( ) )
2023-11-20 13:26:40 +01:00
def analyze_game ( filename : str ) :
2023-11-11 23:09:13 +01:00
max_draw_pile_size = 15
2023-11-11 14:02:44 +01:00
try :
2023-11-20 13:26:40 +01:00
result = subprocess . run ( [ ' ./endgame-analyzer ' , ' -f ' , filename , ' -d ' , str ( max_draw_pile_size ) , ' --interactive ' , ' 0 ' , ' --quiet ' , ' -r ' ] , stdout = subprocess . PIPE , timeout = 60 * 15 )
2023-11-11 14:02:44 +01:00
raw_output = result . stdout
except subprocess . TimeoutExpired as time_err :
raw_output = time_err . stdout
output = raw_output . decode ( ' utf-8 ' )
2023-11-12 00:01:22 +01:00
# Now, parse all results that we obtained (unclear how many depending on whether we ran into the timeout)
probabilities = { }
2023-11-20 12:27:09 +01:00
m = re . search ( r " Specified draw pile size of ([0-9]+) cannot be reached with specified replay \ . \ nReplay ends at turn [0-9]+ with score of ([0-9]+) \ . " , output , re . M )
if m :
won = ' 100 ' if m . group ( 2 ) == ' 25 ' else 0
for draw_pile_size in range ( 1 , int ( m . group ( 1 ) ) + 1 ) :
probabilities [ str ( draw_pile_size ) ] = won
2023-11-11 14:02:44 +01:00
2023-11-11 23:09:13 +01:00
for m in re . finditer ( ' Probability with ([0-9]+) cards left in deck: .*/.* ~ ([0-9.]+) ' , output ) :
2023-11-11 14:02:44 +01:00
probabilities [ str ( m . group ( 1 ) ) ] = m . group ( 2 )
2023-11-11 01:38:37 +01:00
return probabilities
2023-11-11 04:20:41 +01:00
2023-11-20 13:26:40 +01:00
def full_analyze_game ( filename : str ) :
2023-11-12 00:01:22 +01:00
max_draw_pile_size = 10
2023-11-11 01:38:37 +01:00
try :
2023-11-20 13:26:40 +01:00
result = subprocess . run ( [ ' ./endgame-analyzer ' , ' -f ' , filename , ' -d ' , str ( max_draw_pile_size ) , ' -i ' , ' 0 ' , ' --all-clues ' , ' -r ' , ' --quiet ' ] , stdout = subprocess . PIPE , timeout = 180 )
2023-11-12 00:01:22 +01:00
raw_output = result . stdout
except subprocess . TimeoutExpired as time_err :
raw_output = time_err . stdout
output = raw_output . decode ( ' utf-8 ' )
probabilities = { }
zero_dict = {
( ( ' + ' if clue_modifier > = 0 else ' ' ) + str ( clue_modifier ) ) : 0 for clue_modifier in range ( - 8 , 9 )
}
2023-11-20 12:27:09 +01:00
hundred_dict = {
( ( ' + ' if clue_modifier > = 0 else ' ' ) + str ( clue_modifier ) ) : 100 for clue_modifier in range ( - 8 , 9 )
}
m = re . search ( r " Specified draw pile size of ([0-9]+) cannot be reached with specified replay \ . \ nReplay ends at turn [0-9]+ with score of ([0-9]+) \ . " , output , re . M )
if m :
won = hundred_dict if m . group ( 2 ) == ' 25 ' else zero_dict
for draw_pile_size in range ( 1 , int ( m . group ( 1 ) ) + 1 ) :
probabilities [ str ( draw_pile_size ) ] = won
2023-11-12 00:01:22 +01:00
2023-11-11 04:20:41 +01:00
for m in re . finditer ( ' Probability with ([0-9]+) cards left in deck and [0-8] clues \ ((.[0-8]) \ ).*: .*/.* ~ ([0-9.]*) ' , output ) :
if m . group ( 1 ) not in probabilities . keys ( ) :
probabilities [ m . group ( 1 ) ] = { }
probabilities [ m . group ( 1 ) ] [ m . group ( 2 ) ] = m . group ( 3 )
2023-11-11 01:38:37 +01:00
return probabilities
2023-11-11 04:20:41 +01:00
2023-11-20 13:26:40 +01:00
def full_analyze_game_cached ( game_id : int , cheat : bool = False ) :
2023-11-11 01:38:37 +01:00
cached = DATA . get ( ' all ' , { } ) . get ( str ( game_id ) , None )
if cached is not None :
return cached
2023-11-20 13:26:40 +01:00
result = full_analyze_game ( str ( GAMES_PATH / str ( game_id ) ) + ' -cheat ' if cheat else ' ' )
key = ' all ' if not cheat else ' all-cheat '
if key not in DATA . keys ( ) :
DATA [ key ] = { }
DATA [ key ] [ game_id ] = result
2023-11-11 01:38:37 +01:00
save_cache ( )
return result
2023-11-20 13:26:40 +01:00
def analyze_game_cached ( game_id : int , cheat : bool = False ) :
2023-11-11 23:09:13 +01:00
cached = DATA . get ( ' normal ' , { } ) . get ( str ( game_id ) , None )
2023-11-11 01:38:37 +01:00
if cached is not None :
return cached
2023-11-20 13:26:40 +01:00
result = analyze_game ( str ( GAMES_PATH / str ( game_id ) ) + ' -cheat ' if cheat else ' ' )
key = ' normal ' if not cheat else ' normal-cheat '
if key not in DATA . keys ( ) :
DATA [ key ] = { }
DATA [ key ] [ game_id ] = result
2023-11-11 01:38:37 +01:00
save_cache ( )
return result
def save_cache ( ) :
with open ( DATA_FILE , ' w ' ) as f :
f . writelines ( json . dumps ( DATA , indent = 2 ) )