Пример #1
0
    def test_atodzuke_keep_yakuhai_wait(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))

        tiles = self._string_to_136_array(man='11144',
                                          sou='567',
                                          pin='567',
                                          honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        # two of 4 man tiles are already out, so it would seem our wait is worse, but we know
        # we must keep two pairs in order to be atodzuke tempai
        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        player.draw_tile(self._string_to_136_tile(man='2'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '2m')
Пример #2
0
    def test_choose_1_shanten_with_cost_possibility_meld(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(man='557',
                                          pin='468',
                                          sou='55577',
                                          honors='66')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, sou='555')
        player.add_called_meld(meld)

        tile = self._string_to_136_tile(sou='7')
        meld, discard_option = player.try_to_call_meld(tile, False)
        self.assertNotEqual(meld, None)
        self.assertEqual(meld.type, Meld.PON)
        self.assertEqual(self._to_string(meld.tiles), '777s')

        self.assertNotEqual(player.ai.current_strategy, None)
        self.assertEqual(player.ai.current_strategy.type, BaseStrategy.YAKUHAI)

        discarded_tile = discard_option.find_tile_in_hand(player.closed_hand)

        self.assertEqual(self._to_string([discarded_tile]), '7m')
Пример #3
0
    def test_keep_only_yakuhai_pair(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))
        table.add_dora_indicator(self._string_to_136_tile(man='3'))

        table.add_discarded_tile(1, self._string_to_136_tile(honors='7'),
                                 False)

        tiles = self._string_to_136_array(man='11144',
                                          sou='567',
                                          pin='156',
                                          honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        player.draw_tile(self._string_to_136_tile(pin='1'))
        discarded_tile = player.discard_tile()
        self.assertNotEqual(self._to_string([discarded_tile]), '7z')
Пример #4
0
def test_dont_open_bad_hand_if_there_are_expensive_threat():
    table = Table()
    table.add_dora_indicator(string_to_136_tile(man="4"))
    player = table.player
    player.round_step = 10
    table.has_open_tanyao = True
    table.has_aka_dora = True

    enemy_seat = 1
    table.add_called_riichi_step_one(enemy_seat)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(honors="4"), True)

    tiles = string_to_136_array(sou="226", pin="2469", man="3344",
                                honors="4") + [FIVE_RED_MAN]
    player.init_hand(tiles)

    # cheap enemy tempai, but this meld is garbage, let's not push
    tile = string_to_136_array(man="4444")[2]
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is None

    # cheap enemy tempai, and good chi, let's take this meld
    tile = string_to_136_tile(man="2")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is not None

    table.add_called_meld(
        enemy_seat, make_meld(MeldPrint.KAN, is_open=False, honors="1111"))
    # enemy hand is more expensive now (12000)
    # in this case let's not open this hand
    tile = string_to_136_tile(man="2")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is None
def test_atodzuke_dont_open_no_yaku_tempai():
    # make sure yakuhai strategy is activated by adding 3 doras to the hand
    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(man="9"))

    tiles = string_to_136_array(man="111445", sou="567", pin="56", honors="77")
    player.init_hand(tiles)

    meld = make_meld(MeldPrint.PON, man="111")
    player.add_called_meld(meld)

    # 6 man is bad meld, we lose our second pair and so is 4 man
    tile = string_to_136_tile(man="6")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is None

    strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
    assert strategy.should_activate_strategy(player.tiles) is True

    tile = string_to_136_tile(man="4")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is None

    strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
    assert strategy.should_activate_strategy(player.tiles) is True

    # 7 pin is a good meld, we get to tempai keeping yakuhai wait
    tile = string_to_136_tile(pin="7")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is not None

    strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
    assert strategy.should_activate_strategy(player.tiles) is True
Пример #6
0
def test_must_push_1st_and_4th_place_riichi():
    table = Table()
    player = table.player
    table.has_aka_dora = True
    table.has_open_tanyao = True
    # orasu
    table.round_wind_number = 7
    table.dealer_seat = 1
    player.dealer_seat = 1

    table.add_dora_indicator(string_to_136_tile(sou="1"))

    # we have 1-shanten with no doras, but we must push because we have 4th place in oorasu
    tiles = string_to_136_array(man="3488", sou="334678", pin="456")
    table.player.init_hand(tiles)
    table.player.round_step = 5

    player.scores = 45000
    assert table.players[0] == player
    table.players[1].scores = 42000
    table.players[2].scores = 5000
    table.players[3].scores = 8000

    enemy_seat = 3
    table.add_called_riichi_step_one(enemy_seat)

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 1

    assert not player.ai.placement.must_push(threatening_players, 0, 1)
