import re import unicodedata jp_pos_to_en_pos = { '投': 'P', '捕': 'C', '一': '1B', '二': '2B', '三': '3B', '遊': 'SS', '左': 'LF', '中': 'CF', '右': 'RF', '右中': 'RCF', '左中': 'LCF' } def translate_pa_outcome(outcome): partial_outcomes = { 'ファウルフライ': 'FF', 'ファウルライナー': 'FL', 'ゴロ': 'GB', 'フライ': 'FB', 'ライナー': 'LD', '安打': '1B', '2塁打': '2B', '3塁打': '3B', 'ランニング本塁打': 'IHR', # inside-the-park home run '本塁打': 'HR', '犠打': 'SH', '犠飛': 'SF', '併殺打': 'DP', # what about triple plays? 'エラー': 'E', '犠打野選': 'SH FC', '野選': 'FC' } if outcome.endswith('三振'): if outcome.startswith('空振り'): return 'K' elif outcome.startswith('見逃し'): return 'inv_K' elif outcome == '四球': return 'BB' elif outcome == '死球': return 'HBP' elif outcome == '敬遠(申告敬遠)': return 'IBB' elif outcome == 'スリーバント失敗': return 'bunt_K' # have to confirm elif outcome == '犠打失': return 'failed_SH' # have to confirm elif outcome == '犠飛失': return 'failed_SF' #have to confirm elif outcome.endswith('走塁妨害'): return 'obstruction' elif outcome.endswith('走塁妨害'): return 'dropped_K_safe' elif outcome == '振り逃げ' or '暴投' in outcome: return 'WP' # reached base on WP; on another search, 振り逃げ is an uncaught third strike elif outcome.endswith('塁けん制 アウト'): return outcome.replace('塁けん制 アウト', 'B PK') elif 'けん制アウト' in outcome: return 'XB PK' # pickoff at unknown base elif outcome == '守備妨害': return 'defensive_interference' elif '盗塁失敗' in outcome: return 'CS' elif tag_search:= re.search(r'[123本](・[123本])*塁(間|上)タッチアウト', outcome): outcome = unicodedata.normalize('NFKC', tag_search.group(0)) outcome = outcome.replace('本', 'H') bases = re.findall(r'\d|H', outcome) return ' '.join(bases) + 'TO' # tag out elif '捕逸' in outcome: return 'PB' # reached base on passed ball for _outcome in partial_outcomes.keys(): if outcome.endswith(_outcome): return f'{jp_pos_to_en_pos[outcome.removesuffix(_outcome)]} {partial_outcomes[_outcome]}' return outcome jp_pitch_to_en_pitch = { # fastballs 'ストレート': '4-Seam Fastball', 'ツーシーム': '2-Seam Fastball', 'カットボール': 'Cutter', 'ワンシーム': '1-Seam Fastball', 'シンカー': 'Sinker', 'シュート': 'Shootball', # breaking balls 'スライダー': 'Slider', '縦スライダー': 'Vertical Slider', '高速スライダー': 'Hard Slider', 'スラーブ': 'Slurve', 'カーブ': 'Curveball', 'ナックルカーブ': 'Knuckle Curve', 'スローカーブ': 'Slow Curve', 'パワーカーブ': 'Power Curve', 'スクリュー': 'Screwball', # off speed 'チェンジアップ': 'Changeup', 'スプリット': 'Splitter', 'フォーク': 'Forkball', 'パーム': 'Palmball', # other 'スローボール': 'Eephus', } jp_pitch_to_pitch_code = { # fastballs 'ストレート': 'FF', 'ツーシーム': 'FT', 'カットボール': 'FC', 'ワンシーム': 'FE', 'シンカー': 'SI', 'シュート': 'SH', # breaking balls 'スライダー': 'SL', '縦スライダー': 'VS', '高速スライダー': 'HS', 'スラーブ': 'SV', 'カーブ': 'CU', 'ナックルカーブ': 'KC', 'スローカーブ': 'CS', 'パワーカーブ': 'PC', 'スクリュー': 'SC', # off speed 'チェンジアップ': 'CH', 'スプリット': 'FS', 'フォーク': 'FO', 'パーム': 'PA', # other 'スローボール': 'EP', } def translate_pitch_outcome(outcome): partial_outcomes = { '失': 'E', '犠打': 'SH', '犠飛': 'SF', '邪直': 'FLD', # foul line drive '邪飛': 'FF', 'ゴロ': 'GB', '飛': 'FB', '直': 'LD', '安': '1B', '2': '2B', '3': '3B', '走本': 'IHR', # inside-the-park home run, should confirm '本': 'HR', '併打': 'DP', '犠野': 'SH FC', '野選': 'FC' } if outcome == 'ボール': return 'B' elif outcome == 'ファウル': return 'F' elif outcome == '空振り': return 'SS' # swinging strike elif outcome == '見逃し': return 'LS' # swinging strike elif outcome == '空三振': return 'K' elif outcome == '見三振': return 'inv_K' elif outcome == 'バ三振': return 'bunt_K' elif outcome == '四球': return 'BB' elif outcome == '死球': return 'HBP' elif outcome == '犠打失': return 'SH_E' # or SBE? sac hit error elif outcome == '犠飛失': return 'SF_E' # sac fly error elif outcome == '走妨': return 'obstruction' elif outcome == '反則投球': return 'illegal_pitch' elif outcome == '守妨': return 'defensive_interference' elif outcome == '暴振逃': return 'WP_S' elif outcome == '逸振逃': return 'PB_S' for _outcome in partial_outcomes.keys(): if outcome.endswith(_outcome): return f'{jp_pos_to_en_pos[outcome.removesuffix(_outcome)]} {partial_outcomes[_outcome]}' return outcome max_pitch_types = len(jp_pitch_to_en_pitch)