Exemple #1
0
def test_remaining_tiles_and_opened_meld():
    table = Table()
    player = table.player

    tiles = string_to_136_array(man="123456789", sou="167", honors="77")
    player.init_hand(tiles)

    results, shanten = player.ai.hand_builder.find_discard_options()
    result = [x for x in results if x.tile_to_discard_34 == string_to_34_tile(sou="1")][0]
    assert result.ukeire == 8

    # was discard and set was opened
    tile = string_to_136_tile(sou="8")
    player.table.add_discarded_tile(3, tile, False)
    meld = make_meld(MeldPrint.PON, sou="888")
    meld.called_tile = tile
    player.table.add_called_meld(3, meld)

    results, shanten = player.ai.hand_builder.find_discard_options()
    result = [x for x in results if x.tile_to_discard_34 == string_to_34_tile(sou="1")][0]
    assert result.ukeire == 5

    # was discard and set was opened
    tile = string_to_136_tile(sou="3")
    player.table.add_discarded_tile(2, tile, False)
    meld = make_meld(MeldPrint.PON, sou="345")
    meld.called_tile = tile
    player.table.add_called_meld(2, meld)

    results, shanten = player.ai.hand_builder.find_discard_options()
    result = [x for x in results if x.tile_to_discard_34 == string_to_34_tile(sou="1")][0]
    assert result.ukeire == 4