Пример #7
0
def test_calculate_our_hand_cost_1_shanten():
    table = Table()
    player = table.player
    enemy_seat = 2

    table.has_open_tanyao = True
    table.has_aka_dora = False

    table.add_called_riichi_step_one(enemy_seat)

    tiles = string_to_136_array(sou="22245677", pin="145", man="67")

    tile = string_to_136_tile(honors="1")
    player.init_hand(tiles)
    player.add_called_meld(make_meld(MeldPrint.PON, sou="222"))
    player.draw_tile(tile)

    discard_option = find_discard_option(player, honors="1")
    cost = discard_option.average_second_level_cost

    assert cost == 1500

    table.add_dora_indicator(string_to_136_tile(sou="6"))
    discard_option = find_discard_option(player, honors="1")
    cost = discard_option.average_second_level_cost

    assert cost == 5850

    table.add_dora_indicator(string_to_136_tile(pin="2"))
    discard_option = find_discard_option(player, honors="1")
    cost = discard_option.average_second_level_cost

    assert cost == 8737
Пример #8
0
def test_discard_tile_and_wrong_tiles_valuation():
    """
    Bot wanted to discard 5m from the first hand,
    because valuation for 2p was miscalculated (too high)

    Same issue with wrong valuation was with second hand
    """
    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(honors="2"))

    tiles = string_to_136_array(man="5", pin="256678", sou="2333467")
    player.init_hand(tiles)

    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "2p"

    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(man="5"))

    tiles = string_to_136_array(man="45667",
                                pin="34677",
                                sou="38",
                                honors="22")
    player.init_hand(tiles)

    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "8s"
Пример #9
0
def test_skip_cheap_meld_1_shanten_can_move_to_west():
    table = Table()
    player = table.player
    table.has_aka_dora = True
    table.has_open_tanyao = True
    # orasu
    table.round_wind_number = 7
    table.dealer_seat = 1
    player.dealer_seat = 1

    table.add_dora_indicator(string_to_136_tile(sou="2"))

    tiles = string_to_136_array(man="3488", sou="334678", pin="268")
    table.player.init_hand(tiles)
    table.player.round_step = 12

    player.scores = 18000
    assert table.players[0] == player
    table.players[1].scores = 28000
    table.players[2].scores = 29000
    table.players[3].scores = 31000

    # it's cheap, but with ron from first place we can move game to west round, so let's do it
    tile = string_to_136_tile(sou="2")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is not None

    # now this is the cost we might win with
    tile = string_to_136_tile(sou="3")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is not None
Пример #10
0
def test_choose_better_tanki_honor():
    table = Table()
    player = table.player
    player.round_step = 2
    player.dealer_seat = 3

    table.add_dora_indicator(string_to_136_tile(man="8"))

    tiles = string_to_136_array(man="11447799", sou="556", honors="45")
    player.init_hand(tiles)
    player.draw_tile(string_to_136_tile(honors="4"))
    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "6s"

    tiles = string_to_136_array(man="11447799", sou="556", honors="45")
    player.init_hand(tiles)
    player.draw_tile(string_to_136_tile(honors="5"))
    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "6s"

    tiles = string_to_136_array(man="11447799", sou="556", honors="45")
    player.init_hand(tiles)
    player.draw_tile(string_to_136_tile(sou="6"))
    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "5z"
