Example #1
0
def test_open_suit_same_shanten():
    table = Table()
    player = table.player
    player.scores = 25000
    table.count_of_remaining_tiles = 100

    tiles = string_to_136_array(man="1134556", pin="3", sou="78", honors="777")
    player.init_hand(tiles)

    meld = make_meld(MeldPrint.CHI, man="345")
    player.add_called_meld(meld)

    strategy = HonitsuStrategy(BaseStrategy.HONITSU, player)
    assert strategy.should_activate_strategy(player.tiles) is True

    tile = string_to_136_tile(man="1")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is not None
    assert tiles_to_string(meld.tiles) == "111m"
Example #2
0
    def determine_strategy(self, tiles_136, meld_tile=None):
        # for already opened hand we don't need to give up on selected strategy
        if self.player.is_open_hand and self.current_strategy:
            return False

        old_strategy = self.current_strategy
        self.current_strategy = None

        # order is important, we add strategies with the highest priority first
        strategies = []

        if self.player.table.has_open_tanyao:
            strategies.append(TanyaoStrategy(BaseStrategy.TANYAO, self.player))

        strategies.append(YakuhaiStrategy(BaseStrategy.YAKUHAI, self.player))
        strategies.append(HonitsuStrategy(BaseStrategy.HONITSU, self.player))
        strategies.append(ChinitsuStrategy(BaseStrategy.CHINITSU, self.player))

        strategies.append(
            FormalTempaiStrategy(BaseStrategy.FORMAL_TEMPAI, self.player))
        strategies.append(
            CommonOpenTempaiStrategy(BaseStrategy.COMMON_OPEN_TEMPAI,
                                     self.player))

        for strategy in strategies:
            if strategy.should_activate_strategy(tiles_136,
                                                 meld_tile=meld_tile):
                self.current_strategy = strategy
                break

        if self.current_strategy and (
                not old_strategy
                or self.current_strategy.type != old_strategy.type):
            self.player.logger.debug(
                log.STRATEGY_ACTIVATE,
                context=self.current_strategy,
            )

        if not self.current_strategy and old_strategy:
            self.player.logger.debug(log.STRATEGY_DROP, context=old_strategy)

        return self.current_strategy and True or False
Example #3
0
def test_suitable_tiles():
    table = Table()
    player = table.player
    strategy = HonitsuStrategy(BaseStrategy.HONITSU, player)

    tiles = string_to_136_array(sou="12355", man="238", honors="23455")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is True

    tile = string_to_136_tile(man="1")
    assert strategy.is_tile_suitable(tile) is False

    tile = string_to_136_tile(pin="1")
    assert strategy.is_tile_suitable(tile) is False

    tile = string_to_136_tile(sou="1")
    assert strategy.is_tile_suitable(tile) is True

    tile = string_to_136_tile(honors="1")
    assert strategy.is_tile_suitable(tile) is True
