Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #8
0
    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)
Exemple #10
0
    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)
Exemple #12
0
    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)
Exemple #13
0
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
Exemple #14
0
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)
Exemple #15
0
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)
Exemple #16
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,
                                        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,
Exemple #17
0
    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)
Exemple #18
0
    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
Exemple #19
0
    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,
        )
Exemple #20
0
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                                             #
####################################################################
Exemple #21
0
    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
        }
Exemple #22
0
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
    })
Exemple #23
0
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)
Exemple #24
0
# -*- 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