Пример #11
0
    def test_discard_tile_and_wrong_tiles_valuation(self):
        """
        Bot wanted to discard 5m from the first hand,
        because valuation for 2p was miscalculated (too high)

        Same issue with wrong valuation was with second hand
        """
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(honors='2'))

        tiles = self._string_to_136_array(man='445567', pin='245678', sou='67')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '2p')

        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='5'))

        tiles = self._string_to_136_array(man='45667',
                                          pin='34677',
                                          sou='38',
                                          honors='22')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '8s')
    def test_choose_better_tanki_honor(self):
        table = Table()
        player = table.player
        player.round_step = 2
        player.dealer_seat = 3

        table.add_dora_indicator(self._string_to_136_tile(man='8'))

        tiles = self._string_to_136_array(man='11447799', sou='556', honors='45')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(honors='4'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '6s')

        tiles = self._string_to_136_array(man='11447799', sou='556', honors='45')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(honors='5'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '6s')

        tiles = self._string_to_136_array(man='11447799', sou='556', honors='45')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='6'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '5z')

        tiles = self._string_to_136_array(man='11447799', sou='556', honors='34')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='6'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '3z')
Пример #13
0
def test_is_threatening_and_toitoi_melds():
    table = Table()

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 0

    enemy_seat = 2
    table.player.round_step = 2
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, pin="222"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, honors="444"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, sou="999"))

    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="5"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="8"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(pin="9"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="4"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="3"), False)

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

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 1
    assert threatening_players[0].enemy.seat == enemy_seat
    assert threatening_players[0].threat_reason[
        "id"] == EnemyDanger.THREAT_EXPENSIVE_OPEN_HAND["id"]
    assert threatening_players[0].get_assumed_hand_cost(
        string_to_136_tile(man="2")) == 8000
    def test_discard_tile_and_wrong_tiles_valuation(self):
        """
        Bot wanted to discard 5m from the first hand,
        because valuation for 2p was miscalculated (too high)

        Same issue with wrong valuation was with second hand
        """
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(honors='2'))

        tiles = self._string_to_136_array(man='445567', pin='245678', sou='67')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '2p')

        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='5'))

        tiles = self._string_to_136_array(man='45667', pin='34677', sou='38', honors='22')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '8s')
Пример #15
0
def test_is_threatening_and_dora_pon():
    table = Table()

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 0

    enemy_seat = 2
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, man="333"))
    table.player.round_step = 7

    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="5"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="8"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(pin="9"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="4"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="7"), False)

    # simple pon it is no threat
    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 0

    # dora pon is threat
    table.add_dora_indicator(string_to_136_tile(man="2"))
    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 1
    assert threatening_players[0].enemy.seat == enemy_seat
    assert threatening_players[0].threat_reason[
        "id"] == EnemyDanger.THREAT_OPEN_HAND_AND_MULTIPLE_DORA["id"]
    assert threatening_players[0].get_assumed_hand_cost(
        string_to_136_tile(man="2")) == 8000
Пример #16
0
def test_skip_cheap_meld_2_shanten():
    table = Table()
    player = table.player
    table.has_aka_dora = True
    table.has_open_tanyao = True
    # orasu
    table.round_wind_number = 7
    table.dealer_seat = 1
    player.dealer_seat = 1

    table.add_dora_indicator(string_to_136_tile(sou="2"))

    tiles = string_to_136_array(man="34889", sou="33468", pin="268")
    table.player.init_hand(tiles)
    table.player.round_step = 12

    player.scores = 18000
    assert table.players[0] == player
    table.players[1].scores = 28000
    table.players[2].scores = 35000
    table.players[3].scores = 40000

    # it's too cheap, let's not open
    tile = string_to_136_tile(sou="2")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is None

    # now this is the cost we might win with
    tile = string_to_136_tile(sou="3")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is not None
    def test_atodzuke_dont_open_no_yaku_tempai(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))

        tiles = self._string_to_136_array(man='111445', sou='567', pin='56', honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        # 6 man is bad meld, we lose our second pair and so is 4 man
        tile = self._string_to_136_tile(man='6')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertEqual(meld, None)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        tile = self._string_to_136_tile(man='4')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertEqual(meld, None)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        # 7 pin is a good meld, we get to tempai keeping yakuhai wait
        tile = self._string_to_136_tile(pin='7')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertNotEqual(meld, None)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)