Example #4
0
def test_should_activate_strategy():
    table = Table()
    player = table.player
    strategy = HonitsuStrategy(BaseStrategy.HONITSU, player)

    table.add_dora_indicator(string_to_136_tile(pin="1"))
    table.add_dora_indicator(string_to_136_tile(honors="5"))

    tiles = string_to_136_array(sou="12355", man="12389", honors="123")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # many tiles in one suit and yakuhai pair, but still many useless winds
    tiles = string_to_136_array(sou="12355", man="23", pin="68", honors="2355")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # many tiles in one suit and yakuhai pair and another honor pair, so
    # now this is honitsu
    tiles = string_to_136_array(sou="12355", man="238", honors="22355")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is True

    # same conditions, but ready suit with dora in another suit, so no honitsu
    tiles = string_to_136_array(sou="12355", pin="234", honors="22355")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # same conditions, but we have a pon of yakuhai doras, we shouldn't
    # force honitsu with this hand
    tiles = string_to_136_array(sou="12355", pin="238", honors="22666")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # if we have a complete set with dora, we shouldn't go for honitsu
    tiles = string_to_136_array(sou="11123688", pin="123", honors="55")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # even if the set may be interpreted as two forms
    tiles = string_to_136_array(sou="1223688", pin="2334", honors="55")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # even if the set may be interpreted as two forms v2
    tiles = string_to_136_array(sou="1223688", pin="2345", honors="55")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False

    # if we have a long form with dora, we shouldn't go for honitsu
    tiles = string_to_136_array(sou="1223688", pin="2333", honors="55")
    player.init_hand(tiles)
    assert strategy.should_activate_strategy(player.tiles) is False
    def should_activate_strategy(self, tiles_136, meld_tile=None):
        """
        We can go for chinitsu strategy if we have prevalence of one suit
        """

        result = super(ChinitsuStrategy,
                       self).should_activate_strategy(tiles_136)
        if not result:
            return False

        # when making decisions about chinitsu, we should consider
        # the state of our own hand,
        tiles_34 = TilesConverter.to_34_array(self.player.tiles)
        suits = count_tiles_by_suits(tiles_34)

        suits = [x for x in suits if x["name"] != "honor"]
        suits = sorted(suits, key=lambda x: x["count"], reverse=True)
        suit = suits[0]

        count_of_shuntsu_other_suits = 0
        count_of_koutsu_other_suits = 0

        count_of_shuntsu_other_suits += HonitsuStrategy._count_of_shuntsu(
            tiles_34, suits[1]["function"])
        count_of_shuntsu_other_suits += HonitsuStrategy._count_of_shuntsu(
            tiles_34, suits[2]["function"])

        count_of_koutsu_other_suits += HonitsuStrategy._count_of_koutsu(
            tiles_34, suits[1]["function"])
        count_of_koutsu_other_suits += HonitsuStrategy._count_of_koutsu(
            tiles_34, suits[2]["function"])

        # we need to have at least 9 tiles of one suit to fo for chinitsu
        if suit["count"] < 9:
            return False

        # here we only check doras in different suits, we will deal
        # with honors later
        self._initialize_chinitsu_dora_count(tiles_136, suit)

        # 3 non-isolated doras in other suits is too much
        # to even try
        if self.dora_count_not_suitable >= 3:
            return False

        if self.dora_count_not_suitable == 2:
            # 2 doras in other suits, no doras in our suit
            # let's not consider chinitsu
            if self.dora_count_suitable == 0:
                return False

            # we have 2 doras in other suits and we
            # are 1 shanten, let's not rush chinitsu
            if self.player.ai.shanten == 1:
                return False

            # too late to get rid of doras in other suits
            if self.player.round_step > 8:
                return False

        # we are almost tempai, chinitsu is slower
        if suit["count"] == 9 and self.player.ai.shanten == 1:
            return False

        # only 10 tiles by 9th turn is too slow, considering alternative
        if suit["count"] == 10 and self.player.ai.shanten == 1 and self.player.round_step > 8:
            return False

        # only 11 tiles or less by 12th turn is too slow, considering alternative
        if suit["count"] <= 11 and self.player.round_step > 11:
            return False

        # if we have a pon of honors, let's not go for chinitsu
        honor_pons = len(
            [x for x in range(0, 34) if is_honor(x) and tiles_34[x] >= 3])
        if honor_pons >= 1:
            return False

        # if we have a valued pair, let's not go for chinitsu
        valued_pairs = len(
            [x for x in self.player.valued_honors if tiles_34[x] == 2])
        if valued_pairs >= 1:
            return False

        # if we have a pair of honor doras, let's not go for chinitsu
        honor_doras_pairs = len([
            x for x in range(0, 34) if is_honor(x) and tiles_34[x] == 2
            and plus_dora(x * 4, self.player.table.dora_indicators)
        ])
        if honor_doras_pairs >= 1:
            return False

        # if we have a honor pair, we will only throw them away if it's early in the game
        # and if we have lots of tiles in our suit
        honor_pairs = len(
            [x for x in range(0, 34) if is_honor(x) and tiles_34[x] == 2])
        if honor_pairs >= 2:
            return False
        if honor_pairs == 1:
            if suit["count"] < 11:
                return False
            if self.player.round_step > 8:
                return False

        # if we have a complete set in other suits, we can only throw it away if it's early in the game
        if count_of_shuntsu_other_suits + count_of_koutsu_other_suits >= 1:
            # too late to throw away chi after 8 step
            if self.player.round_step > 8:
                return False

            # already 1 shanten, no need to throw away complete set
            if self.player.round_step > 5 and self.player.ai.shanten == 1:
                return False

            # dora is not isolated and we have a complete set, let's not go for chinitsu
            if self.dora_count_not_suitable >= 1:
                return False

        self.chosen_suit = suit["function"]

        return True