From 136c060ac86fbb627ad6f4f5849e8be0ca5caaa3 Mon Sep 17 00:00:00 2001 From: bogachev-pa Date: Fri, 31 Aug 2018 00:22:07 +0300 Subject: [PATCH 1/5] fix check for akadoras --- project/game/ai/first_version/strategies/formal_tempai.py | 2 +- project/game/ai/first_version/strategies/yakuhai.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/game/ai/first_version/strategies/formal_tempai.py b/project/game/ai/first_version/strategies/formal_tempai.py index 5e941486..411ee736 100644 --- a/project/game/ai/first_version/strategies/formal_tempai.py +++ b/project/game/ai/first_version/strategies/formal_tempai.py @@ -31,7 +31,7 @@ def should_activate_strategy(self): return True dora_count = sum([plus_dora(x, self.player.table.dora_indicators) for x in self.player.tiles]) - dora_count += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_open_tanyao)]) + dora_count += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_aka_dora)]) if self.player.ai.previous_shanten == 2: if dora_count < 2: diff --git a/project/game/ai/first_version/strategies/yakuhai.py b/project/game/ai/first_version/strategies/yakuhai.py index b992f5cb..656ae85b 100644 --- a/project/game/ai/first_version/strategies/yakuhai.py +++ b/project/game/ai/first_version/strategies/yakuhai.py @@ -49,7 +49,7 @@ def should_activate_strategy(self): return False dora_count = sum([plus_dora(x, self.player.table.dora_indicators) for x in self.player.tiles]) - dora_count += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_open_tanyao)]) + dora_count += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_aka_dora)]) # let's always open double east if is_double_east_wind: From 0cf142b7d8dd71a9137fae098c5ca60db1460c7b Mon Sep 17 00:00:00 2001 From: bogachev-pa Date: Fri, 31 Aug 2018 02:29:26 +0300 Subject: [PATCH 2/5] revise tanyao strategy requirements #53 --- .../ai/first_version/strategies/tanyao.py | 50 +++++++- .../tests/strategies/tests_tanyao.py | 114 ++++++++++++------ .../game/ai/first_version/tests/tests_ai.py | 15 ++- 3 files changed, 143 insertions(+), 36 deletions(-) diff --git a/project/game/ai/first_version/strategies/tanyao.py b/project/game/ai/first_version/strategies/tanyao.py index 34f61f13..886343c9 100644 --- a/project/game/ai/first_version/strategies/tanyao.py +++ b/project/game/ai/first_version/strategies/tanyao.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- from mahjong.constants import TERMINAL_INDICES, HONOR_INDICES from mahjong.tile import TilesConverter +from mahjong.utils import is_tile_strictly_isolated +from mahjong.utils import plus_dora, is_aka_dora +from mahjong.utils import is_honor from game.ai.first_version.strategies.main import BaseStrategy @@ -21,10 +24,15 @@ def should_activate_strategy(self): return False tiles = TilesConverter.to_34_array(self.player.tiles) + + closed_hand_34 = TilesConverter.to_34_array(self.player.closed_hand) + isolated_tiles = [x // 4 for x in self.player.tiles if is_tile_strictly_isolated(closed_hand_34, x // 4) or is_honor(x // 4)] + count_of_terminal_pon_sets = 0 count_of_terminal_pairs = 0 count_of_valued_pairs = 0 count_of_not_suitable_tiles = 0 + count_of_not_suitable_not_isolated_tiles = 0 for x in range(0, 34): tile = tiles[x] if not tile: @@ -40,7 +48,10 @@ def should_activate_strategy(self): count_of_valued_pairs += 1 if x in self.not_suitable_tiles: - count_of_not_suitable_tiles += 1 + count_of_not_suitable_tiles += tile + + if x in self.not_suitable_tiles and x not in isolated_tiles: + count_of_not_suitable_not_isolated_tiles += tile # we have too much terminals and honors if count_of_not_suitable_tiles >= 5: @@ -61,6 +72,17 @@ def should_activate_strategy(self): if count_of_terminal_pairs > 1: return False + # 3 or more not suitable tiles that + # are not isolated is too much + if count_of_not_suitable_not_isolated_tiles >= 3: + return False + + # if we are 1 shanten, even 2 tiles + # that are not suitable and not isolated + # is too much + if count_of_not_suitable_not_isolated_tiles >= 2 and self.player.ai.previous_shanten == 1: + return False + # 123 and 789 indices indices = [ [0, 1, 2], [6, 7, 8], @@ -75,8 +97,34 @@ def should_activate_strategy(self): if first >= 1 and second >= 1 and third >= 1: return False + dora_indicators_central = [x for x in self.player.table.dora_indicators if not is_honor(x // 4) and not TanyaoStrategy.is_indicator_for_terminal(x // 4)] + dora_count_central = sum([plus_dora(x, dora_indicators_central) for x in self.player.tiles]) + dora_count_central += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_aka_dora)]) + + dora_indicators_not_central = [x for x in self.player.table.dora_indicators if is_honor(x // 4) or TanyaoStrategy.is_indicator_for_terminal(x // 4)] + dora_count_not_central = sum([plus_dora(x, dora_indicators_not_central) for x in self.player.tiles]) + + # if we have 2 or more non-central doras + # we don't want to go for tanyao + if dora_count_not_central >= 2: + return False + + # if we have less than two central doras + # let's not consider open tanyao + if dora_count_central < 2: + return False + + # if we have only two central doras let's + # wait for 5th turn before opening our hand + if dora_count_central == 2 and self.player.round_step < 5: + return False + return True + @staticmethod + def is_indicator_for_terminal(tile): + return tile == 7 or tile == 8 or tile == 16 or tile == 17 or tile == 25 or tile == 26 + def determine_what_to_discard(self, closed_hand, outs_results, shanten, for_open_hand, tile_for_open_hand, hand_was_open=False): if tile_for_open_hand: diff --git a/project/game/ai/first_version/tests/strategies/tests_tanyao.py b/project/game/ai/first_version/tests/strategies/tests_tanyao.py index 4f2f18d4..3ed3760b 100644 --- a/project/game/ai/first_version/tests/strategies/tests_tanyao.py +++ b/project/game/ai/first_version/tests/strategies/tests_tanyao.py @@ -18,55 +18,55 @@ def setUp(self): def test_should_activate_strategy_and_terminal_pon_sets(self): strategy = TanyaoStrategy(BaseStrategy.TANYAO, self.player) - tiles = self._string_to_136_array(sou='234', man='3459', pin='233', honors='111') + tiles = self._string_to_136_array(sou='222', man='3459', pin='233', honors='111') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='3459', pin='233999') + tiles = self._string_to_136_array(sou='222', man='3459', pin='233999') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='3459', pin='233444') + tiles = self._string_to_136_array(sou='222', man='3459', pin='233444') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), True) def test_should_activate_strategy_and_terminal_pairs(self): strategy = TanyaoStrategy(BaseStrategy.TANYAO, self.player) - tiles = self._string_to_136_array(sou='234', man='3459', pin='2399', honors='11') + tiles = self._string_to_136_array(sou='222', man='3459', pin='2399', honors='11') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='345669', pin='2399') + tiles = self._string_to_136_array(sou='222', man='345669', pin='2399') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), True) def test_should_activate_strategy_and_valued_pair(self): strategy = TanyaoStrategy(BaseStrategy.TANYAO, self.player) - tiles = self._string_to_136_array(man='23446679', sou='345', honors='55') + tiles = self._string_to_136_array(man='23446679', sou='222', honors='55') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(man='23446679', sou='345', honors='22') + tiles = self._string_to_136_array(man='23446679', sou='222', honors='22') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), True) def test_should_activate_strategy_and_chitoitsu_like_hand(self): strategy = TanyaoStrategy(BaseStrategy.TANYAO, self.player) - tiles = self._string_to_136_array(sou='223388', man='3344', pin='6687') + tiles = self._string_to_136_array(sou='223388', man='2244', pin='6687') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) def test_should_activate_strategy_and_already_completed_sided_set(self): strategy = TanyaoStrategy(BaseStrategy.TANYAO, self.player) - tiles = self._string_to_136_array(sou='123234', man='3459', pin='234') + tiles = self._string_to_136_array(sou='123234', man='2349', pin='234') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234789', man='3459', pin='234') + tiles = self._string_to_136_array(sou='234789', man='2349', pin='234') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) @@ -74,19 +74,19 @@ def test_should_activate_strategy_and_already_completed_sided_set(self): self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='3457899', pin='234') + tiles = self._string_to_136_array(sou='234', man='2227899', pin='234') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='3459', pin='122334') + tiles = self._string_to_136_array(sou='234', man='2229', pin='122334') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='234', man='3459', pin='234789') + tiles = self._string_to_136_array(sou='234', man='2229', pin='234789') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) - tiles = self._string_to_136_array(sou='223344', man='3459', pin='234') + tiles = self._string_to_136_array(sou='223344', man='2229', pin='234') self.player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), True) @@ -119,21 +119,21 @@ def test_suitable_tiles(self): def test_dont_open_hand_with_high_shanten(self): # with 4 shanten we don't need to aim for open tanyao - tiles = self._string_to_136_array(man='369', pin='378', sou='3488', honors='123') - tile = self._string_to_136_tile(sou='2') + tiles = self._string_to_136_array(man='269', pin='247', sou='2488', honors='123') + tile = self._string_to_136_tile(sou='3') self.player.init_hand(tiles) meld, _ = self.player.try_to_call_meld(tile, False) self.assertEqual(meld, None) # with 3 shanten we can open a hand - tiles = self._string_to_136_array(man='236', pin='378', sou='3488', honors='123') - tile = self._string_to_136_tile(sou='2') + tiles = self._string_to_136_array(man='236', pin='247', sou='2488', honors='123') + tile = self._string_to_136_tile(sou='3') self.player.init_hand(tiles) meld, _ = self.player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) def test_dont_open_hand_with_not_suitable_melds(self): - tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') + tiles = self._string_to_136_array(man='22255788', sou='3479', honors='3') tile = self._string_to_136_tile(sou='8') self.player.init_hand(tiles) meld, _ = self.player.try_to_call_meld(tile, False) @@ -141,7 +141,7 @@ def test_dont_open_hand_with_not_suitable_melds(self): def test_open_hand_and_discard_tiles_logic(self): # 2345779m1p256s44z - tiles = self._string_to_136_array(man='22345', sou='238', pin='256', honors='44') + tiles = self._string_to_136_array(man='22234', sou='238', pin='256', honors='44') self.player.init_hand(tiles) # if we are in tanyao @@ -172,7 +172,7 @@ def test_dont_count_pairs_in_already_opened_hand(self): self.assertNotEqual(meld, None) def test_we_cant_win_with_this_hand(self): - tiles = self._string_to_136_array(man='34577', sou='23', pin='233445') + tiles = self._string_to_136_array(man='22277', sou='23', pin='233445') self.player.init_hand(tiles) meld = self._make_meld(Meld.CHI, pin='234') self.player.add_called_meld(meld) @@ -186,36 +186,35 @@ def test_we_cant_win_with_this_hand(self): self.assertEqual(self._to_string([discard]), '1s') def test_choose_correct_waiting(self): - tiles = self._string_to_136_array(man='234678', sou='234', pin='3588') + tiles = self._string_to_136_array(man='222678', sou='234', pin='3588') self.player.init_hand(tiles) self.player.draw_tile(self._string_to_136_tile(pin='2')) + self._assert_tanyao(self.player) + # discard 5p and riichi discard = self.player.discard_tile() self.assertEqual(self._to_string([discard]), '5p') - table = self._make_table() - player = table.player - meld = self._make_meld(Meld.CHI, man='234') - player.add_called_meld(meld) + self.player.add_called_meld(meld) - tiles = self._string_to_136_array(man='234678', sou='234', pin='3588') - player.init_hand(tiles) - player.draw_tile(self._string_to_136_tile(pin='2')) + tiles = self._string_to_136_array(man='234888', sou='234', pin='3588') + self.player.init_hand(tiles) + self.player.draw_tile(self._string_to_136_tile(pin='2')) # it is not a good idea to wait on 1-4, since we can't win on 1 with open hand # so let's continue to wait on 4 only - discard = player.discard_tile() + discard = self.player.discard_tile() self.assertEqual(self._to_string([discard]), '2p') table = self._make_table() player = table.player - meld = self._make_meld(Meld.CHI, man='234') + meld = self._make_meld(Meld.CHI, man='678') player.add_called_meld(meld) - tiles = self._string_to_136_array(man='234678', sou='234', pin='2388') + tiles = self._string_to_136_array(man='222678', sou='234', pin='2388') player.init_hand(tiles) player.draw_tile(self._string_to_136_tile(sou='7')) @@ -224,9 +223,11 @@ def test_choose_correct_waiting(self): self.assertEqual(self._to_string([discard]), '7s') def test_choose_correct_waiting_and_fist_opened_meld(self): - tiles = self._string_to_136_array(man='2337788', sou='345', pin='234') + tiles = self._string_to_136_array(man='2337788', sou='222', pin='234') self.player.init_hand(tiles) + self._assert_tanyao(self.player) + tile = self._string_to_136_tile(man='8') meld, tile_to_discard = self.player.try_to_call_meld(tile, False) @@ -234,7 +235,7 @@ def test_choose_correct_waiting_and_fist_opened_meld(self): self.assertEqual(self._to_string([discard]), '2m') def test_we_dont_need_to_discard_terminals_from_closed_hand(self): - tiles = self._string_to_136_array(man='22345', sou='13588', pin='558') + tiles = self._string_to_136_array(man='22234', sou='13588', pin='558') self.player.init_hand(tiles) tile = self._string_to_136_tile(pin='5') @@ -244,7 +245,52 @@ def test_we_dont_need_to_discard_terminals_from_closed_hand(self): # our hand is closed, let's keep terminal for now self.assertEqual(self._to_string([tile_to_discard]), '8p') + def test_dont_open_tanyo_with_two_non_central_doras(self): + table = self._make_table() + player = table.player + + table.add_dora_indicator(self._string_to_136_tile(pin='8')) + + tiles = self._string_to_136_array(man='22234', sou='888', pin='5599') + player.init_hand(tiles) + + tile = self._string_to_136_tile(pin='5') + meld, _ = player.try_to_call_meld(tile, False) + self.assertEqual(meld, None) + + def test_dont_open_tanyo_with_three_not_isolated_terminals(self): + tiles = self._string_to_136_array(man='2226', sou='2799', pin='5579') + self.player.init_hand(tiles) + + tile = self._string_to_136_tile(pin='5') + meld, _ = self.player.try_to_call_meld(tile, False) + self.assertEqual(meld, None) + + def test_dont_open_tanyo_with_two_not_isolated_terminals_one_shanten(self): + tiles = self._string_to_136_array(man='22234', sou='79', pin='55579') + self.player.init_hand(tiles) + + # to calculate hand shanten number + self.player.draw_tile(self._string_to_136_tile(honors='1')) + self.player.discard_tile() + self.player.draw_tile(self._string_to_136_tile(honors='1')) + self.player.discard_tile() + + tile = self._string_to_136_tile(man='5') + meld, _ = self.player.try_to_call_meld(tile, False) + self.assertEqual(meld, None) + def _make_table(self): table = Table() table.has_open_tanyao = True + + # add doras so we are sure to go for tanyao + table.add_dora_indicator(self._string_to_136_tile(sou='1')) + table.add_dora_indicator(self._string_to_136_tile(man='1')) + table.add_dora_indicator(self._string_to_136_tile(pin='1')) + return table + + def _assert_tanyao(self, player): + self.assertNotEqual(player.ai.current_strategy, None) + self.assertEqual(player.ai.current_strategy.type, BaseStrategy.TANYAO) diff --git a/project/game/ai/first_version/tests/tests_ai.py b/project/game/ai/first_version/tests/tests_ai.py index cef0dc8a..f24ac7be 100644 --- a/project/game/ai/first_version/tests/tests_ai.py +++ b/project/game/ai/first_version/tests/tests_ai.py @@ -64,6 +64,10 @@ def test_chose_right_set_to_open_hand(self): 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(pin='2')) + table.add_dora_indicator(self._string_to_136_tile(pin='3')) + tiles = self._string_to_136_array(man='23455', pin='3445678', honors='1') tile = self._string_to_136_tile(man='5') player.init_hand(tiles) @@ -75,7 +79,8 @@ def test_chose_right_set_to_open_hand(self): table = Table() player = table.player - table.dora_indicators.append(self._string_to_136_tile(honors='7')) + # add 3 doras so we are sure to go for tanyao + table.add_dora_indicator(self._string_to_136_tile(man='5')) tiles = self._string_to_136_array(man='335666', pin='22', sou='345', honors='55') player.init_hand(tiles) @@ -88,6 +93,9 @@ def test_chose_right_set_to_open_hand(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='1')) + table.add_dora_indicator(self._string_to_136_tile(man='4')) tiles = self._string_to_136_array(man='23557', pin='556788', honors='22') player.init_hand(tiles) @@ -125,8 +133,12 @@ def test_chose_strategy_and_reset_strategy(self): 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')) + tiles = self._string_to_136_array(man='33355788', sou='3479', honors='3') player.init_hand(tiles) + 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 @@ -144,6 +156,7 @@ def test_chose_strategy_and_reset_strategy(self): 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_remaining_tiles_and_enemy_discard(self): From d18bceb711d9684bdcdd462637a756ec0eef2f7b Mon Sep 17 00:00:00 2001 From: Nihisil Date: Fri, 31 Aug 2018 10:07:40 +0800 Subject: [PATCH 3/5] Upgrade to latest mahjong lib version --- .../ai/first_version/strategies/tanyao.py | 27 ++++++++++++------- project/requirements.txt | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/project/game/ai/first_version/strategies/tanyao.py b/project/game/ai/first_version/strategies/tanyao.py index 886343c9..235a7b73 100644 --- a/project/game/ai/first_version/strategies/tanyao.py +++ b/project/game/ai/first_version/strategies/tanyao.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from mahjong.constants import TERMINAL_INDICES, HONOR_INDICES from mahjong.tile import TilesConverter -from mahjong.utils import is_tile_strictly_isolated +from mahjong.utils import is_tile_strictly_isolated, is_terminal from mahjong.utils import plus_dora, is_aka_dora from mahjong.utils import is_honor @@ -97,12 +97,23 @@ def should_activate_strategy(self): if first >= 1 and second >= 1 and third >= 1: return False - dora_indicators_central = [x for x in self.player.table.dora_indicators if not is_honor(x // 4) and not TanyaoStrategy.is_indicator_for_terminal(x // 4)] - dora_count_central = sum([plus_dora(x, dora_indicators_central) for x in self.player.tiles]) - dora_count_central += sum([1 for x in self.player.tiles if is_aka_dora(x, self.player.table.has_aka_dora)]) + dora_count_central = 0 + dora_count_not_central = 0 + for tile_136 in self.player.tiles: + tile_34 = tile_136 // 4 - dora_indicators_not_central = [x for x in self.player.table.dora_indicators if is_honor(x // 4) or TanyaoStrategy.is_indicator_for_terminal(x // 4)] - dora_count_not_central = sum([plus_dora(x, dora_indicators_not_central) for x in self.player.tiles]) + dora = plus_dora(tile_136, self.player.table.dora_indicators) + + if is_aka_dora(tile_136, self.player.table.has_aka_dora): + dora_count_central += 1 + + if not dora: + continue + + if is_honor(tile_34) or is_terminal(tile_34): + dora_count_not_central += 1 + else: + dora_count_central += 1 # if we have 2 or more non-central doras # we don't want to go for tanyao @@ -121,10 +132,6 @@ def should_activate_strategy(self): return True - @staticmethod - def is_indicator_for_terminal(tile): - return tile == 7 or tile == 8 or tile == 16 or tile == 17 or tile == 25 or tile == 26 - def determine_what_to_discard(self, closed_hand, outs_results, shanten, for_open_hand, tile_for_open_hand, hand_was_open=False): if tile_for_open_hand: diff --git a/project/requirements.txt b/project/requirements.txt index 91c6f81f..c2dde972 100644 --- a/project/requirements.txt +++ b/project/requirements.txt @@ -1,3 +1,3 @@ -mahjong==1.1.3 +mahjong==1.1.4 requests==2.18.4 flake8==3.4.1 \ No newline at end of file From c70324f650754dc2de1abee835eb584750f94787 Mon Sep 17 00:00:00 2001 From: Nihisil Date: Fri, 31 Aug 2018 13:25:35 +0800 Subject: [PATCH 4/5] Small tanyao tests refactoring --- .../tests/strategies/tests_tanyao.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/project/game/ai/first_version/tests/strategies/tests_tanyao.py b/project/game/ai/first_version/tests/strategies/tests_tanyao.py index 3ed3760b..4821a05b 100644 --- a/project/game/ai/first_version/tests/strategies/tests_tanyao.py +++ b/project/game/ai/first_version/tests/strategies/tests_tanyao.py @@ -140,15 +140,13 @@ def test_dont_open_hand_with_not_suitable_melds(self): self.assertEqual(meld, None) def test_open_hand_and_discard_tiles_logic(self): - # 2345779m1p256s44z tiles = self._string_to_136_array(man='22234', sou='238', pin='256', honors='44') self.player.init_hand(tiles) - # if we are in tanyao - # we need to discard terminals and honors tile = self._string_to_136_tile(sou='4') meld, discard_option = self.player.try_to_call_meld(tile, True) discarded_tile = self.player.discard_tile(discard_option) + self.assertNotEqual(meld, None) self.assertEqual(self._to_string([discarded_tile]), '4z') @@ -156,7 +154,6 @@ def test_open_hand_and_discard_tiles_logic(self): self.player.draw_tile(tile) tile_to_discard = self.player.discard_tile() - # we are in tanyao, so we should discard honors and terminals self.assertEqual(self._to_string([tile_to_discard]), '4z') def test_dont_count_pairs_in_already_opened_hand(self): @@ -222,7 +219,7 @@ def test_choose_correct_waiting(self): discard = player.discard_tile() self.assertEqual(self._to_string([discard]), '7s') - def test_choose_correct_waiting_and_fist_opened_meld(self): + def test_choose_correct_waiting_and_first_opened_meld(self): tiles = self._string_to_136_array(man='2337788', sou='222', pin='234') self.player.init_hand(tiles) @@ -245,7 +242,7 @@ def test_we_dont_need_to_discard_terminals_from_closed_hand(self): # our hand is closed, let's keep terminal for now self.assertEqual(self._to_string([tile_to_discard]), '8p') - def test_dont_open_tanyo_with_two_non_central_doras(self): + def test_dont_open_tanyao_with_two_non_central_doras(self): table = self._make_table() player = table.player @@ -258,7 +255,7 @@ def test_dont_open_tanyo_with_two_non_central_doras(self): meld, _ = player.try_to_call_meld(tile, False) self.assertEqual(meld, None) - def test_dont_open_tanyo_with_three_not_isolated_terminals(self): + def test_dont_open_tanyao_with_three_not_isolated_terminals(self): tiles = self._string_to_136_array(man='2226', sou='2799', pin='5579') self.player.init_hand(tiles) @@ -266,16 +263,10 @@ def test_dont_open_tanyo_with_three_not_isolated_terminals(self): meld, _ = self.player.try_to_call_meld(tile, False) self.assertEqual(meld, None) - def test_dont_open_tanyo_with_two_not_isolated_terminals_one_shanten(self): + def test_dont_open_tanyao_with_two_not_isolated_terminals_one_shanten(self): tiles = self._string_to_136_array(man='22234', sou='79', pin='55579') self.player.init_hand(tiles) - # to calculate hand shanten number - self.player.draw_tile(self._string_to_136_tile(honors='1')) - self.player.discard_tile() - self.player.draw_tile(self._string_to_136_tile(honors='1')) - self.player.discard_tile() - tile = self._string_to_136_tile(man='5') meld, _ = self.player.try_to_call_meld(tile, False) self.assertEqual(meld, None) From 968534f69dfd085b30ba57ce912b9cb448574e1e Mon Sep 17 00:00:00 2001 From: Nihisil Date: Fri, 31 Aug 2018 14:01:50 +0800 Subject: [PATCH 5/5] Issue #66. When considering ukeire for open hand don't count tiles that don't suit our yaku --- project/game/ai/first_version/main.py | 8 ++++++-- project/game/ai/first_version/strategies/main.py | 1 + .../tests/strategies/tests_tanyao.py | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/project/game/ai/first_version/main.py b/project/game/ai/first_version/main.py index be124cb4..5573329a 100644 --- a/project/game/ai/first_version/main.py +++ b/project/game/ai/first_version/main.py @@ -199,8 +199,12 @@ def calculate_outs(self, tiles, closed_hand, open_sets_34=None): def count_tiles(self, waiting, tiles_34): n = 0 - for item in waiting: - n += 4 - self.player.total_tiles(item, tiles_34) + not_suitable_tiles = self.current_strategy and self.current_strategy.not_suitable_tiles or [] + for tile_34 in waiting: + if self.player.is_open_hand and tile_34 in not_suitable_tiles: + continue + + n += 4 - self.player.total_tiles(tile_34, tiles_34) return n def try_to_call_meld(self, tile, is_kamicha_discard): diff --git a/project/game/ai/first_version/strategies/main.py b/project/game/ai/first_version/strategies/main.py index 9ad68c14..534f4361 100644 --- a/project/game/ai/first_version/strategies/main.py +++ b/project/game/ai/first_version/strategies/main.py @@ -17,6 +17,7 @@ class BaseStrategy(object): FORMAL_TEMPAI: 'Formal Tempai' } + not_suitable_tiles = [] player = None type = None # number of shanten where we can start to open hand diff --git a/project/game/ai/first_version/tests/strategies/tests_tanyao.py b/project/game/ai/first_version/tests/strategies/tests_tanyao.py index 4821a05b..2da29873 100644 --- a/project/game/ai/first_version/tests/strategies/tests_tanyao.py +++ b/project/game/ai/first_version/tests/strategies/tests_tanyao.py @@ -271,6 +271,22 @@ def test_dont_open_tanyao_with_two_not_isolated_terminals_one_shanten(self): meld, _ = self.player.try_to_call_meld(tile, False) self.assertEqual(meld, None) + def test_dont_count_terminal_tiles_in_ukeire(self): + # for closed hand let's chose tile with best ukeire + tiles = self._string_to_136_array(man='234578', sou='235', pin='2246') + self.player.init_hand(tiles) + self.player.draw_tile(self._string_to_136_tile(pin='5')) + discard = self.player.discard_tile() + self.assertEqual(self._to_string([discard]), '5m') + + # but with opened hand we don't need to count not suitable tiles as ukeire + tiles = self._string_to_136_array(man='234578', sou='235', pin='2246') + self.player.init_hand(tiles) + self.player.add_called_meld(self._make_meld(Meld.CHI, man='234')) + self.player.draw_tile(self._string_to_136_tile(pin='5')) + discard = self.player.discard_tile() + self.assertEqual(self._to_string([discard]), '8m') + def _make_table(self): table = Table() table.has_open_tanyao = True