Пример #18
0
def test_skip_ron_in_west_4():
    table = Table()
    player = table.player
    table.has_aka_dora = True
    table.has_open_tanyao = True
    # orasu
    table.round_wind_number = 11
    table.dealer_seat = 1
    player.dealer_seat = 1

    table.add_dora_indicator(string_to_136_tile(sou="1"))

    tiles = string_to_136_array(man="23488", sou="34678", pin="567")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.CHI, pin="567"))
    table.player.round_step = 14

    player.scores = 20100
    assert table.players[0] == player
    table.players[1].scores = 22000
    table.players[2].scores = 26000
    table.players[3].scores = 29900

    assert player.should_call_win(string_to_136_tile(sou="5"), False, 1)
    assert not player.should_call_win(string_to_136_tile(sou="5"), False, 2)
    assert not player.should_call_win(string_to_136_tile(sou="5"), False, 3)
Пример #19
0
def test_discard_tile_with_better_wait_in_iishanten():
    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(sou="4"))

    tiles = string_to_136_array(man="123567", pin="113788", sou="99")
    player.init_hand(tiles)

    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "8p"
Пример #20
0
def _make_table():
    table = Table()
    table.has_open_tanyao = True

    # add doras so we are sure to go for tanyao
    table.add_dora_indicator(string_to_136_tile(sou="1"))
    table.add_dora_indicator(string_to_136_tile(man="1"))
    table.add_dora_indicator(string_to_136_tile(pin="1"))

    return table
    def test_discard_tile_with_better_wait_in_iishanten(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(man='123567', pin='113788', sou='99')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '8p')
Пример #22
0
    def test_discard_tile_with_better_wait_in_iishanten(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(man='123567', pin='113788', sou='99')
        player.init_hand(tiles)

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '8p')
Пример #23
0
    def test_prefer_valuable_tiles_with_almost_same_tiles_count(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(sou='1366', pin='123456', man='345')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='5'))

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '1s')
Пример #24
0
def test_prefer_valuable_tiles_with_almost_same_ukeire():
    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(sou="4"))

    tiles = string_to_136_array(sou="1366", pin="123456", man="345")
    player.init_hand(tiles)
    player.draw_tile(string_to_136_tile(sou="5"))

    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "1s"
Пример #25
0
def test_discard_tile_with_max_ukeire_second_level():
    table = Table()
    player = table.player
    table.add_dora_indicator(string_to_136_tile(sou="4"))

    tiles = string_to_136_array(sou="11367", pin="45", man="344778")
    player.init_hand(tiles)
    player.draw_tile(string_to_136_tile(pin="6"))

    discarded_tile, _ = player.discard_tile()
    assert tiles_to_string([discarded_tile]) == "3s"
    def test_prefer_valuable_tiles_with_almost_same_ukeire(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(sou='1366', pin='123456', man='345')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='5'))

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '1s')
    def test_discard_tile_with_max_ukeire_second_level(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(sou='11367', pin='45', man='344778')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(pin='6'))

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '3s')
Пример #28
0
    def test_discard_tile_with_max_ukeire_second_level(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(sou='11367', pin='45', man='344778')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(pin='6'))

        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '3s')
    def test_calculate_second_level_ukeire(self):
        """
        There was a bug with 2356 form and second level ukeire
        """
        table = Table()
        player = table.player

        table.add_dora_indicator(self._string_to_136_tile(man='2'))
        table.add_discarded_tile(1, self._string_to_136_tile(man='2'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='3'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='3'), False)

        tiles = self._string_to_136_array(man='34678', pin='2356', sou='4467')
        tile = self._string_to_136_tile(sou='8')

        player.init_hand(tiles)
        player.draw_tile(tile)

        discard_options, _ = player.ai.hand_builder.find_discard_options(
            player.tiles,
            player.closed_hand,
            player.melds
        )

        tile = self._string_to_136_tile(man='4')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 108)

        tile = self._string_to_136_tile(man='3')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 108)

        tile = self._string_to_136_tile(pin='2')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 96)

        tile = self._string_to_136_tile(pin='3')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 96)

        tile = self._string_to_136_tile(pin='5')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 96)

        tile = self._string_to_136_tile(pin='6')
        discard_option = [x for x in discard_options if x.tile_to_discard == tile // 4][0]
        player.ai.hand_builder.calculate_second_level_ukeire(discard_option, player.tiles, player.melds)
        self.assertEqual(discard_option.ukeire_second, 96)
Пример #30
0
def test_get_common_tempai_sanshoku():
    table = Table()

    table.add_dora_indicator(string_to_136_tile(man="8"))

    tiles = string_to_136_array(man="13999", sou="123", pin="12899")
    table.player.init_hand(tiles)

    tile = string_to_136_tile(pin="3")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is not None
    assert tiles_to_string(meld.tiles) == "123p"
Пример #31
0
    def test_should_activate_strategy(self):
        table = Table()
        player = table.player
        strategy = HonitsuStrategy(BaseStrategy.HONITSU, player)

        table.add_dora_indicator(self._string_to_136_tile(pin='1'))
        table.add_dora_indicator(self._string_to_136_tile(honors='5'))

        tiles = self._string_to_136_array(sou='12355', man='12389', honors='123')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)

        # many tiles in one suit and yakuhai pair, but still many useless winds
        tiles = self._string_to_136_array(sou='12355', man='23', pin='68', honors='2355')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)

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

        # same conditions, but ready suit with dora in another suit, so no honitsu
        tiles = self._string_to_136_array(sou='12355', pin='234', honors='22355')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)

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

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

        # even if the set may be interpreted as two forms
        tiles = self._string_to_136_array(sou='1223688', pin='2334', honors='55')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)

        # even if the set may be interpreted as two forms v2
        tiles = self._string_to_136_array(sou='1223688', pin='2345', honors='55')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)

        # if we have a long form with dora, we shouldn't go for honitsu
        tiles = self._string_to_136_array(sou='1223688', pin='2333', honors='55')
        player.init_hand(tiles)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), False)