Exemple #2
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
Exemple #3
0
def test_open_hand_and_discard_tiles_logic_advanced():
    # we should choose between one of the ryanmens to discard
    # in this case - discard the one that leads us to atodzuke and has less tanyao ukeire
    # despite the fact that general ukeire is higher
    table = _make_table()
    table.add_discarded_tile(2, string_to_136_tile(pin="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(pin="7"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="7"), False)

    tiles = string_to_136_array(man="236777", sou="56", pin="22256")
    table.player.init_hand(tiles)
    meld = make_meld(MeldPrint.PON, pin="222")
    table.player.add_called_meld(meld)
    tile = string_to_136_tile(man="6")
    table.player.draw_tile(tile)
    tile_to_discard, _ = table.player.discard_tile()
    assert tiles_to_string([tile_to_discard]) == "2m" or tiles_to_string(
        [tile_to_discard]) == "3m"

    # now same situation, but better ryanmen is no atodzuke
    table = _make_table()
    table.add_discarded_tile(2, string_to_136_tile(pin="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(pin="7"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="7"), False)

    tiles = string_to_136_array(man="346777", sou="56", pin="22256")
    table.player.init_hand(tiles)
    meld = make_meld(MeldPrint.PON, pin="222")
    table.player.add_called_meld(meld)
    tile = string_to_136_tile(man="6")
    table.player.draw_tile(tile)
    tile_to_discard, _ = table.player.discard_tile()
    assert (tiles_to_string([tile_to_discard]) == "5s"
            or tiles_to_string([tile_to_discard]) == "6s"
            or tiles_to_string([tile_to_discard]) == "5p"
            or tiles_to_string([tile_to_discard]) == "6p")

    # now same situation as the first one, but ryanshanten
    table = _make_table()
    table.add_discarded_tile(2, string_to_136_tile(pin="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(pin="7"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="4"), False)
    table.add_discarded_tile(2, string_to_136_tile(sou="7"), False)
    table.add_discarded_tile(2, string_to_136_tile(man="5"), False)
    table.add_discarded_tile(2, string_to_136_tile(man="8"), False)

    tiles = string_to_136_array(man="2367", sou="2356", pin="22256")
    table.player.init_hand(tiles)
    meld = make_meld(MeldPrint.PON, pin="222")
    table.player.add_called_meld(meld)
    tile = string_to_136_tile(man="8")
    table.player.draw_tile(tile)
    tile_to_discard, _ = table.player.discard_tile()
    assert (tiles_to_string([tile_to_discard]) == "2m"
            or tiles_to_string([tile_to_discard]) == "3m"
            or tiles_to_string([tile_to_discard]) == "2s"
            or tiles_to_string([tile_to_discard]) == "3s")
Exemple #4
0
def test_crash_when_tyring_to_open_meld():
    """
    Bot crashed when tried to calculate meld possibility with hand 7m333789s + 3s [222z, 123p]
    This test is checking that there are no crashes in such situations anymore
    """
    # checking a few similar hands here
    # #1
    table = Table()
    # dora here to activate honitsu strategy
    table.add_dora_indicator(string_to_136_tile(sou="9"))
    player = table.player

    tiles = string_to_136_array(sou="1112345678", honors="447")
    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

    # #2
    table = Table()
    # dora here to activate honitsu strategy
    table.add_dora_indicator(string_to_136_tile(sou="9"))
    player = table.player

    tiles = string_to_136_array(sou="11123456789", honors="47")
    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

    # #3
    table = Table()
    # dora here to activate honitsu strategy
    table.add_dora_indicator(string_to_136_tile(sou="9"))
    player = table.player

    tiles = string_to_136_array(sou="111234567", honors="4444")
    player.init_hand(tiles)
    table.add_called_meld(player.seat, make_meld(MeldPrint.PON, honors="444"))
    tile = string_to_136_array(sou="1111")[3]
    meld, _ = player.try_to_call_meld(tile, False)
    assert meld is not None

    # #4 - the original one
    table = Table()
    # dora here to activate yakuhai strategy
    table.add_dora_indicator(string_to_136_tile(sou="2"))
    player = table.player

    tiles = string_to_136_array(man="7", pin="123", sou="333789", honors="111")
    player.init_hand(tiles)
    table.add_called_meld(player.seat, make_meld(MeldPrint.PON, honors="111"))
    table.add_called_meld(player.seat, make_meld(MeldPrint.CHI, pin="123"))
    # it is important for crash to take fourth 3s (with index 83)
    tile = string_to_136_array(sou="3333")[3]
    meld, _ = player.try_to_call_meld(tile, False)
    assert meld is None
Exemple #5
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
Exemple #6
0
def test_shanten_and_hand_structure():
    table = Table()
    player = table.player

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

    tiles = string_to_136_array(man="33344455", pin="34567")
    player.init_hand(tiles)
    player.melds.append(make_meld(MeldPrint.CHI, man="345"))
    player.melds.append(make_meld(MeldPrint.CHI, man="345"))

    closed_hand_34 = TilesConverter.to_34_array(player.closed_hand)

    shanten, _ = player.ai.hand_builder.calculate_shanten_and_decide_hand_structure(closed_hand_34)
    assert shanten == 1
Exemple #7
0
def test_kuikae_simple():
    # case 1: simple chi
    table = _make_table()
    table.add_dora_indicator(string_to_136_tile(pin="2"))
    # but with opened hand we don't need to count not suitable tiles as ukeire
    tiles = string_to_136_array(man="234678", sou="135", pin="3335")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.CHI, man="234"))

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

    # case 2: kuikae
    table = _make_table()
    table.add_dora_indicator(string_to_136_tile(pin="2"))
    # but with opened hand we don't need to count not suitable tiles as ukeire
    tiles = string_to_136_array(man="234678", sou="123", pin="3335")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.CHI, man="234"))

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

    # case 3: no kuikae can be applie to pon
    table = _make_table()
    table.add_dora_indicator(string_to_136_tile(pin="2"))
    # but with opened hand we don't need to count not suitable tiles as ukeire
    tiles = string_to_136_array(man="234678", sou="144", pin="3335")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.CHI, man="234"))

    tile = string_to_136_tile(sou="4")
    meld, _ = table.player.try_to_call_meld(tile, False)
    assert meld is not None

    # case 4: no false kuikae
    table = _make_table()
    table.add_dora_indicator(string_to_136_tile(pin="2"))
    # but with opened hand we don't need to count not suitable tiles as ukeire
    tiles = string_to_136_array(man="234678", sou="237", pin="3335")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.CHI, man="234"))

    tile = string_to_136_tile(sou="4")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is not None
