Exemplo n.º 1
0
def hand_calculator(tiles, win_tile, config=HandConfig()):
    calculator = HandCalculator()
    tiles = TilesConverter.one_line_string_to_136_array(str(tiles),
                                                        has_aka_dora=True)
    win_tile = TilesConverter.one_line_string_to_136_array(
        str(win_tile), has_aka_dora=True)[0]
    return calculator.estimate_hand_value(tiles, win_tile, config=config)
Exemplo n.º 2
0
    def test_one_line_string_to_136_array(self):
        initial_string = '789m456p555s11222z'
        tiles = TilesConverter.one_line_string_to_136_array(initial_string)
        self.assertEqual(len(tiles), 14)

        new_string = TilesConverter.to_one_line_string(tiles)
        self.assertEqual(initial_string, new_string)
Exemplo n.º 3
0
def getTile(s: str) -> dict:
    #translate s into supported format
    if len(s) == 0:
        return {}
    tiles = TilesConverter.one_line_string_to_136_array(s, True)
    test = {}
    # check tiles length
    added = []
    if len(tiles) % 3 == 0:
        #3n, add a random tile
        while True:
            tmp = randint(0, 135)
            if tmp not in tiles:
                tiles.append(tmp)
                added.append(tmp)
                break
    if len(tiles) % 3 == 1:
        #3n+1, add a random tile
        while True:
            tmp = randint(0, 135)
            if tmp not in tiles:
                tiles.append(tmp)
                added.append(tmp)
                break
    if len(added) > 0:
        test[-1] = added
    # now is a normal form
    tiles.sort()
    avaliable = []
    for i in range(0, 136):
        if i not in tiles:
            avaliable.append(i)
    calculator = Shanten()
    baseShanten = calculator.calculate_shanten(
        TilesConverter.to_34_array(tiles))
    if baseShanten == -1:
        return {-2: '已和牌'}
    #14*122 try

    tmp = copy.deepcopy(tiles)
    for t in tiles:
        tmp.remove(t)
        one_try = []
        for i in avaliable:
            tmp.append(i)
            res = calculator.calculate_shanten(
                TilesConverter.to_34_array(sorted(tmp)))
            if res < baseShanten:
                one_try.append(i)
            tmp.remove(i)
        t = 4 * (t // 4)
        if len(one_try) > 0 and t not in test.keys():
            test[t] = copy.deepcopy(one_try)
        tmp.append(t)
    return test
Exemplo n.º 4
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
    })
Exemplo n.º 5
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