From c41f3d33f3b42be061e06303b93c616982169a8b Mon Sep 17 00:00:00 2001 From: Alexey Lisikhin Date: Fri, 17 Mar 2017 16:30:26 +0800 Subject: [PATCH] Don't call a riichi for a pair wait (except chitoitsu) --- project/mahjong/ai/main.py | 24 +++++++++++++++- project/mahjong/ai/tests/tests_riichi.py | 36 ++++++++++++++++++++++++ project/mahjong/player.py | 4 ++- project/mahjong/tests/tests_player.py | 5 ++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 project/mahjong/ai/tests/tests_riichi.py diff --git a/project/mahjong/ai/main.py b/project/mahjong/ai/main.py index 0d0040d7..f79974a9 100644 --- a/project/mahjong/ai/main.py +++ b/project/mahjong/ai/main.py @@ -104,7 +104,7 @@ def discard_tile(self): we_can_call_riichi = shanten == 0 and self.player.can_call_riichi() # current strategy can affect on our discard options - # and don't use strategy specific choices for calling riichi + # so, don't use strategy specific choices for calling riichi if self.current_strategy and not we_can_call_riichi: results = self.current_strategy.determine_what_to_discard(self.player.closed_hand, results, @@ -234,6 +234,28 @@ def estimate_hand_value(self, win_tile): dora_indicators=self.player.table.dora_indicators) return result + def should_call_riichi(self): + # empty waiting can be found in some cases + if not self.waiting: + return False + + # we have a good wait, let's riichi + if len(self.waiting) > 1: + return True + + waiting = self.waiting[0] + tiles_34 = TilesConverter.to_34_array(self.player.closed_hand) + count_of_pairs = len([x for x in range(0, 34) if tiles_34[x] == 2]) + + # pair wait is really easy to improve, + # so let's not riichi it + # but for chitoitsu we can call a riichi + is_pair_wait = tiles_34[waiting] == 1 + if is_pair_wait and count_of_pairs != 6: + return False + + return True + @property def valued_honors(self): return [CHUN, HAKU, HATSU, self.player.table.round_wind, self.player.player_wind] diff --git a/project/mahjong/ai/tests/tests_riichi.py b/project/mahjong/ai/tests/tests_riichi.py new file mode 100644 index 00000000..453e004b --- /dev/null +++ b/project/mahjong/ai/tests/tests_riichi.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import unittest + +from mahjong.ai.discard import DiscardOption +from mahjong.ai.main import MainAI +from mahjong.ai.shanten import Shanten +from mahjong.constants import EAST, SOUTH, WEST, NORTH, HAKU, HATSU, CHUN, FIVE_RED_SOU +from mahjong.player import Player +from mahjong.table import Table +from utils.tests import TestMixin + + +class CallRiichiTestCase(unittest.TestCase, TestMixin): + + def test_should_call_riichi_and_tanki_wait(self): + table = Table() + table.count_of_remaining_tiles = 60 + player = Player(table, 0, 0, False) + player.scores = 25000 + + tiles = self._string_to_136_array(sou='123456', pin='12345', man='34') + tile = self._string_to_136_tile(pin='6') + player.init_hand(tiles) + player.draw_tile(tile) + player.discard_tile() + + self.assertEqual(player.can_call_riichi(), False) + + tiles = self._string_to_136_array(sou='1133557799', pin='113') + tile = self._string_to_136_tile(pin='6') + player.init_hand(tiles) + player.draw_tile(tile) + player.discard_tile() + + # for chitoitsu it is ok to have a pair wait + self.assertEqual(player.can_call_riichi(), True) diff --git a/project/mahjong/player.py b/project/mahjong/player.py index 20fdb369..7e45c26e 100644 --- a/project/mahjong/player.py +++ b/project/mahjong/player.py @@ -145,7 +145,7 @@ def discard_tile(self, tile=None): return tile_to_discard def can_call_riichi(self): - return all([ + result = all([ self.in_tempai, not self.in_riichi, @@ -155,6 +155,8 @@ def can_call_riichi(self): self.table.count_of_remaining_tiles > 4 ]) + return result and self.ai.should_call_riichi() + def try_to_call_meld(self, tile, is_kamicha_discard): return self.ai.try_to_call_meld(tile, is_kamicha_discard) diff --git a/project/mahjong/tests/tests_player.py b/project/mahjong/tests/tests_player.py index 9b959946..442f0e76 100644 --- a/project/mahjong/tests/tests_player.py +++ b/project/mahjong/tests/tests_player.py @@ -18,6 +18,7 @@ def test_can_call_riichi_and_tempai(self): player.in_riichi = False player.scores = 2000 player.table.count_of_remaining_tiles = 40 + player.ai.waiting = [1, 2] self.assertEqual(player.can_call_riichi(), False) @@ -33,6 +34,7 @@ def test_can_call_riichi_and_already_in_riichi(self): player.in_riichi = True player.scores = 2000 player.table.count_of_remaining_tiles = 40 + player.ai.waiting = [1, 2] self.assertEqual(player.can_call_riichi(), False) @@ -48,6 +50,7 @@ def test_can_call_riichi_and_scores(self): player.in_riichi = False player.scores = 0 player.table.count_of_remaining_tiles = 40 + player.ai.waiting = [1, 2] self.assertEqual(player.can_call_riichi(), False) @@ -63,6 +66,7 @@ def test_can_call_riichi_and_remaining_tiles(self): player.in_riichi = False player.scores = 2000 player.table.count_of_remaining_tiles = 3 + player.ai.waiting = [1, 2] self.assertEqual(player.can_call_riichi(), False) @@ -79,6 +83,7 @@ def test_can_call_riichi_and_open_hand(self): player.scores = 2000 player.melds = [1] player.table.count_of_remaining_tiles = 40 + player.ai.waiting = [1, 2] self.assertEqual(player.can_call_riichi(), False)