Exemple #8
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
Exemple #9
0
def test_dont_meld_agari():
    """
    We shouldn't open when we are already in tempai expect for some special cases
    """
    table = Table()
    table.player.dealer_seat = 3

    strategy = FormalTempaiStrategy(BaseStrategy.FORMAL_TEMPAI, table.player)

    tiles = string_to_136_array(man="2379", sou="4568", pin="22299")
    table.player.init_hand(tiles)

    # Let's move to 15th round step
    for _ in range(0, 15):
        table.player.add_discarded_tile(Tile(0, False))

    assert strategy.should_activate_strategy(table.player.tiles) is True

    tiles = string_to_136_array(man="23789", sou="456", pin="22299")
    table.player.init_hand(tiles)

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

    tile = string_to_136_tile(man="4")
    meld, _ = table.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
Exemple #11
0
def test_opened_kan_and_threatening_riichi():
    table = Table()
    table.count_of_remaining_tiles = 10

    enemy_seat = 2
    table.add_called_riichi_step_one(enemy_seat)

    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_RIICHI["id"]

    tiles = string_to_136_array(man="2399", sou="111456", honors="111")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.PON, honors="111"))

    # to rebuild all caches
    table.player.draw_tile(string_to_136_tile(pin="9"))
    table.player.discard_tile()

    # our hand is open, in tempai and with a good wait but there is a riichi so calling open kan is a bad idea
    tile = string_to_136_tile(sou="1")
    assert table.player.should_call_kan(tile, True) is None
    assert table.player.try_to_call_meld(tile, True) == (None, None)