Пример #32
0
def test_get_common_tempai_sandoko():
    table = Table()

    table.add_dora_indicator(string_to_136_tile(man="1"))

    tiles = string_to_136_array(man="222", sou="2278", pin="222899")
    table.player.init_hand(tiles)

    tile = string_to_136_tile(sou="2")
    meld, _ = table.player.try_to_call_meld(tile, False)
    assert meld is not None
    assert tiles_to_string(meld.tiles) == "222s"
Пример #33
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
Пример #34
0
def test_open_hand_and_not_go_for_atodzuke_yakuhai():
    table = Table()
    # dora here to activate honitsu strategy
    table.add_dora_indicator(string_to_136_tile(sou="9"))
    player = table.player
    player.seat = 1

    tiles = string_to_136_array(sou="1112345678", honors="557")
    player.init_hand(tiles)
    tile = string_to_136_array(sou="1111")[3]
    meld, _ = player.try_to_call_meld(tile, False)
    assert meld is not None
    assert tiles_to_string(meld.tiles) == "111s"
Пример #35
0
def _make_table(dora_indicators=None):
    table = Table()
    table.count_of_remaining_tiles = 60
    table.player.scores = 25000

    # with that we don't have daburi anymore
    table.player.round_step = 1

    if dora_indicators:
        for x in dora_indicators:
            table.add_dora_indicator(x)

    return table
Пример #36
0
    def test_mark_dora_as_dangerous_tile_for_suji(self):
        table = Table()
        table.add_dora_indicator(self._string_to_136_tile(man='8'))

        tiles = self._string_to_136_array(man='112235', pin='4557788')
        table.player.init_hand(tiles)
        # 9 man is dora!
        table.player.draw_tile(self._string_to_136_tile(man='9'))

        table.add_discarded_tile(1, self._string_to_136_tile(man='6'), False)
        table.add_called_riichi(1)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '3m')
    def test_open_hand_when_yakuhai_already_in_the_hand(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(honors='5'))

        tiles = self._string_to_136_array(man='46', pin='4679', sou='1348', honors='666')
        player.init_hand(tiles)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        tile = self._string_to_136_tile(sou='2')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertNotEqual(meld, None)
