import json import sys import model import model3p import numpy as np tiles_tenhou = { '1m': 0, '2m': 1, '3m': 2, '4m': 3, '5m': 4, '5mr': 4.5, '6m': 5, '7m': 6, '8m': 7, '9m': 8, '1p': 9, '2p': 10, '3p': 11, '4p': 12, '5p': 13, '5pr': 13.5, '6p': 14, '7p': 15, '8p': 16, '9p': 17, '1s': 18, '2s': 19, '3s': 20, '4s': 21, '5s': 22, '5sr': 22.5, '6s': 23, '7s': 24, '8s': 25, '9s': 26, 'E': 27, 'S': 28, 'W': 29, 'N': 30, 'P': 31, 'F': 32, 'C': 33 } MASK_4P = [ "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "E", "S", "W", "N", "P", "F", "C", '5mr', '5pr', '5sr', 'reach', 'chi_low', 'chi_mid', 'chi_high', 'pon', 'kan', 'hora', 'ryukyoku', 'none' ] MASK_3P = [ "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "E", "S", "W", "N", "P", "F", "C", '5mr', '5pr', '5sr', 'reach', 'pon', 'kan', 'nukidora', 'hora', 'ryukyoku', 'none' ] def SoftMax(arr, temperature=1.0): arr = np.array(arr, dtype=float) # Ensure the input is a numpy array of floats if arr.size == 0: return arr # Return the empty array if input is empty if not temperature == 1.0: arr /= temperature # Scale by temperature if temperature is not approximately 1 # Shift values by max for numerical stability max_val = np.max(arr) arr = arr - max_val # Apply the softmax transformation exp_arr = np.exp(arr) sum_exp = np.sum(exp_arr) softmax_arr = exp_arr / sum_exp return softmax_arr def ToBinStr(mask_bits): binary_string = bin(mask_bits)[2:] binary_string = binary_string.zfill(46) return binary_string def ToBoolList(mask_bits): binary_string = ToBinStr(mask_bits) bool_list = [] for bit in binary_string[::-1]: bool_list.append(bit == '1') return bool_list def ParseMeta(is_3p, meta): if is_3p: mask_list = MASK_3P else: mask_list = MASK_4P q_values = meta['q_values'] mask_bits = meta['mask_bits'] mask = ToBoolList(mask_bits) weight_values = SoftMax(q_values) q_value_idx = 0 option_list = [] for i in range(46): if mask[i]: option_list.append((mask_list[i], weight_values[q_value_idx])) q_value_idx += 1 option_list = sorted(option_list, key=lambda x: x[1], reverse=True) return option_list class Bot: def __init__(self): self.player_id: int = None self.model = None def react(self, events: str): events = json.loads(events) return_action = None for e in events: if e["type"] == "start_game": self.player_id = e["id"] self.model = model3p.load_model(self.player_id) continue if self.model is None or self.player_id is None: raise Exception(f"Model is not loaded yet") continue if e["type"] == "end_game": self.player_id = None self.model = None continue return_action = self.model.react(json.dumps(e, separators=(",", ":"))) return return_action class Bot4P: def __init__(self): self.player_id: int = None self.model = None def react(self, events: str, H = True): events = json.loads(events) return_action = None for e in events: if e["type"] == "start_game": self.player_id = e["id"] self.model = model.load_model(self.player_id) continue if self.model is None or self.player_id is None: raise Exception(f"Model is not loaded yet") continue if e["type"] == "end_game": self.player_id = None self.model = None continue return_action = self.model.react(json.dumps(e, separators=(",", ":"))) if H: return return_action if return_action == None: return None original = json.loads(return_action) return Select(original, ParseMeta(False, original['meta'])) false = False true = True if __name__ == '__main__': bot = Bot4P() print(bot) events = { "is3p": false, "model": "v2-a", "events": [ { "id": 0, "type": "start_game" }, { "oya": 0, "type": "start_kyoku", "honba": 0, "kyoku": 1, "bakaze": "E", "scores": [ 25000, 25000, 25000, 0 ], "tehais": [ [ "1m", "2s", "3s", "3p", "4p", "5p", "5s", "6s", "7s", "N", "N", "S", "W" ], [ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" ], [ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" ], [ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" ] ], "kyotaku": 0, "dora_marker": "9m" }, { "pai": "1p", "type": "tsumo", "actor": 0 } ], "timestamp": "2025-09-22T15:03:13.873Z" } res = bot.react(json.dumps(events['events'])) print(res)