Exemple #12
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)
Exemple #13
0
def test_is_threatening_and_atodzuke():
    table = Table()

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

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

    enemy_seat = 2
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.CHI, man="234"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, sou="333"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.KAN, pin="9999"))
    table.player.round_step = 5

    table.add_discarded_tile(enemy_seat, string_to_136_tile(honors="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(honors="4"), 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="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="6"), False)

    # atodzuke with 3 melds is a threat
    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_UNKNOWN_COST["id"]
    assert threatening_players[0].get_assumed_hand_cost(
        string_to_136_tile(honors="5")) == 2000
    assert threatening_players[0].get_assumed_hand_cost(
        string_to_136_tile(honors="6")) == 8000

    for tile_136 in range(0, 136):
        bonus_danger = threatening_players[0].threat_reason.get(
            "active_yaku")[0].get_bonus_danger(tile_136, 1)
        if not is_honor(tile_136 // 4):
            assert not bonus_danger
        elif ((tile_136 // 4 == string_to_34_tile(honors="1"))
              or (tile_136 // 4 == string_to_34_tile(honors="3"))
              or (tile_136 // 4 == string_to_34_tile(honors="5"))
              or (tile_136 // 4 == string_to_34_tile(honors="6"))
              or (tile_136 // 4 == string_to_34_tile(honors="7"))):
            assert bonus_danger
        else:
            assert not bonus_danger
Exemple #14
0
def test_encode_called_ankan():
    meld = make_meld(Meld.KAN, tiles=[72, 73, 74, 75])
    meld.who = 2
    meld.from_who = 2
    meld.called_tile = 74
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "18944"
Exemple #15
0
def test_encode_called_shouminkan():
    meld = make_meld(Meld.SHOUMINKAN, tiles=[112, 113, 115, 114])
    meld.who = 2
    meld.from_who = 3
    meld.called_tile = 114
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "44113"
Exemple #16
0
def test_encode_called_daiminkan():
    meld = make_meld(Meld.KAN, tiles=[100, 101, 102, 103])
    meld.who = 2
    meld.from_who = 3
    meld.called_tile = 103
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "26369"
Exemple #17
0
def test_encode_called_pon():
    meld = make_meld(Meld.PON, tiles=[104, 105, 107])
    meld.who = 0
    meld.from_who = 1
    meld.called_tile = 105
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "40521"

    meld = make_meld(Meld.PON, tiles=[124, 126, 127])
    meld.who = 0
    meld.from_who = 2
    meld.called_tile = 124
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "47658"
Exemple #18
0
def test_encode_called_chi():
    meld = make_meld(Meld.CHI, tiles=[26, 29, 35])
    meld.who = 3
    meld.from_who = 2
    meld.called_tile = 29
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "19895"

    meld = make_meld(Meld.CHI, tiles=[4, 11, 13])
    meld.who = 1
    meld.from_who = 0
    meld.called_tile = 4
    replay = TenhouReplay("", [], "")

    result = replay._encode_meld(meld)
    assert result == "3303"
Exemple #19
0
def test_choose_best_option_with_melds():
    table = Table()
    player = table.player
    table.has_aka_dora = False

    tiles = string_to_136_array(sou="245666789", honors="2266")
    player.init_hand(tiles)

    meld = make_meld(MeldPrint.PON, sou="666")
    player.add_called_meld(meld)
    meld = make_meld(MeldPrint.CHI, sou="789")
    player.add_called_meld(meld)

    player.draw_tile(string_to_136_tile(sou="5"))

    discarded_tile, _ = player.discard_tile()
    # we should discard best ukeire option here - 2s
    assert tiles_to_string([discarded_tile]) == "2s"
Exemple #20
0
def test_is_threatening_and_honitsu_hand():
    table = Table()
    table.add_dora_indicator(string_to_136_tile(pin="1"))

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

    enemy_seat = 1
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, honors="444"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.CHI, pin="123"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.CHI, pin="345"))

    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(sou="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(sou="9"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(man="1"), False)
    table.add_discarded_tile(enemy_seat, string_to_136_tile(pin="1"), False)

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 1
    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(pin="4")) == 3900
    assert threatening_players[0].get_assumed_hand_cost(
        string_to_136_tile(pin="2")) == 8000
    assert HonitsuAnalyzer.id in [
        x.id for x in threatening_players[0].threat_reason["active_yaku"]
    ]

    honitsu_analyzer = [
        x for x in threatening_players[0].threat_reason["active_yaku"]
        if x.id == HonitsuAnalyzer.id
    ][0]

    for tile_136 in range(0, 136):
        bonus_danger = honitsu_analyzer.get_bonus_danger(tile_136, 1)
        if is_honor(tile_136 // 4):
            assert bonus_danger
        else:
            assert not bonus_danger
Exemple #21
0
def test_tile_danger_against_tanyao_threat():
    table = Table()
    player = table.player

    enemy_seat = 2
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, pin="234"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.CHI, sou="333"))
    table.player.round_step = 2
    table.add_dora_indicator(string_to_136_tile(pin="1"))
    table.add_dora_indicator(string_to_136_tile(pin="2"))

    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)

    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 1
    assert threatening_players[0].enemy.seat == enemy_seat

    tiles = string_to_136_array(man="11134", pin="1569", honors="2555")
    tile = string_to_136_tile(sou="4")
    player.init_hand(tiles)
    player.draw_tile(tile)

    _assert_discard(player,
                    enemy_seat,
                    TileDanger.SAFE_AGAINST_THREATENING_HAND,
                    man="1")
    _assert_discard(player,
                    enemy_seat,
                    TileDanger.SAFE_AGAINST_THREATENING_HAND,
                    pin="9")
    _assert_discard(player,
                    enemy_seat,
                    TileDanger.SAFE_AGAINST_THREATENING_HAND,
                    honors="2")
    _assert_discard_not_equal(player,
                              enemy_seat,
                              TileDanger.SAFE_AGAINST_THREATENING_HAND,
                              pin="5")
Exemple #22
0
def test_crash_when_tyring_to_discard_with_open_hand():
    """
    Bot crashed when tried to discard tile from hand 266m4444z + 1z [111z, 789m]
    This test is checking that there are no crashes in such situations anymore
    """
    table = Table()
    player = table.player

    tiles = string_to_136_array(man="266789", honors="1114444")
    player.init_hand(tiles)
    # we manually reveal one tile to emulate the fact that we saw it when it was discarded
    table._add_revealed_tile(string_to_136_tile(honors="1"))
    table.add_called_meld(player.seat, make_meld(MeldPrint.PON, honors="111"))
    table.add_called_meld(player.seat, make_meld(MeldPrint.CHI, man="789"))
    # it is important for crash to take fourth 4z
    tile = string_to_136_array(honors="1111")[3]
    player.draw_tile(tile)
    discard = player.discard_tile()
    assert discard is not None
def test_atodzuke_dont_destroy_second_pair():
    # 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="468", pin="56", honors="77")
    player.init_hand(tiles)

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

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

    # 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

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

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

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

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

    # 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 not None

    tile = string_to_136_tile(man="4")
    meld, _ = player.try_to_call_meld(tile, True)
    assert meld is not None
def test_wrong_shanten_improvements_detection():
    """
    With hand 2345s1p11z bot wanted to open set on 2s,
    so after opened set we will get 25s1p11z
    it is not correct logic, because we ruined our hand
    :return:
    """
    table = Table()

    tiles = string_to_136_array(sou="2345999", honors="114446")
    table.player.init_hand(tiles)

    meld = make_meld(MeldPrint.PON, sou="999")
    table.player.add_called_meld(meld)
    meld = make_meld(MeldPrint.PON, honors="444")
    table.player.add_called_meld(meld)

    tile = string_to_136_array(sou="2222")[1]
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is None
Exemple #25
0
def test_dont_meld_agari():
    table = _make_table()
    tiles = string_to_136_array(man="23567", sou="456", pin="22244")
    table.player.init_hand(tiles)

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

    tile = string_to_136_tile(man="4")
    meld, _ = table.player.try_to_call_meld(tile, True)
    assert meld is None
Exemple #26
0
def test_is_threatening_and_two_open_yakuhai_melds():
    table = Table()

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

    # south player
    enemy_seat = 1
    # south round
    table.round_wind_number = 4

    table.add_called_meld(enemy_seat, make_meld(MeldPrint.PON, honors="222"))
    table.add_called_meld(enemy_seat, make_meld(MeldPrint.CHI, man="123"))
    table.player.round_step = 2

    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)

    # double wind is not enough
    threatening_players = table.player.ai.defence.get_threatening_players()
    assert len(threatening_players) == 0

    # with one dora in enemy melds we can start think about threat
    # it will be 3 han
    table.add_dora_indicator(string_to_136_tile(man="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="8")) == 3900

    for tile_136 in range(0, 136):
        bonus_danger = threatening_players[0].threat_reason.get(
            "active_yaku")[0].get_bonus_danger(tile_136, 1)
        assert not bonus_danger
Exemple #27
0
def test_shouminkan_and_weak_hand():
    table = Table()
    table.count_of_remaining_tiles = 40

    tiles = string_to_136_array(man="135567", sou="248", pin="5", honors="666")
    table.player.init_hand(tiles)
    table.player.add_called_meld(make_meld(MeldPrint.PON, honors="666"))

    tile = string_to_136_array(honors="6666")[3]
    table.player.draw_tile(tile)

    assert table.player.should_call_kan(tile, False) is None
Exemple #28
0
def test_call_shouminkan():
    table = Table()
    table.count_of_remaining_tiles = 10

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

    tile = string_to_136_array(honors="6666")[3]
    table.player.draw_tile(tile)

    assert table.player.should_call_kan(tile, False) == MeldPrint.SHOUMINKAN
Exemple #29
0
def test_correct_discard_agari_no_yaku():
    table = _make_table()
    tiles = string_to_136_array(man="23567", sou="456", pin="22244")
    table.player.init_hand(tiles)

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

    tile = string_to_136_tile(man="1")
    table.player.draw_tile(tile)
    discard, _ = table.player.discard_tile()
    assert tiles_to_string([discard]) == "1m"
Exemple #30
0
def test_choose_best_wait_with_melds():
    table = Table()
    player = table.player
    table.has_aka_dora = False

    tiles = string_to_136_array(sou="3499222555123")
    player.init_hand(tiles)

    meld = make_meld(MeldPrint.PON, sou="222")
    table.add_called_meld(0, meld)
    # 123s, we can't automatically chose correct index for fourth 2s
    meld = make_meld(MeldPrint.CHI, tiles=[72, 79, 80])
    table.add_called_meld(0, meld)
    meld = make_meld(MeldPrint.PON, sou="555")
    table.add_called_meld(0, meld)

    player.draw_tile(string_to_136_tile(sou="4"))
    discarded_tile, _ = player.discard_tile()
    # double-pairs wait becomes better, because it has 4 tiles to wait for
    # against just 1 in ryanmen
    assert tiles_to_string([discarded_tile]) == "3s"