Пример #38
0
def test_call_shouminkan_and_bad_ukeire_after_call_second_case():
    table = Table()
    table.add_dora_indicator(string_to_136_tile(honors="5"))
    table.count_of_remaining_tiles = 10
    player = table.player

    tiles = string_to_136_array(man="3455567", sou="222", honors="666")
    player.init_hand(tiles)
    player.add_called_meld(make_meld(MeldPrint.PON, man="555"))
    player.add_called_meld(make_meld(MeldPrint.PON, honors="666"))

    tile = string_to_136_array(man="5555")[3]
    player.draw_tile(tile)

    assert player.should_call_kan(tile, False) is None
    def test_discard_tile_based_on_second_level_ukeire_and_cost(self):
        table = Table()
        player = table.player

        table.add_dora_indicator(self._string_to_136_tile(man='2'))
        table.add_discarded_tile(1, self._string_to_136_tile(man='2'), False)

        tiles = self._string_to_136_array(man='34678', pin='2356', sou='4467')
        tile = self._string_to_136_tile(sou='8')

        player.init_hand(tiles)
        player.draw_tile(tile)

        discarded_tile = player.discard_tile()
        discard_correct = self._to_string([discarded_tile]) == '2p' or self._to_string([discarded_tile]) == '3p'
        self.assertEqual(discard_correct, True)
    def test_choose_1_shanten_with_cost_possibility_draw(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(man='557', pin='468', sou='55577', honors='66')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, sou='555')
        player.add_called_meld(meld)

        tile = self._string_to_136_tile(sou='7')
        player.draw_tile(tile)
        discarded_tile = player.discard_tile()
        self.assertNotEqual(player.ai.current_strategy, None)
        self.assertEqual(player.ai.current_strategy.type, BaseStrategy.YAKUHAI)
        self.assertEqual(self._to_string([discarded_tile]), '7m')
    def test_5_pairs_yakuhai_not_chiitoitsu(self):
        table = Table()
        player = table.player

        table.add_dora_indicator(self._string_to_136_tile(sou='9'))
        table.add_dora_indicator(self._string_to_136_tile(sou='1'))

        tiles = self._string_to_136_array(sou='112233', pin='16678', honors='66')
        player.init_hand(tiles)

        tile = self._string_to_136_tile(honors='6')
        meld, _ = player.try_to_call_meld(tile, True)

        self.assertNotEqual(player.ai.current_strategy.type, BaseStrategy.CHIITOITSU)

        self.assertEqual(player.ai.current_strategy.type, BaseStrategy.YAKUHAI)

        self.assertNotEqual(meld, None)
    def test_keep_only_yakuhai_pon(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))
        table.add_dora_indicator(self._string_to_136_tile(man='3'))

        tiles = self._string_to_136_array(man='11144', sou='567', pin='56', honors='777')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        player.draw_tile(self._string_to_136_tile(man='4'))
        discarded_tile = player.discard_tile()
        self.assertNotEqual(self._to_string([discarded_tile]), '7z')
    def test_atodzuke_dont_destroy_second_pair(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))

        tiles = self._string_to_136_array(man='111445', sou='468', pin='56', honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        # 6 man is bad meld, we lose our second pair and so is 4 man
        tile = self._string_to_136_tile(man='6')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertEqual(meld, None)

        tile = self._string_to_136_tile(man='4')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertEqual(meld, None)

        # but if we have backup pair it's ok
        tiles = self._string_to_136_array(man='111445', sou='468', pin='88', honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        # 6 man is bad meld, we lose our second pair and so is 4 man
        tile = self._string_to_136_tile(man='6')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertNotEqual(meld, None)

        tile = self._string_to_136_tile(man='4')
        meld, _ = player.try_to_call_meld(tile, True)
        self.assertNotEqual(meld, None)
    def test_atodzuke_choose_hidden_syanpon(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))

        tiles = self._string_to_136_array(man='111678', sou='56678', honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        for _ in range(0, 4):
            table.add_discarded_tile(1, self._string_to_136_tile(sou='9'), False)

        player.draw_tile(self._string_to_136_tile(man='6'))
        discarded_tile = player.discard_tile()
        self.assertNotEqual(self._to_string([discarded_tile]), '6m')
    def test_discard_less_valuable_isolated_tile_first(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(sou='2456', pin='129', man='234458')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='7'))

        discarded_tile = player.discard_tile()
        # we have a choice what to discard: 9p or 8m
        # 9p is less valuable
        self.assertEqual(self._to_string([discarded_tile]), '9p')

        table.dora_indicators.append(self._string_to_136_tile(pin='8'))
        tiles = self._string_to_136_array(sou='2456', pin='129', man='234458')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='7'))
        discarded_tile = player.discard_tile()
        # but if 9p is dora
        # let's discard 8m instead
        self.assertEqual(self._to_string([discarded_tile]), '8m')
    def test_atodzuke_keep_yakuhai_wait(self):
        # make sure yakuhai strategy is activated by adding 3 doras to the hand
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(man='9'))

        tiles = self._string_to_136_array(man='11144', sou='567', pin='567', honors='77')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, man='111')
        player.add_called_meld(meld)

        # two of 4 man tiles are already out, so it would seem our wait is worse, but we know
        # we must keep two pairs in order to be atodzuke tempai
        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)

        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)
        self.assertEqual(strategy.should_activate_strategy(player.tiles), True)

        player.draw_tile(self._string_to_136_tile(man='2'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '2m')
    def test_choose_1_shanten_with_cost_possibility_meld(self):
        table = Table()
        player = table.player
        table.add_dora_indicator(self._string_to_136_tile(sou='4'))

        tiles = self._string_to_136_array(man='557', pin='468', sou='55577', honors='66')
        player.init_hand(tiles)

        meld = self._make_meld(Meld.PON, sou='555')
        player.add_called_meld(meld)

        tile = self._string_to_136_tile(sou='7')
        meld, discard_option = player.try_to_call_meld(tile, False)
        self.assertNotEqual(meld, None)
        self.assertEqual(meld.type, Meld.PON)
        self.assertEqual(self._to_string(meld.tiles), '777s')

        self.assertNotEqual(player.ai.current_strategy, None)
        self.assertEqual(player.ai.current_strategy.type, BaseStrategy.YAKUHAI)

        discarded_tile = discard_option.find_tile_in_hand(player.closed_hand)

        self.assertEqual(self._to_string([discarded_tile]), '7m')
    def test_choose_correct_wait_yaku_versus_dora(self):
        table = Table()
        player = table.player
        player.round_step = 2

        table.add_dora_indicator(self._string_to_136_tile(pin='4'))

        tiles = self._string_to_136_array(man='23478', sou='23488', pin='235')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(pin='4'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '5p')

        table = Table()
        player = table.player
        player.round_step = 2

        table.add_dora_indicator(self._string_to_136_tile(pin='1'))

        tiles = self._string_to_136_array(man='34578', sou='34588', pin='235')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(pin='4'))
        discarded_tile = player.discard_tile()
        self.assertEqual(self._to_string([discarded_tile]), '2p')
    def test_should_go_for_defence_and_good_hand(self):
        """
        When we have 13 tiles in hand and someone declared a riichi
        """
        table = Table()

        tiles = self._string_to_136_array(sou='234678', pin='34789', man='77')
        table.player.init_hand(tiles)
        table.player.draw_tile(self._string_to_136_tile(man='6'))
        # discard here to reinit shanten number in AI
        table.player.discard_tile()

        self.assertEqual(table.player.ai.defence.should_go_to_defence_mode(), False)

        table.add_called_riichi(3)

        # our hand is in tempai, but it is really cheap
        self.assertEqual(table.player.ai.defence.should_go_to_defence_mode(), True)

        table.add_dora_indicator(self._string_to_136_tile(man='4'))
        table.add_dora_indicator(self._string_to_136_tile(pin='3'))

        # our hand in tempai, and it has a cost, so let's push it
        self.assertEqual(table.player.ai.defence.should_go_to_defence_mode(), False)
