def test_calculate_scores_and_tsumo(self): hand = ScoresCalculator() config = HandConfig(is_tsumo=True, options=OptionalRules(kazoe_limit=HandConfig.KAZOE_NO_LIMIT)) result = hand.calculate_scores(han=1, fu=30, config=config) self.assertEqual(result['main'], 500) self.assertEqual(result['additional'], 300) result = hand.calculate_scores(han=3, fu=30, config=config) self.assertEqual(result['main'], 2000) self.assertEqual(result['additional'], 1000) result = hand.calculate_scores(han=3, fu=60, config=config) self.assertEqual(result['main'], 3900) self.assertEqual(result['additional'], 2000) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result['main'], 3900) self.assertEqual(result['additional'], 2000) result = hand.calculate_scores(han=5, fu=0, config=config) self.assertEqual(result['main'], 4000) self.assertEqual(result['additional'], 2000) result = hand.calculate_scores(han=6, fu=0, config=config) self.assertEqual(result['main'], 6000) self.assertEqual(result['additional'], 3000) result = hand.calculate_scores(han=8, fu=0, config=config) self.assertEqual(result['main'], 8000) self.assertEqual(result['additional'], 4000) result = hand.calculate_scores(han=11, fu=0, config=config) self.assertEqual(result['main'], 12000) self.assertEqual(result['additional'], 6000) result = hand.calculate_scores(han=13, fu=0, config=config) self.assertEqual(result['main'], 16000) self.assertEqual(result['additional'], 8000) result = hand.calculate_scores(han=26, fu=0, config=config) self.assertEqual(result['main'], 32000) self.assertEqual(result['additional'], 16000) result = hand.calculate_scores(han=39, fu=0, config=config) self.assertEqual(result['main'], 48000) self.assertEqual(result['additional'], 24000) result = hand.calculate_scores(han=52, fu=0, config=config) self.assertEqual(result['main'], 64000) self.assertEqual(result['additional'], 32000) result = hand.calculate_scores(han=65, fu=0, config=config) self.assertEqual(result['main'], 80000) self.assertEqual(result['additional'], 40000) result = hand.calculate_scores(han=78, fu=0, config=config) self.assertEqual(result['main'], 96000) self.assertEqual(result['additional'], 48000)
def test_calculate_scores_and_tsumo_by_dealer(self): hand = ScoresCalculator() config = HandConfig( player_wind=EAST, is_tsumo=True, options=OptionalRules(kazoe_limit=HandConfig.KAZOE_NO_LIMIT)) result = hand.calculate_scores(han=1, fu=30, config=config) self.assertEqual(result["main"], 500) self.assertEqual(result["additional"], 500) result = hand.calculate_scores(han=3, fu=30, config=config) self.assertEqual(result["main"], 2000) self.assertEqual(result["additional"], 2000) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result["main"], 3900) self.assertEqual(result["additional"], 3900) result = hand.calculate_scores(han=5, fu=0, config=config) self.assertEqual(result["main"], 4000) self.assertEqual(result["additional"], 4000) result = hand.calculate_scores(han=6, fu=0, config=config) self.assertEqual(result["main"], 6000) self.assertEqual(result["additional"], 6000) result = hand.calculate_scores(han=8, fu=0, config=config) self.assertEqual(result["main"], 8000) self.assertEqual(result["additional"], 8000) result = hand.calculate_scores(han=11, fu=0, config=config) self.assertEqual(result["main"], 12000) self.assertEqual(result["additional"], 12000) result = hand.calculate_scores(han=13, fu=0, config=config) self.assertEqual(result["main"], 16000) self.assertEqual(result["additional"], 16000) result = hand.calculate_scores(han=26, fu=0, config=config) self.assertEqual(result["main"], 32000) self.assertEqual(result["additional"], 32000) result = hand.calculate_scores(han=39, fu=0, config=config) self.assertEqual(result["main"], 48000) self.assertEqual(result["additional"], 48000) result = hand.calculate_scores(han=52, fu=0, config=config) self.assertEqual(result["main"], 64000) self.assertEqual(result["additional"], 64000) result = hand.calculate_scores(han=65, fu=0, config=config) self.assertEqual(result["main"], 80000) self.assertEqual(result["additional"], 80000) result = hand.calculate_scores(han=78, fu=0, config=config) self.assertEqual(result["main"], 96000) self.assertEqual(result["additional"], 96000)
def test_kiriage_mangan(self): hand = ScoresCalculator() config = HandConfig(options=OptionalRules(kiriage=True)) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result['main'], 8000) result = hand.calculate_scores(han=3, fu=60, config=config) self.assertEqual(result['main'], 8000) config = HandConfig(player_wind=EAST, options=OptionalRules(kiriage=True)) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result['main'], 12000) result = hand.calculate_scores(han=3, fu=60, config=config) self.assertEqual(result['main'], 12000)
def test_calculate_scores_and_ron(self): hand = ScoresCalculator() config = HandConfig(options=OptionalRules( kazoe_limit=HandConfig.KAZOE_NO_LIMIT)) result = hand.calculate_scores(han=1, fu=30, config=config) self.assertEqual(result['main'], 1000) result = hand.calculate_scores(han=1, fu=110, config=config) self.assertEqual(result['main'], 3600) result = hand.calculate_scores(han=2, fu=30, config=config) self.assertEqual(result['main'], 2000) result = hand.calculate_scores(han=3, fu=30, config=config) self.assertEqual(result['main'], 3900) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result['main'], 7700) result = hand.calculate_scores(han=4, fu=40, config=config) self.assertEqual(result['main'], 8000) result = hand.calculate_scores(han=5, fu=0, config=config) self.assertEqual(result['main'], 8000) result = hand.calculate_scores(han=6, fu=0, config=config) self.assertEqual(result['main'], 12000) result = hand.calculate_scores(han=8, fu=0, config=config) self.assertEqual(result['main'], 16000) result = hand.calculate_scores(han=11, fu=0, config=config) self.assertEqual(result['main'], 24000) result = hand.calculate_scores(han=13, fu=0, config=config) self.assertEqual(result['main'], 32000) result = hand.calculate_scores(han=26, fu=0, config=config) self.assertEqual(result['main'], 64000) result = hand.calculate_scores(han=39, fu=0, config=config) self.assertEqual(result['main'], 96000) result = hand.calculate_scores(han=52, fu=0, config=config) self.assertEqual(result['main'], 128000) result = hand.calculate_scores(han=65, fu=0, config=config) self.assertEqual(result['main'], 160000) result = hand.calculate_scores(han=78, fu=0, config=config) self.assertEqual(result['main'], 192000)
def test_tsumo_hand_and_disabled_pinfu(self): fu_calculator = FuCalculator() config = HandConfig(is_tsumo=True, options=OptionalRules(fu_for_pinfu_tsumo=True)) tiles = self._string_to_136_array(sou='2278', man='123456', pin='123') win_tile = self._string_to_136_tile(sou='6') hand = self._hand(self._to_34_array(tiles + [win_tile])) fu_details, fu = fu_calculator.calculate_fu(hand, win_tile, self._get_win_group(hand, win_tile), config) self.assertEqual(2, len(fu_details)) self.assertTrue({'fu': 20, 'reason': FuCalculator.BASE} in fu_details) self.assertTrue({'fu': 2, 'reason': FuCalculator.TSUMO} in fu_details) self.assertEqual(fu, 30)
def test_open_hand_withou_additional_fu(self): fu_calculator = FuCalculator() config = HandConfig() tiles = self._string_to_136_array(sou='23478', man='234567', pin='22') win_tile = self._string_to_136_tile(sou='6') hand = self._hand(self._to_34_array(tiles + [win_tile])) melds = [self._make_meld(Meld.CHI, sou='234')] config = HandConfig(options=OptionalRules(fu_for_open_pinfu=False)) fu_details, fu = fu_calculator.calculate_fu(hand, win_tile, self._get_win_group(hand, win_tile), config, melds=melds) self.assertEqual(1, len(fu_details)) self.assertTrue({'fu': 20, 'reason': FuCalculator.BASE} in fu_details) self.assertEqual(fu, 20)
def test_calculate_scores_and_ron_by_dealer(self): hand = ScoresCalculator() config = HandConfig( player_wind=EAST, options=OptionalRules(kazoe_limit=HandConfig.KAZOE_NO_LIMIT)) result = hand.calculate_scores(han=1, fu=30, config=config) self.assertEqual(result['main'], 1500) result = hand.calculate_scores(han=2, fu=30, config=config) self.assertEqual(result['main'], 2900) result = hand.calculate_scores(han=3, fu=30, config=config) self.assertEqual(result['main'], 5800) result = hand.calculate_scores(han=4, fu=30, config=config) self.assertEqual(result['main'], 11600) result = hand.calculate_scores(han=5, fu=0, config=config) self.assertEqual(result['main'], 12000) result = hand.calculate_scores(han=6, fu=0, config=config) self.assertEqual(result['main'], 18000) result = hand.calculate_scores(han=8, fu=0, config=config) self.assertEqual(result['main'], 24000) result = hand.calculate_scores(han=11, fu=0, config=config) self.assertEqual(result['main'], 36000) result = hand.calculate_scores(han=13, fu=0, config=config) self.assertEqual(result['main'], 48000) result = hand.calculate_scores(han=26, fu=0, config=config) self.assertEqual(result['main'], 96000) result = hand.calculate_scores(han=39, fu=0, config=config) self.assertEqual(result['main'], 144000) result = hand.calculate_scores(han=52, fu=0, config=config) self.assertEqual(result['main'], 192000) result = hand.calculate_scores(han=65, fu=0, config=config) self.assertEqual(result['main'], 240000) result = hand.calculate_scores(han=78, fu=0, config=config) self.assertEqual(result['main'], 288000)
def calculate_waiting_costs(self, player, player_waiting): waiting = [] for tile in player_waiting: config = HandConfig( is_riichi=player.discards[-1].after_riichi, player_wind=player.player_wind, round_wind=player.table.round_wind, options=OptionalRules(has_aka_dora=True, has_open_tanyao=True), ) win_tile = tile * 4 # we don't need to think, that our waiting is aka dora if win_tile in AKA_DORA_LIST: win_tile += 1 tiles = player.tiles + [win_tile] result = self.finished_hand.estimate_hand_value( tiles, win_tile, player.melds, player.table.dora_indicators, config) if result.error: waiting.append({ "tile": win_tile, "han": None, "fu": None, "cost": 0, "yaku": [] }) else: waiting.append({ "tile": win_tile, "han": result.han, "fu": result.fu, "cost": result.cost["main"], "yaku": [{ "id": x.yaku_id, "name": x.name } for x in result.yaku], }) return waiting
def calculate_exact_hand_value_or_get_from_cache( self, win_tile_136, tiles=None, call_riichi=False, is_tsumo=False, is_chankan=False, is_haitei=False, is_ippatsu=False, ): if not tiles: tiles = self.player.tiles[:] else: tiles = tiles[:] tiles += [win_tile_136] additional_han = 0 if is_chankan: additional_han += 1 if is_haitei: additional_han += 1 if is_ippatsu: additional_han += 1 config = HandConfig( is_riichi=call_riichi, player_wind=self.player.player_wind, round_wind=self.player.table.round_wind_tile, is_tsumo=is_tsumo, options=OptionalRules( has_aka_dora=self.player.table.has_aka_dora, has_open_tanyao=self.player.table.has_open_tanyao, has_double_yakuman=False, ), is_chankan=is_chankan, is_ippatsu=is_ippatsu, is_haitei=is_tsumo and is_haitei or False, is_houtei=(not is_tsumo) and is_haitei or False, tsumi_number=self.player.table.count_of_honba_sticks, kyoutaku_number=self.player.table.count_of_riichi_sticks, ) return self._estimate_hand_value_or_get_from_cache( win_tile_136, tiles, call_riichi, is_tsumo, additional_han, config)
def _make_hand_config(self, is_tsumo=False, is_riichi=False, is_ippatsu=False, is_rinshan=False, is_chankan=False, is_haitei=False, is_houtei=False, is_daburu_riichi=False, is_nagashi_mangan=False, is_tenhou=False, is_renhou=False, is_chiihou=False, player_wind=None, round_wind=None, has_open_tanyao=False, has_aka_dora=False, disable_double_yakuman=False, renhou_as_yakuman=False, allow_daisharin=False, allow_daisharin_other_suits=False): options = OptionalRules( has_open_tanyao=has_open_tanyao, has_aka_dora=has_aka_dora, has_double_yakuman=not disable_double_yakuman, renhou_as_yakuman=renhou_as_yakuman, has_daisharin=allow_daisharin, has_daisharin_other_suits=allow_daisharin_other_suits) return HandConfig(is_tsumo=is_tsumo, is_riichi=is_riichi, is_ippatsu=is_ippatsu, is_rinshan=is_rinshan, is_chankan=is_chankan, is_haitei=is_haitei, is_houtei=is_houtei, is_daburu_riichi=is_daburu_riichi, is_nagashi_mangan=is_nagashi_mangan, is_tenhou=is_tenhou, is_renhou=is_renhou, is_chiihou=is_chiihou, player_wind=player_wind, round_wind=round_wind, options=options)
def estimate_hand_value_or_get_from_cache(self, win_tile_34, tiles=None, call_riichi=False, is_tsumo=False, is_rinshan=False, is_chankan=False): win_tile_136 = win_tile_34 * 4 # we don't need to think, that our waiting is aka dora if win_tile_136 in AKA_DORA_LIST: win_tile_136 += 1 if not tiles: tiles = self.player.tiles[:] else: tiles = tiles[:] tiles += [win_tile_136] config = HandConfig( is_riichi=call_riichi, player_wind=self.player.player_wind, round_wind=self.player.table.round_wind_tile, is_tsumo=is_tsumo, is_rinshan=is_rinshan, is_chankan=is_chankan, options=OptionalRules( has_aka_dora=self.player.table.has_aka_dora, has_open_tanyao=self.player.table.has_open_tanyao, has_double_yakuman=False, ), tsumi_number=self.player.table.count_of_honba_sticks, kyoutaku_number=self.player.table.count_of_riichi_sticks, ) return self._estimate_hand_value_or_get_from_cache( win_tile_136, tiles, call_riichi, is_tsumo, 0, config, is_rinshan, is_chankan)
def test_kokushi_musou_multiple_yakuman(self): hand_calculator = HandCalculator() # kokushi test tiles = TilesConverter.string_to_136_array(sou="19", pin="19", man="19", honors="12345677") win_tile = TilesConverter.string_to_136_array(honors="1")[0] hand_config = HandConfig(is_tsumo=True, is_tenhou=False, is_chiihou=False) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 1) self.assertTrue(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertFalse( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 13) hand_config = HandConfig(is_tsumo=True, is_tenhou=True, is_chiihou=False) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 2) self.assertTrue(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertFalse( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertTrue(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 26) hand_config = HandConfig(is_tsumo=True, is_tenhou=False, is_chiihou=True) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 2) self.assertTrue(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertFalse( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertTrue(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 26) # double kokushi test tiles = TilesConverter.string_to_136_array(sou="19", pin="19", man="19", honors="12345677") win_tile = TilesConverter.string_to_136_array(honors="7")[0] hand_config = HandConfig(is_tsumo=True, is_tenhou=False, is_chiihou=False) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 1) self.assertFalse(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 26) hand_config = HandConfig(is_tsumo=True, is_tenhou=True, is_chiihou=False) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 2) self.assertFalse(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertTrue(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 39) hand_config = HandConfig(is_tsumo=True, is_tenhou=False, is_chiihou=True) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 2) self.assertFalse(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertTrue(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 39) hand_config = HandConfig(is_tsumo=False, is_renhou=True, options=OptionalRules(renhou_as_yakuman=True)) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 2) self.assertFalse(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.renhou_yakuman in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 39) hand_config = HandConfig( is_tsumo=False, is_renhou=True, is_riichi=True, is_open_riichi=True, options=OptionalRules(renhou_as_yakuman=True, has_sashikomi_yakuman=True), ) hand_calculation = hand_calculator.estimate_hand_value( tiles, win_tile, config=hand_config) self.assertIsNone(hand_calculation.error) self.assertEqual(len(hand_calculation.yaku), 3) self.assertFalse(hand_config.yaku.kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.daburu_kokushi in hand_calculation.yaku) self.assertTrue( hand_config.yaku.renhou_yakuman in hand_calculation.yaku) self.assertTrue(hand_config.yaku.sashikomi in hand_calculation.yaku) self.assertFalse(hand_config.yaku.tenhou in hand_calculation.yaku) self.assertFalse(hand_config.yaku.chiihou in hand_calculation.yaku) self.assertEqual(hand_calculation.han, 52)
def score(boxes, tsumo, y_divider, round_wind=None, player_wind=None): """ +---------------+ | _ _ _ _ _ | | |_|_|_|_| |_| | classfied to `open` | | |---------------| <- y_divider | _ _ _ _ _ _ | | |_|_|_|_|_|_| | classfied to `closed` | | +---------------+ boxes: array of box which elements are: tile id, xmin, ymin, xmax and ymax. e.g. [[0, 100, 200, 150, 250], [2, 200, 300, 350, 350], [...]] the right most of the tile is assumed as win tile, and ron or tsumo is specified by tsumo. tile id is: man1...man9: 0...8 pin1...pin9: 9...17 sou1...sou9: 18...26 ton, nan, sha, pei: 27, 28, 29, 30 haku, hatsu, chun: 31, 32, 33 y_divider: tiles are divided into two types; open or closed. if the position is upper than y_divider, the tile is classfied as open. """ open_boxes, win_box, closed_boxes = classify_boxes(boxes, y_divider) if open_boxes is None: return None melds = make_melds(open_boxes) if melds is None: return None # 4-tile-set of kan should be trimed to 3-tile-set. open_kan = [ x.tiles_34[0] for x in melds if x.type == Meld.KAN and x.opened ] open_tiles = boxes_to_tiles(open_boxes, open_kan) if open_tiles is None: return None win_tile = boxes_to_tiles([win_box]) if win_tile is None: return None closed_kan_melds, closed_boxes_replaced = make_closed_kan_melds( closed_boxes) # 4-tile-set of kan should be trimed to 3-tile-set. closed_kan = [x.tiles_34[0] for x in closed_kan_melds] closed_tiles = boxes_to_tiles(closed_boxes_replaced, closed_kan) if closed_tiles is None: return None hand = closed_tiles + open_tiles + win_tile print("win:\n", tc.to_one_line_string(win_tile)) print("hand:\n", tc.to_one_line_string(hand)) print("melds:\n", melds + closed_kan_melds) for meld in melds: print(tc.to_one_line_string(meld.tiles)) options = OptionalRules(has_open_tanyao=True, kazoe_limit=HandConfig.KAZOE_NO_LIMIT) config = HandConfig( is_tsumo=tsumo, player_wind=player_wind, round_wind=round_wind, options=options, ) print("tsumo:", tsumo, " player:", player_wind, " round:", round_wind) result = HandCalculator().estimate_hand_value(hand, win_tile[0], melds=melds + closed_kan_melds, config=config) print_hand_result(result) return result
def maj_cal(data): """{ "tehai":{ "man":"111", "pin":"222", "sou":"333", "honors":"11166" }, "agari":{ "man":"1", "pin":"", "sou":"", "honors":"" }, "wind":{ "round":"1", "player":"1", }, "dora": {"man":"", "pin":"1", "sou":"", "honors":"" }, "kan":[ {"man":"", "pin":"", "sou":"", "honors":"", "open":"" } ], "pon":[ {"man":"", "pin":"", "sou":"", "honors":"" } ], "chi":[ {"man":"", "pin":"", "sou":"", "honors":"" } ], "option":[] }""" print(data) has_aka_dora = False for d_i, d in data.items(): if d_i != "option" and has_aka_dora == False: if type(d) == type({}): for i, v in d.items(): if i != "open" and "r" in v: has_aka_dora = True break elif type(d) == type([]): for d2 in d: for i, v in d2.items(): # print("v",v) if i != "open" and "r" in v: has_aka_dora = True break handconfig = HandConfig( options=OptionalRules(has_open_tanyao=True, has_aka_dora=has_aka_dora)) melds = [] dora_indicators = [] yaku_opened = False if "wind" in data.keys(): handconfig.round_wind = WINDS[int(data["wind"]["round"]) - 1] handconfig.player_wind = WINDS[int(data["wind"]["player"]) - 1] handconfig.is_dealer = handconfig.player_wind == WINDS[0] if "kan" in data.keys() and len(data["kan"]) > 0: for kan in data["kan"]: opened = (kan["open"] in {"1", 1}) melds.append( Meld(meld_type=Meld.KAN, tiles=to_136_array(obj=kan), opened=opened)) if opened: yaku_opened = opened if "pon" in data.keys() and len(data["pon"]) > 0: for pon in data["pon"]: melds.append(Meld(meld_type=Meld.PON, tiles=to_136_array(obj=pon))) yaku_opened = True if "chi" in data.keys() and len(data["chi"]) > 0: for chi in data["chi"]: #配列内をソート for chi_key in chi.keys(): if chi[chi_key] != "": r_flag = False if "r" in chi[chi_key]: r_flag = True chi[chi_key] = chi[chi_key].replace("r", "5") tmp = chi[chi_key] tmp = sorted([tmp[0], tmp[1], tmp[2]]) chi[chi_key] = "".join(tmp) if r_flag: chi[chi_key] = chi[chi_key].replace("5", "r") print(chi[chi_key]) melds.append(Meld(meld_type=Meld.CHI, tiles=to_136_array(obj=chi))) yaku_opened = True if "dora" in data.keys(): dora_indicators = to_136_array(obj=data["dora"]) if "option" in data.keys(): for i in data["option"]: if i in ["tsumo", "ツモ", "つも"]: handconfig.is_tsumo = True elif i in ["riichi", "リーチ", "りーち"]: handconfig.is_riichi = True elif i in ["rinshan", "嶺上", "りんしゃん", "リンシャン"]: handconfig.is_rinshan = True elif i in ["ippatsu", "一発", "いっぱつ", "イッパツ"]: handconfig.is_ippatsu = True elif i in ["chankan", "槍槓", "ちゃんかん", "チャンカン"]: handconfig.is_chankan = True elif i in ["haitei", "海底", "はいてい", "ハイテイ"]: handconfig.is_haitei = True elif i in ["houtei", "河底", "ほうてい", "ホウテイ"]: handconfig.is_houtei = True elif i in ["daburu_riichi", "だぶりー", "ダブリー", "だぶるりーち", "ダブルリーチ"]: handconfig.is_daburu_riichi = True elif i in ["nagashi_mangan", "流しマンガン", "ナガシマンガン", "ながしまんがん"]: handconfig.is_nagashi_mangan = True elif i in ["tenhou", "テンホウ", "てんほう"]: handconfig.is_tenhou = True elif i in ["renhou", "レンホウ", "れんほう"]: handconfig.is_renhou = True elif i in ["chiihou", "ちいほう", "チイホウ"]: handconfig.is_chiihou = True import json #print(json.dumps(data["tehai"], indent=4)) #print(json.dumps(data["agari"], indent=4)) tiles = to_136_array(data["tehai"], has_aka_dora=has_aka_dora) win_tile = to_136_array(data["agari"], has_aka_dora=has_aka_dora)[0] if len(dora_indicators) == []: dora_indicators = None if len(melds) == 0: melds = None result = calculator.estimate_hand_value(tiles, win_tile, melds=melds, dora_indicators=dora_indicators, config=handconfig) return print_hand_result(result, opened=yaku_opened)
tiles = TilesConverter.string_to_136_array(man=Manzu, pin=Pinzu, sou=Sozu, honors=Zihai, has_aka_dora=False) win_tile = TilesConverter.string_to_136_array(man='2')[0] melds = None dora_indicators = None config = HandConfig(is_tsumo=False, is_ippatsu=False, is_rinshan=False, is_chankan=False, is_haitei=False, is_houtei=False, is_daburu_riichi=False, is_nagashi_mangan=False, is_tenhou=False, is_renhou=False, is_chiihou=False, options=OptionalRules( has_open_tanyao=False, has_aka_dora=False, kazoe_limit=HandConfig.KAZOE_LIMITED)) result = calculator.estimate_hand_value(tiles, win_tile, melds, dora_indicators, config) print_hand_result(result)
] tiles = TilesConverter.string_to_136_array(man='22334466557788') win_tile = TilesConverter.string_to_136_array(man='4')[0] result = calculator.estimate_hand_value(tiles, win_tile, dora_indicators=dora_indicators, config=config) print_hand_result(result) #################################################################### # Bug: Yakuman and Non-yakuman Yakus should not add together # #################################################################### config = HandConfig(is_renhou=True, options=OptionalRules(renhou_as_yakuman=True)) # renhou as an yakuman - old style # This should be the correct way to count Renhou as Yakuman dora_indicators = [ TilesConverter.string_to_136_array(man='1')[0], TilesConverter.string_to_136_array(man='1')[0], TilesConverter.string_to_136_array(man='1')[0], TilesConverter.string_to_136_array(man='1')[0] ] tiles = TilesConverter.string_to_136_array(man='22334466557788') win_tile = TilesConverter.string_to_136_array(man='4')[0] result = calculator.estimate_hand_value(tiles, win_tile,
def yaku(self, player, is_tsumo, agari_hai=None, chankan=False): # 手牌 tile_strs = [""] * 4 win_tile_strs = [""] * 4 for hai in player.tehai.hais: tile_strs[hai.kind] += "r" if hai.red else str(hai.num) for furo in player.tehai.furos: for hai in furo.hais: tile_strs[hai.kind] += "r" if hai.red else str(hai.num) if furo.kind == FuroKind.ANKAN or furo.kind == FuroKind.MINKAN or furo.kind == FuroKind.KAKAN: tile_strs[furo.hais[0].kind] = tile_strs[ furo.hais[0].kind][:-1] if is_tsumo: hai = player.tehai.tsumo_hai tile_strs[hai.kind] += "r" if hai.red else str(hai.num) win_tile_strs[hai.kind] += "r" if hai.red else str(hai.num) else: tile_strs[agari_hai.kind] += "r" if agari_hai.red else str( agari_hai.num) win_tile_strs[agari_hai.kind] += "r" if agari_hai.red else str( agari_hai.num) tiles = TilesConverter.string_to_136_array(tile_strs[0], tile_strs[1], tile_strs[2], tile_strs[3], True) win_tile = TilesConverter.string_to_136_array(win_tile_strs[0], win_tile_strs[1], win_tile_strs[2], win_tile_strs[3], True)[0] # 副露 FURO_MELD = { FuroKind.PON: Meld.PON, FuroKind.CHI: Meld.CHI, FuroKind.ANKAN: Meld.KAN, FuroKind.MINKAN: Meld.KAN, FuroKind.KAKAN: Meld.CHANKAN } melds = [] for furo in player.tehai.furos: furo_strs = [""] * 4 for hai in furo.hais: furo_strs[hai.kind] += "r" if hai.red else str(hai.num) meld_tiles = TilesConverter.string_to_136_array( furo_strs[0], furo_strs[1], furo_strs[2], furo_strs[3], True) melds.append( Meld(FURO_MELD[furo.kind], meld_tiles, furo.kind != FuroKind.ANKAN)) # ドラ dora_indicators = [] for hai in self.dora_hais: dora_strs = [""] * 4 dora_strs[hai.kind] += "r" if hai.red else str(hai.num) dora_tile = TilesConverter.string_to_136_array( dora_strs[0], dora_strs[1], dora_strs[2], dora_strs[3], True)[0] dora_indicators.append(dora_tile) if player.richi: for hai in self.uradora_hais: dora_strs = [""] * 4 dora_strs[hai.kind] += "r" if hai.red else str(hai.num) dora_tile = TilesConverter.string_to_136_array( dora_strs[0], dora_strs[1], dora_strs[2], dora_strs[3], True)[0] dora_indicators.append(dora_tile) # 設定 KAZE_WIND = [EAST, SOUTH, WEST, NORTH] config = HandConfig( is_tsumo=is_tsumo, is_riichi=player.richi, is_ippatsu=player.ippatsu, is_rinshan=player.rinshan, is_chankan=chankan, is_haitei=agari_hai is None and self.yama.remain == 0, is_houtei=agari_hai is not None and self.yama.remain == 0, is_daburu_riichi=len(player.kawa.hais) > 0 and player.kawa.hais[0].richi, is_tenhou=agari_hai is None and self.jikaze(player) == 0 and len(player.kawa.hais) == 0, is_renhou=agari_hai is not None and len(player.kawa.hais) == 0, is_chiihou=agari_hai is None and self.jikaze(player) != 0 and len(player.kawa.hais) == 0, player_wind=KAZE_WIND[self.jikaze(player)], round_wind=KAZE_WIND[self.bakaze], options=OptionalRules(has_aka_dora=True)) return self.calculator.estimate_hand_value(tiles, win_tile, melds, dora_indicators, config)
def tsumo(self, draw, game): if draw in winning_tiles(str(self.hand)): calculator = HandCalculator() dora = str(game.dora) if self.in_riichi: dora += str(game.ura_dora) dora_indicators = TilesConverter.one_line_string_to_136_array( dora, has_aka_dora=True) haitei = False tenhou = False chiihou = False if game.wall.remaining == 0: haitei = True if game.tenhou and game.wall.remaining > 65: if self.seat == EAST: tenhou = True else: chiihou = True config = HandConfig(options = OptionalRules(has_open_tanyao = True, has_aka_dora = True),\ is_tsumo = True,\ is_riichi = self.in_riichi,\ is_ippatsu = self.ippatsu,\ is_rinshan = self.rinshan,\ is_haitei = haitei,\ is_daburu_riichi = self.double_riichi,\ is_tenhou = tenhou,\ is_chiihou = chiihou,\ player_wind = self.seat,\ round_wind = game.round_wind\ ) melds = [] meld_string = '' for meld in self.melds.melds: opened = True if len(meld) == 4: meld_type = mjMeld.KAN opened = meld.opened elif meld.tiles.count(meld.tiles[0]) == 3: meld_type = mjMeld.PON else: meld_type = mjMeld.CHI #not sure if the meld_type is necessary, but since it's not a hassle i'll leave it in new_meld = mjMeld(meld_type = meld_type,\ tiles = TilesConverter.one_line_string_to_136_array(str(meld), has_aka_dora = True),\ opened = opened) melds.append(new_meld) #really dumb workaround because the hand is supposed to be exactly 14 tiles #and adding the kan as a string directly to the rest of the hand #causes the hand to exceed 14 tiles #this would subtract by 4 if len(meld) referred to the length of the #string associated with the meld, but len(meld) actually refers #to the number of tiles in the meld (aka it ignores the suit) #so the length of '222p' is 3 and the length of '1111m' is 4 meld_string += str(meld)[len(meld) - 3:] hand = TilesConverter.one_line_string_to_136_array( str(self.hand) + str(draw) + str(meld_string), has_aka_dora=True) draw = TilesConverter.one_line_string_to_136_array( str(draw), has_aka_dora=True)[0] result = calculator.estimate_hand_value(hand, draw, melds = melds, \ dora_indicators = dora_indicators, config = config) if result.yaku and result.cost and not result.error: return result else: return False else: return False
def _make_hand_config( self, is_tsumo=False, is_riichi=False, is_ippatsu=False, is_rinshan=False, is_chankan=False, is_haitei=False, is_houtei=False, is_daburu_riichi=False, is_nagashi_mangan=False, is_tenhou=False, is_renhou=False, is_chiihou=False, player_wind=None, round_wind=None, has_open_tanyao=False, has_aka_dora=False, disable_double_yakuman=False, renhou_as_yakuman=False, allow_daisharin=False, allow_daisharin_other_suits=False, is_open_riichi=False, has_sashikomi_yakuman=False, limit_to_sextuple_yakuman=True, paarenchan_needs_yaku=True, has_daichisei=False, paarenchan=0, ): options = OptionalRules( has_open_tanyao=has_open_tanyao, has_aka_dora=has_aka_dora, has_double_yakuman=not disable_double_yakuman, renhou_as_yakuman=renhou_as_yakuman, has_daisharin=allow_daisharin, has_daisharin_other_suits=allow_daisharin_other_suits, has_daichisei=has_daichisei, has_sashikomi_yakuman=has_sashikomi_yakuman, limit_to_sextuple_yakuman=limit_to_sextuple_yakuman, paarenchan_needs_yaku=paarenchan_needs_yaku, ) return HandConfig( is_tsumo=is_tsumo, is_riichi=is_riichi, is_ippatsu=is_ippatsu, is_rinshan=is_rinshan, is_chankan=is_chankan, is_haitei=is_haitei, is_houtei=is_houtei, is_daburu_riichi=is_daburu_riichi, is_nagashi_mangan=is_nagashi_mangan, is_tenhou=is_tenhou, is_renhou=is_renhou, is_chiihou=is_chiihou, player_wind=player_wind, round_wind=round_wind, is_open_riichi=is_open_riichi, paarenchan=paarenchan, options=options, )
print_hand_result(result) #################################################################### # Add open set to hand # #################################################################### melds = [ Meld(meld_type=Meld.PON, tiles=TilesConverter.string_to_136_array(man='444')) ] result = calculator.estimate_hand_value( tiles, win_tile, melds=melds, config=HandConfig(options=OptionalRules(has_open_tanyao=True))) print_hand_result(result) #################################################################### # Shanten calculation # #################################################################### shanten = Shanten() tiles = TilesConverter.string_to_34_array(man='13569', pin='123459', sou='443') result = shanten.calculate_shanten(tiles) print(result) #################################################################### # Kazoe as a sanbaiman # ####################################################################
def agari_result(self, winner, loser, is_tsumo, tiles, win_tile, is_chankan): logger.info( "{}: {} + {}".format( is_tsumo and "Tsumo" or "Ron", TilesConverter.to_one_line_string(tiles, print_aka_dora=True), TilesConverter.to_one_line_string([win_tile], print_aka_dora=True), ), ) ura_dora = [] number_of_dora_indicators = len(self.dora_indicators) # add one more dora for riichi win if winner.player.in_riichi: # 9 10 11 12 indices for x in range(number_of_dora_indicators): next_indicator_index = 9 + x ura_dora.append(self.dead_wall[next_indicator_index]) is_tenhou = False # tenhou.net doesn't have renhou is_renhou = False is_chiihou = False if not self.players_with_open_hands and len( winner.player.discards) == 0 and is_tsumo: if winner.player.is_dealer: is_tenhou = True else: is_chiihou = True is_haitei = False is_houtei = False if not self.tiles: if is_tsumo: is_haitei = True else: is_houtei = True config = HandConfig( is_riichi=winner.player.in_riichi, player_wind=winner.player.player_wind, round_wind=winner.player.table.round_wind_tile, is_tsumo=is_tsumo, is_tenhou=is_tenhou, is_renhou=is_renhou, is_chiihou=is_chiihou, is_daburu_riichi=winner.is_daburi, is_ippatsu=winner.is_ippatsu, is_haitei=is_haitei, is_houtei=is_houtei, is_rinshan=winner.is_rinshan, is_chankan=is_chankan, options=OptionalRules( has_aka_dora=settings.FIVE_REDS, has_open_tanyao=settings.OPEN_TANYAO, has_double_yakuman=False, ), ) hand_value = self.finished_hand.estimate_hand_value( tiles=tiles + [win_tile], win_tile=win_tile, melds=winner.player.melds, dora_indicators=self.dora_indicators + ura_dora, config=config, ) if hand_value.error: logger.error("Can't estimate a hand: {}. Error: {}".format( TilesConverter.to_one_line_string(tiles + [win_tile], print_aka_dora=True), hand_value.error)) raise ValueError("Not correct hand") logger.info("Dora indicators: {}".format( TilesConverter.to_one_line_string(self.dora_indicators, print_aka_dora=True))) logger.info("Hand yaku: {}".format(", ".join( str(x) for x in hand_value.yaku))) if loser is not None: loser_seat = loser.seat else: # tsumo loser_seat = winner.seat self.replay.win( winner.seat, loser_seat, win_tile, self.honba_sticks, self.riichi_sticks, hand_value.han, hand_value.fu, hand_value.cost, hand_value.yaku, self.dora_indicators, ura_dora, ) riichi_bonus = self.riichi_sticks * 1000 self.riichi_sticks = 0 honba_bonus = self.honba_sticks * 300 # win by ron if loser: scores_to_pay = hand_value.cost["main"] + honba_bonus win_amount = scores_to_pay + riichi_bonus winner.player.scores += win_amount loser.player.scores -= scores_to_pay logger.info("Win: {0} +{1:,d} +{2:,d}".format( winner.player.name, scores_to_pay, riichi_bonus)) logger.info("Lose: {0} -{1:,d}".format(loser.player.name, scores_to_pay)) # win by tsumo else: calculated_cost = hand_value.cost[ "main"] + hand_value.cost["additional"] * 2 win_amount = calculated_cost + riichi_bonus + honba_bonus winner.player.scores += win_amount logger.info("Win: {0} +{1:,d} +{2:,d}".format( winner.player.name, calculated_cost, riichi_bonus + honba_bonus)) for client in self.clients: if client != winner: if client.player.is_dealer: scores_to_pay = hand_value.cost["main"] else: scores_to_pay = hand_value.cost["additional"] scores_to_pay += honba_bonus / 3 client.player.scores -= scores_to_pay logger.info("Lose: {0} -{1:,d}".format( client.player.name, int(scores_to_pay))) return { "winner": winner, "loser": loser, "is_tsumo": is_tsumo, "is_abortive_retake": False }
def win(): req = flask.request.get_json() calculator = HandCalculator() try: tiles = TilesConverter.one_line_string_to_136_array(req["hands"], has_aka_dora=True) except KeyError: return flask.jsonify({"error": "hands required"}), 400 except ValueError: return flask.jsonify({"error": "invalid hands"}), 400 try: win_tile = TilesConverter.one_line_string_to_136_array( req["win_tile"], has_aka_dora=True)[0] except KeyError: return flask.jsonify({"error": "win_tile required"}), 400 except ValueError: return flask.jsonify({"error": "invalid win_tile"}), 400 melds = [] try: melds = req["melds"] except KeyError: pass meld_tiles = [] for meld in melds: try: m = meld["meld"] except KeyError: return flask.jsonify({"error": "meld required"}), 400 try: if m == "chi": meld_tiles.append( Meld( Meld.CHI, TilesConverter.one_line_string_to_136_array( meld["tiles"]))) elif m == "pon": meld_tiles.append( Meld( Meld.PON, TilesConverter.one_line_string_to_136_array( meld["tiles"]))) elif m == "minkan": meld_tiles.append( Meld( Meld.KAN, TilesConverter.one_line_string_to_136_array( meld["tiles"]), True)) elif m == "ankan": meld_tiles.append( Meld( Meld.KAN, TilesConverter.one_line_string_to_136_array( meld["tiles"]), False)) elif m == "kakan": meld_tiles.append( Meld( Meld.CHANKAN, TilesConverter.one_line_string_to_136_array( meld["tiles"]))) else: return flask.jsonify({"error": "invalid meld"}), 400 except KeyError: return flask.jsonify({"error": "meld tiles required"}), 400 except ValueError: return flask.jsonify({"error": "invalid meld tiles"}), 400 try: tsumo = req["tsumo"] except KeyError: tsumo = False try: riichi = req["riichi"] except KeyError: riichi = False try: ippatsu = req["ippatsu"] except KeyError: ippatsu = False try: rinshan = req["rinshan"] except KeyError: rinshan = False try: chankan = req["chankan"] except KeyError: chankan = False try: haitei = req["haitei"] except KeyError: haitei = False try: houtei = req["houtei"] except KeyError: houtei = False try: double_riichi = req["double_riichi"] except KeyError: double_riichi = False try: tenhou = req["tenhou"] except KeyError: tenhou = False try: chiihou = req["chiihou"] except KeyError: chiihou = False try: wind_player = req["wind_player"] if wind_player == "east": wind_player = EAST elif wind_player == "south": wind_player = SOUTH elif wind_player == "west": wind_player = WEST elif wind_player == "north": wind_player = NORTH else: return flask.jsonify({"error": "invalid wind_player"}), 400 except KeyError: return flask.jsonify({"error": "wind_player required"}), 400 try: wind_round = req["wind_round"] if wind_round == "east": wind_round = EAST elif wind_round == "south": wind_round = SOUTH elif wind_round == "west": wind_round = WEST elif wind_round == "north": wind_round = NORTH else: return flask.jsonify({"error": "invalid wind_round"}), 400 except KeyError: return flask.jsonify({"error": "wind_round required"}), 400 try: dora_indicators = TilesConverter.one_line_string_to_136_array( req["dora_indicators"], has_aka_dora=True) except KeyError: return flask.jsonify({"error": "dora_indicators required"}), 400 except ValueError: return flask.jsonify({"error": "invalid dora_indicators"}), 400 option = OptionalRules(has_open_tanyao=True, has_aka_dora=True, has_double_yakuman=False) config = HandConfig(is_tsumo=tsumo, is_riichi=riichi, is_ippatsu=ippatsu, is_rinshan=rinshan, is_chankan=chankan, is_haitei=haitei, is_houtei=houtei, is_daburu_riichi=double_riichi, is_tenhou=tenhou, is_chiihou=chiihou, player_wind=wind_player, round_wind=wind_round, options=option) result = calculator.estimate_hand_value(tiles, win_tile, dora_indicators=dora_indicators, config=config) if result.error: return flask.jsonify({"error": result.error}), 400 yaku = map(lambda y: y.japanese, result.yaku) return flask.jsonify({ "cost": result.cost, "han": result.han, "fu": result.fu, "yaku": list(yaku), "error": None })
def maj_cal(te_hai): #te_hai = input("てはい>>") #p:1 s:1 m:1 j:東南西北撥白中 a:p1 b:東 k:東 tumo ron kan:1111 tehai_list = {"man":None,"pin":None,"sou":None,"honors":None} agarihai_list = {"man":None,"pin":None,"sou":None,"honors":None} handconfig = HandConfig(options=OptionalRules(has_open_tanyao=True,has_aka_dora=True)) melds = [] dora_indicators = [] for i in te_hai.split(): if ":" in i: tmp = i.split(":") if tmp[0] == "p": #ピンズの手牌設定 p:123456789r tehai_list["pin"] = tmp[1] elif tmp[0] == "s": #ソウズの手牌設定 s:123456789r tehai_list["sou"] = tmp[1] elif tmp[0] == "m": #マンズの手牌設定 m:123456789r tehai_list["man"] = tmp[1] elif tmp[0] == "j": #字牌の手牌設定 j:123456789r tehai_list["honors"] = to_honors(tmp[1]) elif tmp[0] == "a": #上がり牌 a:p1 if tmp[1][0] == "p": agarihai_list["pin"] = tmp[1][1] elif tmp[1][0] == "s": agarihai_list["sou"] = tmp[1][1] elif tmp[1][0] == "m": agarihai_list["man"] = tmp[1][1] elif tmp[1][0] == "j": agarihai_list["honors"] = to_honors(tmp[1][1]) elif tmp[0] == "b": #場風 j:東 handconfig.round_wind=WINDS[int(to_honors(tmp[1]))-1] elif tmp[0] == "k": #自風 k:東 handconfig.player_wind=WINDS[int(to_honors(tmp[1]))-1] elif tmp[0] == "kan": #カン kan:s1111n nのありなしで鳴きを判断 if tmp[1][0] == "p": kan_tiles = to_136_array(pin=tmp[1][1:5]) elif tmp[1][0] == "s": kan_tiles = to_136_array(sou=tmp[1][1:5]) elif tmp[1][0] == "m": kan_tiles = to_136_array(man=tmp[1][1:5]) elif tmp[1][0] == "j": kan_tiles = to_136_array(honors=to_honors(tmp[1][1:5])) if tmp[1][-1] == "n": melds.append(Meld(meld_type=Meld.KAN, tiles=kan_tiles, opened=True)) else: melds.append(Meld(meld_type=Meld.KAN, tiles=kan_tiles, opened=False)) # elif tmp[0] == "chankan": #チャンカン # if tmp[1][0] == "p": chankan_tiles = to_136_array(pin=tmp[1][1:5]) # elif tmp[1][0] == "s": chankan_tiles = to_136_array(sou=tmp[1][1:5]) # elif tmp[1][0] == "m": chankan_tiles = to_136_array(man=tmp[1][1:5]) # elif tmp[1][0] == "j": chankan_tiles = to_136_array(honors=to_honors(tmp[1][1:5])) # melds.append(Meld(meld_type=Meld.CHANKAN, tiles=chankan_tiles)) elif tmp[0] == "pon": #ポン pon:s111 if tmp[1][0] == "p": pon_tiles = to_136_array(pin=tmp[1][1:4]) elif tmp[1][0] == "s": pon_tiles = to_136_array(sou=tmp[1][1:4]) elif tmp[1][0] == "m": pon_tiles = to_136_array(man=tmp[1][1:4]) elif tmp[1][0] == "j": pon_tiles = to_136_array(honors=to_honors(tmp[1][1:4])) melds.append(Meld(meld_type=Meld.PON, tiles=pon_tiles)) elif tmp[0] == "chi": #チー chi:s111 if tmp[1][0] == "p": chi_tiles = to_136_array(pin=tmp[1][1:4]) elif tmp[1][0] == "s": chi_tiles = to_136_array(sou=tmp[1][1:4]) elif tmp[1][0] == "m": chi_tiles = to_136_array(man=tmp[1][1:4]) elif tmp[1][0] == "j": chi_tiles = to_136_array(honors=to_honors(tmp[1][1:4])) melds.append(Meld(meld_type=Meld.CHI, tiles=chi_tiles)) elif tmp[0] == "dora": #ドラ dora:s1s1s1 for dora_i in range(0,len(tmp[1]),2): if tmp[1][dora_i] == "p": dora_tiles = to_136_array(pin=tmp[1][dora_i+1]) elif tmp[1][dora_i] == "s": dora_tiles = to_136_array(sou=tmp[1][dora_i+1]) elif tmp[1][dora_i] == "m": dora_tiles = to_136_array(man=tmp[1][dora_i+1]) elif tmp[1][dora_i] == "j": dora_tiles = to_136_array(honors=to_honors(tmp[1][dora_i+1])) dora_indicators.append(dora_tiles[0]) else: if i in ["tumo", "ツモ", "つも"]: handconfig.is_tsumo =True elif i in ["riichi", "リーチ", "りーち"]: handconfig.is_riichi =True elif i in ["rinshan", "嶺上", "りんしゃん", "リンシャン"]: handconfig.is_rinshan=True elif i in ["ippatsu", "一発", "いっぱつ", "イッパツ"]: handconfig.is_ippatsu=True elif i in ["chankan", "槍槓", "ちゃんかん", "チャンカン"]: handconfig.is_chankan=True elif i in ["haitei", "海底", "はいてい", "ハイテイ"]: handconfig.is_haitei=True elif i in ["houtei", "河底", "ほうてい", "ホウテイ"]: handconfig.is_houtei=True elif i in ["だぶりー", "ダブリー", "だぶるりーち", "ダブルリーチ"]: handconfig.is_daburu_riichi=True elif i in ["流しマンガン", "ナガシマンガン", "ながしまんがん"]: handconfig.is_nagashi_mangan=True elif i in ["テンホウ", "てんほう"]: handconfig.is_tenhou=True elif i in ["レンホウ", "れんほう"]: handconfig.is_renhou=True elif i in ["ちいほう", "チイホウ"]: handconfig.is_chiihou=True import json print(json.dumps(tehai_list, indent=4)) print(json.dumps(agarihai_list, indent=4)) tiles = to_136_array(tehai_list, has_aka_dora=True) win_tile = to_136_array(agarihai_list, has_aka_dora=True)[0] if len(dora_indicators) == []: dora_indicators = None if len(melds) == 0: melds = None result = calculator.estimate_hand_value(tiles, win_tile, melds=melds, dora_indicators=dora_indicators, config=handconfig) return print_hand_result(result)
# -*- coding: utf-8 -*- import numpy as np import copy from mahjong.shanten import Shanten from mahjong.tile import TilesConverter from mahjong.hand_calculating.hand import HandCalculator from mahjong.hand_calculating.hand_config import HandConfig from mahjong.meld import Meld from mahjong.agari import Agari from mahjong.hand_calculating.hand_config import OptionalRules tenhou_option = OptionalRules(has_open_tanyao=True, has_aka_dora=True, has_double_yakuman=False) def softmax(x): probs = np.exp(x - np.max(x)) probs /= np.sum(probs) return probs def tile_type(x): if x < 9: return 0 if x < 18: return 1 if x < 27: return 2 return 3