Hide keyboard shortcuts

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.chinitsu import ChinitsuStrategy 

3from game.ai.strategies.common_open_tempai import CommonOpenTempaiStrategy 

4from game.ai.strategies.formal_tempai import FormalTempaiStrategy 

5from game.ai.strategies.honitsu import HonitsuStrategy 

6from game.ai.strategies.main import BaseStrategy 

7from game.ai.strategies.tanyao import TanyaoStrategy 

8from game.ai.strategies.yakuhai import YakuhaiStrategy 

9from mahjong.shanten import Shanten 

10from mahjong.tile import TilesConverter 

11 

12 

13class OpenHandHandler: 

14 player = None 

15 current_strategy = None 

16 last_discard_option = None 

17 

18 def __init__(self, player): 

19 self.player = player 

20 

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 

25 

26 old_strategy = self.current_strategy 

27 self.current_strategy = None 

28 

29 # order is important, we add strategies with the highest priority first 

30 strategies = [] 

31 

32 if self.player.table.has_open_tanyao: 

33 strategies.append(TanyaoStrategy(BaseStrategy.TANYAO, self.player)) 

34 

35 strategies.append(YakuhaiStrategy(BaseStrategy.YAKUHAI, self.player)) 

36 strategies.append(HonitsuStrategy(BaseStrategy.HONITSU, self.player)) 

37 strategies.append(ChinitsuStrategy(BaseStrategy.CHINITSU, self.player)) 

38 

39 strategies.append(FormalTempaiStrategy(BaseStrategy.FORMAL_TEMPAI, self.player)) 

40 strategies.append(CommonOpenTempaiStrategy(BaseStrategy.COMMON_OPEN_TEMPAI, self.player)) 

41 

42 for strategy in strategies: 

43 if strategy.should_activate_strategy(tiles_136, meld_tile=meld_tile): 

44 self.current_strategy = strategy 

45 break 

46 

47 if self.current_strategy and (not old_strategy or self.current_strategy.type != old_strategy.type): 

48 self.player.logger.debug( 

49 log.STRATEGY_ACTIVATE, 

50 context=self.current_strategy, 

51 ) 

52 

53 if not self.current_strategy and old_strategy: 

54 self.player.logger.debug(log.STRATEGY_DROP, context=old_strategy) 

55 

56 return self.current_strategy and True or False 

57 

58 def try_to_call_meld(self, tile_136, is_kamicha_discard): 

59 tiles_136_previous = self.player.tiles[:] 

60 closed_hand_136_previous = self.player.closed_hand[:] 

61 tiles_136 = tiles_136_previous + [tile_136] 

62 self.determine_strategy(tiles_136, meld_tile=tile_136) 

63 

64 if not self.current_strategy: 

65 self.player.logger.debug(log.MELD_DEBUG, "We don't have active strategy. Abort melding.") 

66 return None, None 

67 

68 closed_hand_34_previous = TilesConverter.to_34_array(closed_hand_136_previous) 

69 previous_shanten, _ = self.player.ai.hand_builder.calculate_shanten_and_decide_hand_structure( 

70 closed_hand_34_previous 

71 ) 

72 

73 if previous_shanten == Shanten.AGARI_STATE and not self.current_strategy.can_meld_into_agari(): 

74 return None, None 

75 

76 meld, discard_option = self.current_strategy.try_to_call_meld(tile_136, is_kamicha_discard, tiles_136) 

77 if discard_option: 

78 self.last_discard_option = discard_option 

79 

80 self.player.logger.debug( 

81 log.MELD_CALL, 

82 "We decided to open hand", 

83 context=[ 

84 f"Hand: {self.player.format_hand_for_print(tile_136)}", 

85 f"Meld: {meld.serialize()}", 

86 f"Discard after meld: {discard_option.serialize()}", 

87 ], 

88 ) 

89 

90 return meld, discard_option