class CallRiichiTestCase(unittest.TestCase, TestMixin):
    def _make_table(self, dora_indicators=None):
        self.table = Table()
        self.table.count_of_remaining_tiles = 60
        self.player = self.table.player
        self.player.scores = 25000

        # with that we don't have daburi anymore
        self.player.round_step = 1

        if dora_indicators:
            for x in dora_indicators:
                self.table.add_dora_indicator(x)

    def test_dont_call_riichi_with_yaku_and_central_tanki_wait(self):
        self._make_table()

        tiles = self._string_to_136_array(sou='234567', pin='234567', man='4')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(man='5'))
        self.player.discard_tile()

        self.assertEqual(self.player.can_call_riichi(), False)

    def test_dont_call_riichi_expensive_damaten_with_yaku(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(man='7'),
            self._string_to_136_tile(man='5'),
            self._string_to_136_tile(sou='1'),
        ])

        # tanyao pinfu sanshoku dora 4 - this is damaten baiman, let's not riichi it
        tiles = self._string_to_136_array(man='67888', sou='678', pin='34678')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)

        # let's test lots of doras hand, tanyao dora 8, also damaten baiman
        tiles = self._string_to_136_array(man='666888', sou='22', pin='34678')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)

        # chuuren
        tiles = self._string_to_136_array(man='1112345678999')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)

    def test_riichi_expensive_hand_without_yaku(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(man='1'),
            self._string_to_136_tile(sou='1'),
            self._string_to_136_tile(pin='1')
        ])

        tiles = self._string_to_136_array(man='222', sou='22278', pin='22789')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), True)

    def test_riichi_tanki_honor_without_yaku(self):
        self._make_table(
            dora_indicators=[
                self._string_to_136_tile(man='2'),
                self._string_to_136_tile(sou='6')
            ]
        )

        tiles = self._string_to_136_array(man='345678', sou='789', pin='123', honors='2')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), True)

    def test_riichi_tanki_honor_chiitoitsu(self):
        self._make_table()

        tiles = self._string_to_136_array(man='22336688', sou='99', pin='99', honors='2')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), True)

    def test_always_call_daburi(self):
        self._make_table()
        self.player.round_step = 0

        tiles = self._string_to_136_array(sou='234567', pin='234567', man='4')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(man='5'))
        self.player.discard_tile()

        self.assertEqual(self.player.can_call_riichi(), True)

    def test_dont_call_karaten_tanki_riichi(self):
        self._make_table()

        tiles = self._string_to_136_array(man='22336688', sou='99', pin='99', honors='2')
        self.player.init_hand(tiles)

        for _ in range(0, 3):
            self.table.add_discarded_tile(1, self._string_to_136_tile(honors='2'), False)
            self.table.add_discarded_tile(1, self._string_to_136_tile(honors='3'), False)

        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)

    def test_dont_call_karaten_ryanmen_riichi(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(man='1'),
            self._string_to_136_tile(sou='1'),
            self._string_to_136_tile(pin='1')
        ])

        tiles = self._string_to_136_array(man='222', sou='22278', pin='22789')
        self.player.init_hand(tiles)

        for _ in range(0, 4):
            self.table.add_discarded_tile(1, self._string_to_136_tile(sou='6'), False)
            self.table.add_discarded_tile(1, self._string_to_136_tile(sou='9'), False)

        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)

    def test_call_riichi_penchan_with_suji(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(pin='1'),
        ])

        tiles = self._string_to_136_array(sou='11223', pin='234567', man='66')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(sou='6'))
        self.player.discard_tile()

        self.assertEqual(self.player.can_call_riichi(), True)

    def test_call_riichi_tanki_with_kabe(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(pin='1'),
        ])

        for _ in range(0, 3):
            self.table.add_discarded_tile(1, self._string_to_136_tile(honors='1'), False)

        for _ in range(0, 4):
            self.table.add_discarded_tile(1, self._string_to_136_tile(sou='8'), False)

        tiles = self._string_to_136_array(sou='1119', pin='234567', man='666')
        self.player.init_hand(tiles)
        self.player.draw_tile(self._string_to_136_tile(honors='1'))
        self.player.discard_tile()

        self.assertEqual(self.player.can_call_riichi(), True)

    def test_call_riichi_chiitoitsu_with_suji(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(man='1'),
        ])

        for _ in range(0, 3):
            self.table.add_discarded_tile(1, self._string_to_136_tile(honors='3'), False)

        tiles = self._string_to_136_array(man='22336688', sou='9', pin='99', honors='22')
        self.player.init_hand(tiles)
        self.player.add_discarded_tile(Tile(self._string_to_136_tile(sou='6'), True))

        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), True)

    def test_dont_call_riichi_chiitoitsu_bad_wait(self):
        self._make_table(dora_indicators=[
            self._string_to_136_tile(man='1'),
        ])

        for _ in range(0, 3):
            self.table.add_discarded_tile(1, self._string_to_136_tile(honors='3'), False)

        tiles = self._string_to_136_array(man='22336688', sou='4', pin='99', honors='22')
        self.player.init_hand(tiles)

        self.player.draw_tile(self._string_to_136_tile(honors='3'))
        self.player.discard_tile()
        self.assertEqual(self.player.can_call_riichi(), False)