Coverage for project/game/ai/open_hand_v2.py : 98%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import utils.decisions_constants as log
2from game.ai.strategies_v2.chinitsu import ChinitsuStrategy
3from game.ai.strategies_v2.common_open_tempai import CommonOpenTempaiStrategy
4from game.ai.strategies_v2.formal_tempai import FormalTempaiStrategy
5from game.ai.strategies_v2.honitsu import HonitsuStrategy
6from game.ai.strategies_v2.main import BaseStrategy
7from game.ai.strategies_v2.tanyao import TanyaoStrategy
8from game.ai.strategies_v2.yakuhai import YakuhaiStrategy
9from mahjong.shanten import Shanten
10from mahjong.tile import TilesConverter
13class OpenHandHandlerV2:
14 player = None
15 current_strategy = None
16 last_discard_option = None
18 def __init__(self, player):
19 self.player = player
21 def determine_strategy(self, tiles_136, meld_tile=None):
22 # for already opened hand we don't need to give up on selected strategy
23 if self.player.is_open_hand and self.current_strategy:
24 return False
26 old_strategy = self.current_strategy
27 self.current_strategy = None
29 # order is important, we add strategies with the highest priority first
30 strategies = []
32 # first priority
33 if self.player.table.has_open_tanyao:
34 strategies.append(TanyaoStrategy(BaseStrategy.TANYAO, self.player))
36 # second priority
37 strategies.append(HonitsuStrategy(BaseStrategy.HONITSU, self.player))
38 strategies.append(ChinitsuStrategy(BaseStrategy.CHINITSU, self.player))
40 # third priority
41 strategies.append(YakuhaiStrategy(BaseStrategy.YAKUHAI, self.player))
43 # fourth priority
44 strategies.append(FormalTempaiStrategy(BaseStrategy.FORMAL_TEMPAI, self.player))
45 strategies.append(CommonOpenTempaiStrategy(BaseStrategy.COMMON_OPEN_TEMPAI, self.player))
47 for strategy in strategies:
48 if strategy.should_activate_strategy(tiles_136, meld_tile=meld_tile):
49 self.current_strategy = strategy
50 break
52 if self.current_strategy and (not old_strategy or self.current_strategy.type != old_strategy.type):
53 self.player.logger.debug(
54 log.STRATEGY_ACTIVATE,
55 context=self.current_strategy,
56 )
58 if not self.current_strategy and old_strategy:
59 self.player.logger.debug(log.STRATEGY_DROP, context=old_strategy)
61 return self.current_strategy and True or False
63 def try_to_call_meld(self, tile_136, is_kamicha_discard):
64 tiles_136_previous = self.player.tiles[:]
65 closed_hand_136_previous = self.player.closed_hand[:]
66 tiles_136 = tiles_136_previous + [tile_136]
67 self.determine_strategy(tiles_136, meld_tile=tile_136)
69 if not self.current_strategy:
70 self.player.logger.debug(log.MELD_DEBUG, "We don't have active strategy. Abort melding.")
71 return None, None
73 closed_hand_34_previous = TilesConverter.to_34_array(closed_hand_136_previous)
74 previous_shanten, _ = self.player.ai.hand_builder.calculate_shanten_and_decide_hand_structure(
75 closed_hand_34_previous
76 )
78 if previous_shanten == Shanten.AGARI_STATE and not self.current_strategy.can_meld_into_agari():
79 return None, None
81 meld, discard_option = self.current_strategy.try_to_call_meld(tile_136, is_kamicha_discard, tiles_136)
82 if discard_option:
83 self.last_discard_option = discard_option
85 self.player.logger.debug(
86 log.MELD_CALL,
87 "We decided to open hand",
88 context=[
89 f"Hand: {self.player.format_hand_for_print(tile_136)}",
90 f"Meld: {meld.serialize()}",
91 f"Discard after meld: {discard_option.serialize()}",
92 ],
93 )
95 return meld, discard_option