Spaces:
Sleeping
Sleeping
| 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"] | |
| model_type = e.get('model') | |
| self.model = model3p.load_model(self.player_id, model_type) | |
| 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"] | |
| model_type = e.get('model') | |
| self.model = model.load_model(self.player_id, model_type) | |
| 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 = Bot() | |
| print(bot) | |
| events = { | |
| "is3p": false, | |
| "model": "v2-a", | |
| "events": [ | |
| {'type':'start_game','id':0}, | |
| { | |
| "oya": 0, | |
| "type": "start_kyoku", | |
| "honba": 0, | |
| "kyoku": 1, | |
| "bakaze": "E", | |
| "scores": [35000,35000,35000,0], | |
| "kyotaku": 0, | |
| "dora_marker": "5s", | |
| "tehais": [ | |
| ['1m','9m','1s','2s','3s','1p','2p','3p','E','N','N','P','P'], | |
| ['?','?','?','?','?','?','?','?','?','?','?','?','?',], | |
| ['?','?','?','?','?','?','?','?','?','?','?','?','?',], | |
| ['?','?','?','?','?','?','?','?','?','?','?','?','?',], | |
| ] | |
| }, | |
| { | |
| "pai": "1p", | |
| "type": "tsumo", | |
| "actor": 0 | |
| }, | |
| ]} | |
| res = bot.react(json.dumps(events['events'])) | |
| print(res) | |
| print(ParseMeta(True, json.loads(res)['meta'])) | |