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
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_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")
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
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_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
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
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
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
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)
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)
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
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"
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"
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"
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"
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"
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"
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
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")
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
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
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
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
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
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"
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"