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
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_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)
def test_chose_strategy_and_reset_strategy(self): table = Table() table.has_open_tanyao = True player = table.player tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO) # we draw a tile that will change our selected strategy tile = self._string_to_136_tile(sou='8') player.draw_tile(tile) self.assertEqual(player.ai.current_strategy, None) tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO) # for already opened hand we don't need to give up on selected strategy meld = Meld() meld.tiles = [1, 2, 3] player.add_called_meld(meld) tile = self._string_to_136_tile(sou='8') player.draw_tile(tile) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO)
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
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_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_chose_right_set_to_open_hand(self): """ Different test cases to open hand and chose correct set to open hand. Based on real examples of incorrect opened hands """ table = Table() table.has_open_tanyao = True player = table.player tiles = self._string_to_136_array(man='23455', pin='3445678', honors='1') tile = self._string_to_136_tile(man='5') player.init_hand(tiles) meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.PON) self.assertEqual(self._to_string(meld.tiles), '555m') table = Table() player = table.player tiles = self._string_to_136_array(man='335666', pin='22', sou='345', honors='55') player.init_hand(tiles) tile = self._string_to_136_tile(man='4') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.CHI) self.assertEqual(self._to_string(meld.tiles), '345m') table = Table() table.has_open_tanyao = True player = table.player tiles = self._string_to_136_array(man='23557', pin='556788', honors='22') player.init_hand(tiles) tile = self._string_to_136_tile(pin='5') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.PON) self.assertEqual(self._to_string(meld.tiles), '555p')
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_is_dora(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) table.dora_indicators = [self._string_to_136_tile(sou='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='2'))) table.dora_indicators = [self._string_to_136_tile(sou='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='1'))) table.dora_indicators = [self._string_to_136_tile(pin='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(pin='1'))) table.dora_indicators = [self._string_to_136_tile(man='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='1'))) table.dora_indicators = [self._string_to_136_tile(man='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='6'))) table.dora_indicators = [self._string_to_136_tile(honors='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='2'))) table.dora_indicators = [self._string_to_136_tile(honors='2')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='3'))) table.dora_indicators = [self._string_to_136_tile(honors='3')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='4'))) table.dora_indicators = [self._string_to_136_tile(honors='4')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='1'))) table.dora_indicators = [self._string_to_136_tile(honors='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='6'))) table.dora_indicators = [self._string_to_136_tile(honors='6')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='7'))) table.dora_indicators = [self._string_to_136_tile(honors='7')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='5'))) table.dora_indicators = [self._string_to_136_tile(pin='1')] self.assertFalse(table.is_dora(self._string_to_136_tile(sou='2'))) table.has_open_tanyao = True # red five man self.assertTrue(table.is_dora(FIVE_RED_MAN)) # red five pin self.assertTrue(table.is_dora(FIVE_RED_PIN)) # red five sou self.assertTrue(table.is_dora(FIVE_RED_SOU))
def test_is_dora(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) table.dora_indicators = [self._string_to_136_tile(sou='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='2'))) table.dora_indicators = [self._string_to_136_tile(sou='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='1'))) table.dora_indicators = [self._string_to_136_tile(pin='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(pin='1'))) table.dora_indicators = [self._string_to_136_tile(man='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='1'))) table.dora_indicators = [self._string_to_136_tile(man='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='6'))) table.dora_indicators = [self._string_to_136_tile(honors='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='2'))) table.dora_indicators = [self._string_to_136_tile(honors='2')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='3'))) table.dora_indicators = [self._string_to_136_tile(honors='3')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='4'))) table.dora_indicators = [self._string_to_136_tile(honors='4')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='1'))) table.dora_indicators = [self._string_to_136_tile(honors='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='6'))) table.dora_indicators = [self._string_to_136_tile(honors='6')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='7'))) table.dora_indicators = [self._string_to_136_tile(honors='7')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='5'))) table.dora_indicators = [self._string_to_136_tile(pin='1')] self.assertFalse(table.is_dora(self._string_to_136_tile(sou='2'))) table.has_open_tanyao = True # red five man self.assertTrue(table.is_dora(FIVE_RED_MAN)) # red five pin self.assertTrue(table.is_dora(FIVE_RED_PIN)) # red five sou self.assertTrue(table.is_dora(FIVE_RED_SOU))
def test_is_dora(): table = Table() table.init_round(0, 0, 0, 0, 0, []) table.dora_indicators = [string_to_136_tile(sou="1")] assert table.is_dora(string_to_136_tile(sou="2")) table.dora_indicators = [string_to_136_tile(sou="9")] assert table.is_dora(string_to_136_tile(sou="1")) table.dora_indicators = [string_to_136_tile(pin="9")] assert table.is_dora(string_to_136_tile(pin="1")) table.dora_indicators = [string_to_136_tile(man="9")] assert table.is_dora(string_to_136_tile(man="1")) table.dora_indicators = [string_to_136_tile(man="5")] assert table.is_dora(string_to_136_tile(man="6")) table.dora_indicators = [string_to_136_tile(honors="1")] assert table.is_dora(string_to_136_tile(honors="2")) table.dora_indicators = [string_to_136_tile(honors="2")] assert table.is_dora(string_to_136_tile(honors="3")) table.dora_indicators = [string_to_136_tile(honors="3")] assert table.is_dora(string_to_136_tile(honors="4")) table.dora_indicators = [string_to_136_tile(honors="4")] assert table.is_dora(string_to_136_tile(honors="1")) table.dora_indicators = [string_to_136_tile(honors="5")] assert table.is_dora(string_to_136_tile(honors="6")) table.dora_indicators = [string_to_136_tile(honors="6")] assert table.is_dora(string_to_136_tile(honors="7")) table.dora_indicators = [string_to_136_tile(honors="7")] assert table.is_dora(string_to_136_tile(honors="5")) table.dora_indicators = [string_to_136_tile(pin="1")] assert not table.is_dora(string_to_136_tile(sou="2")) table.has_open_tanyao = True # red five man assert table.is_dora(FIVE_RED_MAN) # red five pin assert table.is_dora(FIVE_RED_PIN) # red five sou assert table.is_dora(FIVE_RED_SOU)
def test_chose_strategy_and_reset_strategy(): table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="2")) # we draw a tile that will set tanyao as our selected strategy tiles = string_to_136_array(man="33355788", sou="3479", honors="3") player.init_hand(tiles) tile = string_to_136_tile(sou="7") player.draw_tile(tile) assert player.ai.current_strategy is not None assert player.ai.current_strategy.type == BaseStrategy.TANYAO # we draw a tile that will change our selected strategy tiles = string_to_136_array(man="33355788", sou="3479", honors="3") player.init_hand(tiles) tile = string_to_136_tile(sou="2") meld, _ = player.try_to_call_meld(tile, False) assert player.ai.current_strategy is not None assert player.ai.current_strategy.type == BaseStrategy.TANYAO assert meld is None tile = string_to_136_tile(sou="8") player.draw_tile(tile) assert player.ai.current_strategy is None # for already opened hand we don't need to give up on selected strategy tiles = string_to_136_array(man="33355788", sou="3479", honors="3") player.init_hand(tiles) player.draw_tile(string_to_136_tile(honors="5")) player.discard_tile() meld = make_meld(MeldPrint.PON, man="333") player.add_called_meld(meld) tile = string_to_136_tile(sou="8") player.draw_tile(tile) assert player.ai.current_strategy is not None assert player.ai.current_strategy.type == BaseStrategy.TANYAO
def test_calculate_our_hand_cost_1_shanten_karaten(): 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) # average cost should not change because of less waits for _ in range(0, 4): table.add_discarded_tile(1, string_to_136_tile(pin="3"), False) discard_option = find_discard_option(player, honors="1") cost = discard_option.average_second_level_cost assert cost == 1500 # average cost should become 0 for karaten, even if just one of the waits is dead for _ in range(0, 4): table.add_discarded_tile(1, string_to_136_tile(pin="6"), False) discard_option = find_discard_option(player, honors="1") cost = discard_option.average_second_level_cost assert cost == 0 # nothing should crash in case all waits are dead as well for _ in range(0, 4): table.add_discarded_tile(1, string_to_136_tile(man="5"), False) table.add_discarded_tile(1, string_to_136_tile(man="8"), False) discard_option = find_discard_option(player, honors="1") cost = discard_option.average_second_level_cost assert cost == 0
def test_chose_strategy_and_reset_strategy(self): table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(self._string_to_136_tile(man='2')) # we draw a tile that will set tanyao as our selected strategy tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) tile = self._string_to_136_tile(sou='7') player.draw_tile(tile) self.assertNotEqual(player.ai.current_strategy, None) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO) # we draw a tile that will change our selected strategy tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) tile = self._string_to_136_tile(sou='2') meld, _ = player.try_to_call_meld(tile, False) self.assertNotEqual(player.ai.current_strategy, None) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO) self.assertEqual(meld, None) tile = self._string_to_136_tile(sou='8') player.draw_tile(tile) self.assertEqual(player.ai.current_strategy, None) # for already opened hand we don't need to give up on selected strategy tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) player.draw_tile(self._string_to_136_tile(honors='5')) player.discard_tile() meld = self._make_meld(Meld.PON, man='333') player.add_called_meld(meld) tile = self._string_to_136_tile(sou='8') player.draw_tile(tile) self.assertNotEqual(player.ai.current_strategy, None) self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO)
def test_take_cheap_meld_tempai(): 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(man="2")) tiles = string_to_136_array(man="23789", sou="3789", pin="99", honors="33") table.player.init_hand(tiles) table.player.round_step = 5 player.scores = 20000 assert table.players[0] == player table.players[1].scores = 20900 table.players[2].scores = 35000 table.players[3].scores = 40000 # no yaku, skip tile = string_to_136_tile(man="4") 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(man="1") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is not None # now this is not enough player.scores = 20000 assert table.players[0] == player table.players[1].scores = 30900 table.players[2].scores = 35000 table.players[3].scores = 40000 tile = string_to_136_tile(man="1") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is None
def test_skip_ron(): 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")) # 1900 to 3rd place player.scores = 20100 assert table.players[0] == player table.players[1].scores = 22000 table.players[2].scores = 26000 table.players[3].scores = 30900 minimal_cost = player.ai.placement.get_minimal_cost_needed() assert minimal_cost == 1900 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 # we should not call ron 1000 from 2nd place as it leaves us on 4th assert not player.should_call_win(string_to_136_tile(sou="5"), False, 2) # ron 2000 from 2nd place is ok, it's enough to get to 3rd assert player.should_call_win(string_to_136_tile(sou="2"), False, 2) # ron 1000 from 3rd place is ok too assert player.should_call_win(string_to_136_tile(sou="5"), False, 1) # ron 1000 from 1st place is ok too as it moves us to west round assert player.should_call_win(string_to_136_tile(sou="5"), False, 3) # ron 2000 from 1st place is ok, checking just to be sure assert player.should_call_win(string_to_136_tile(sou="2"), False, 3)
def test_take_cheap_meld_tempai_tanyao_not_activated(): 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 # tanyao is not activated due to tanyao rules but we don't care and take this meld tiles = string_to_136_array(man="23678", sou="3567", pin="2257") table.player.init_hand(tiles) table.player.round_step = 5 player.scores = 20000 assert table.players[0] == player table.players[1].scores = 20900 table.players[2].scores = 35000 table.players[3].scores = 40000 # no yaku, skip tile = string_to_136_tile(man="1") 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(man="4") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is not None # now this is not enough player.scores = 20000 assert table.players[0] == player table.players[1].scores = 30900 table.players[2].scores = 35000 table.players[3].scores = 40000 tile = string_to_136_tile(man="4") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is None
def test_take_cheap_meld_yakuhai_1_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 tiles = string_to_136_array(man="236778", sou="357", pin="22", honors="55") table.player.init_hand(tiles) table.player.round_step = 5 player.scores = 20000 assert table.players[0] == player table.players[1].scores = 20900 table.players[2].scores = 35000 table.players[3].scores = 40000 # bad atodzuke - skip tile = string_to_136_tile(pin="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(honors="5") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is not None # now this is not enough player.scores = 20000 assert table.players[0] == player table.players[1].scores = 30900 table.players[2].scores = 35000 table.players[3].scores = 40000 tile = string_to_136_tile(honors="5") meld, _ = table.player.try_to_call_meld(tile, True) assert meld is None
def test_skip_ron_wind_placement(): 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")) 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 = 21000 assert table.players[0] == player table.players[1].scores = 22000 table.players[2].scores = 30100 table.players[3].scores = 31000 player.first_seat = 0 table.players[1].first_seat = 1 assert player.ai.placement.get_minimal_cost_needed() == 1000 assert player.should_call_win(string_to_136_tile(sou="5"), False, 1) assert player.should_call_win(string_to_136_tile(sou="5"), False, 2) assert player.should_call_win(string_to_136_tile(sou="5"), False, 3) player.first_seat = 1 table.players[1].first_seat = 0 assert player.ai.placement.get_minimal_cost_needed() == 1100 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_dont_open_bad_hand_if_there_are_multiple_threats(): 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 table.add_called_riichi_step_one(1) table.add_discarded_tile(1, string_to_136_tile(honors="4"), True) table.add_called_riichi_step_one(2) table.add_discarded_tile(2, string_to_136_tile(honors="4"), True) tiles = string_to_136_array(sou="22499", pin="27", man="3344", honors="4") + [FIVE_RED_MAN] player.init_hand(tiles) tile = string_to_136_tile(man="4") # there are multiple threats with (3900+) hands # let's not push in that case meld, _ = player.try_to_call_meld(tile, False) assert meld is None
def test_chose_right_set_to_open_hand_dora(): table = Table() table.has_open_tanyao = True table.has_aka_dora = False player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) table.add_dora_indicator(string_to_136_tile(sou="1")) tiles = string_to_136_array(man="3456788", sou="245888") player.init_hand(tiles) tile = string_to_136_tile(sou="3") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "234s" table = Table() table.has_open_tanyao = True table.has_aka_dora = False player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) table.add_dora_indicator(string_to_136_tile(sou="4")) tiles = string_to_136_array(man="3456788", sou="245888") player.init_hand(tiles) tile = string_to_136_tile(sou="3") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345s" table = Table() table.has_open_tanyao = True table.has_aka_dora = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) # 5 from string is always aka tiles = string_to_136_array(man="3456788", sou="240888") player.init_hand(tiles) tile = string_to_136_tile(sou="3") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "340s" table = Table() table.has_open_tanyao = True table.has_aka_dora = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) table.add_dora_indicator(string_to_136_tile(sou="1")) table.add_dora_indicator(string_to_136_tile(sou="4")) # double dora versus regular dora, we should keep double dora tiles = string_to_136_array(man="3456788", sou="245888") player.init_hand(tiles) tile = string_to_136_tile(sou="3") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345s"
def _make_table(self): table = Table() table.has_open_tanyao = True return table
def test_chose_right_set_to_open_hand(): """ Different test cases to open hand and chose correct set to open hand. Based on real examples of incorrect opened hands """ table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(pin="2")) table.add_dora_indicator(string_to_136_tile(pin="3")) tiles = string_to_136_array(man="23455", pin="3445678", honors="1") tile = string_to_136_array(man="5555")[2] player.init_hand(tiles) meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.PON assert tiles_to_string(meld.tiles) == "555m" table = Table() player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="5")) tiles = string_to_136_array(man="335666", pin="22", sou="345", honors="55") player.init_hand(tiles) tile = string_to_136_tile(man="4") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345m" table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="1")) table.add_dora_indicator(string_to_136_tile(man="4")) tiles = string_to_136_array(man="23557", pin="556788", honors="22") player.init_hand(tiles) tile = string_to_136_array(pin="5555")[2] meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.PON assert tiles_to_string(meld.tiles) == "555p" table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="4")) table.add_dora_indicator(string_to_136_tile(pin="5")) tiles = string_to_136_array(man="35568", pin="234668", sou="28") player.init_hand(tiles) tile = string_to_136_tile(man="4") meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345m" table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="4")) table.add_dora_indicator(string_to_136_tile(pin="5")) tiles = string_to_136_array(man="34458", pin="234668", sou="28") player.init_hand(tiles) tile = string_to_136_array(man="4444")[2] meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345m" table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) tiles = string_to_136_array(man="567888", pin="788", sou="3456") player.init_hand(tiles) tile = string_to_136_array(sou="4444")[1] meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "456s" tile = string_to_136_array(sou="5555")[1] meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "345s" table = Table() table.has_open_tanyao = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(string_to_136_tile(man="7")) tiles = string_to_136_array(man="567888", pin="788", sou="2345") player.init_hand(tiles) tile = string_to_136_array(sou="4444")[1] meld, _ = player.try_to_call_meld(tile, True) assert meld is not None assert meld.type == MeldPrint.CHI assert tiles_to_string(meld.tiles) == "234s"
def reproduce(self, player, wind, honba, needed_tile, action, tile_number_to_stop): player_position = self._find_player_position(player) round_content = self._find_needed_round(wind, honba) draw_tags = ["T", "U", "V", "W"] discard_tags = ["D", "E", "F", "G"] player_draw = draw_tags[player_position] player_draw_regex = re.compile(r"^<[{}]+\d*".format( "".join(player_draw))) discard_regex = re.compile(r"^<[{}]+\d*".format("".join(discard_tags))) draw_regex = re.compile(r"^<[{}]+\d*".format("".join(draw_tags))) last_draws = {0: None, 1: None, 2: None, 3: None} table = Table() # TODO get this info from log content table.has_aka_dora = True table.has_open_tanyao = True table.player.init_logger(self.logger) players = {} for round_item in self.rounds: for tag in round_item: if "<UN" in tag: players_temp = self.decoder.parse_names_and_ranks(tag) if players_temp: for x in players_temp: players[x["seat"]] = x draw_tile_seen_number = 0 enemy_discard_seen_number = 0 for tag in round_content: if player_draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) table.count_of_remaining_tiles -= 1 # is it time to stop reproducing? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile if action == "draw" and found_tile: draw_tile_seen_number += 1 if draw_tile_seen_number == tile_number_to_stop: self.logger.info("Stop on player draw") discard_result = None with_riichi = False table.player.draw_tile(tile) table.player.should_call_kan( tile, open_kan=False, from_riichi=table.player.in_riichi) if not table.player.in_riichi: discard_result = table.player.discard_tile() with_riichi = table.player.can_call_riichi() return discard_result, with_riichi table.player.draw_tile(tile) if "INIT" in tag: values = self.decoder.parse_initial_values(tag) shifted_scores = [] for x in range(0, 4): shifted_scores.append( values["scores"][self._normalize_position( player_position, x)]) table.init_round( values["round_wind_number"], values["count_of_honba_sticks"], values["count_of_riichi_sticks"], values["dora_indicator"], self._normalize_position(values["dealer"], player_position), shifted_scores, ) hands = [ [ int(x) for x in self.decoder.get_attribute_content( tag, "hai0").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai1").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai2").split(",") ], [ int(x) for x in self.decoder.get_attribute_content( tag, "hai3").split(",") ], ] table.player.init_hand(hands[player_position]) table.player.name = players[player_position]["name"] self.logger.info("Init round info") self.logger.info(table.player.name) self.logger.info(f"Scores: {table.player.scores}") self.logger.info( f"Wind: {DISPLAY_WINDS[table.player.player_wind]}") if "DORA hai" in tag: table.add_dora_indicator( int(self._get_attribute_content(tag, "hai"))) if draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) player_sign = tag.upper()[1] player_seat = self._normalize_position( draw_tags.index(player_sign), player_position) last_draws[player_seat] = tile if discard_regex.match(tag) and "DORA" not in tag: tile = self.decoder.parse_tile(tag) player_sign = tag.upper()[1] player_seat = self._normalize_position( discard_tags.index(player_sign), player_position) if player_seat == 0: table.player.discard_tile(tile, force_tsumogiri=True) else: # is it time to stop? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile is_kamicha_discard = player_seat == 3 if action == "enemy_discard" and found_tile: enemy_discard_seen_number += 1 if enemy_discard_seen_number == tile_number_to_stop: self.logger.info("Stop on enemy discard") self._rebuild_bot_shanten_cache(table.player) table.player.should_call_kan(tile, open_kan=True, from_riichi=False) return table.player.try_to_call_meld( tile, is_kamicha_discard) is_tsumogiri = last_draws[player_seat] == tile table.add_discarded_tile(player_seat, tile, is_tsumogiri=is_tsumogiri) if "<N who=" in tag: meld = self.decoder.parse_meld(tag) player_seat = self._normalize_position(meld.who, player_position) table.add_called_meld(player_seat, meld) if player_seat == 0: if meld.type != MeldPrint.KAN and meld.type != MeldPrint.SHOUMINKAN: table.player.draw_tile(meld.called_tile) if "<REACH" in tag and 'step="1"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_one(who_called_riichi) if "<REACH" in tag and 'step="2"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_two(who_called_riichi)
def test_chose_right_set_to_open_hand_dora(self): table = Table() table.has_open_tanyao = True table.has_aka_dora = False player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(self._string_to_136_tile(man='7')) table.add_dora_indicator(self._string_to_136_tile(sou='1')) tiles = self._string_to_136_array(man='3456788', sou='245888') player.init_hand(tiles) tile = self._string_to_136_tile(sou='3') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.CHI) self.assertEqual(self._to_string(meld.tiles), '234s') table = Table() table.has_open_tanyao = True table.has_aka_dora = False player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(self._string_to_136_tile(man='7')) table.add_dora_indicator(self._string_to_136_tile(sou='4')) tiles = self._string_to_136_array(man='3456788', sou='245888') player.init_hand(tiles) tile = self._string_to_136_tile(sou='3') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.CHI) self.assertEqual(self._to_string(meld.tiles), '345s') table = Table() table.has_open_tanyao = True table.has_aka_dora = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(self._string_to_136_tile(man='7')) # 5 from string is always aka tiles = self._string_to_136_array(man='3456788', sou='245888') player.init_hand(tiles) tile = self._string_to_136_tile(sou='3') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.CHI) self.assertEqual(self._to_string(meld.tiles), '345s') table = Table() table.has_open_tanyao = True table.has_aka_dora = True player = table.player # add 3 doras so we are sure to go for tanyao table.add_dora_indicator(self._string_to_136_tile(man='7')) table.add_dora_indicator(self._string_to_136_tile(sou='1')) table.add_dora_indicator(self._string_to_136_tile(sou='4')) # double dora versus regular dora, we should keep double dora tiles = self._string_to_136_array(man='3456788', sou='245888') player.init_hand(tiles) tile = self._string_to_136_tile(sou='3') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(meld.type, Meld.CHI) self.assertEqual(self._to_string(meld.tiles), '345s')