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

1from game.ai.helpers.defence import TileDanger 

2from mahjong.constants import EAST 

3from mahjong.tile import TilesConverter 

4from utils.general import revealed_suits_tiles 

5 

6 

7class PossibleFormsAnalyzer: 

8 POSSIBLE_TANKI = 1 

9 POSSIBLE_SYANPON = 2 

10 POSSIBLE_PENCHAN = 3 

11 POSSIBLE_KANCHAN = 4 

12 POSSIBLE_RYANMEN = 5 

13 POSSIBLE_RYANMEN_SIDES = 6 

14 

15 def __init__(self, player): 

16 self.player = player 

17 

18 def calculate_possible_forms(self, safe_tiles): 

19 possible_forms_34 = [None] * 34 

20 

21 closed_hand_34 = TilesConverter.to_34_array(self.player.closed_hand) 

22 

23 # first of all let's find suji for suits tiles 

24 suits = revealed_suits_tiles(self.player, closed_hand_34) 

25 for x in range(0, 3): 

26 suit = suits[x] 

27 

28 for y in range(0, 9): 

29 tile_34_index = y + x * 9 

30 

31 # we are only interested in tiles that we can discard 

32 if closed_hand_34[tile_34_index] == 0: 

33 continue 

34 

35 forms_count = self._init_zero_forms_count() 

36 possible_forms_34[tile_34_index] = forms_count 

37 

38 # that means there are no possible forms for him to wait (we don't consider furiten here, 

39 # because we are defending from enemy taking ron) 

40 if tile_34_index in safe_tiles: 

41 continue 

42 

43 # tanki 

44 forms_count[self.POSSIBLE_TANKI] = 4 - suit[y] 

45 

46 # syanpon 

47 if suit[y] == 1: 

48 forms_count[self.POSSIBLE_SYANPON] = 3 

49 if suit[y] == 2: 

50 forms_count[self.POSSIBLE_SYANPON] = 1 

51 else: 

52 forms_count[self.POSSIBLE_SYANPON] = 0 

53 

54 # penchan 

55 if y == 2: 

56 forms_count[self.POSSIBLE_PENCHAN] = (4 - suit[0]) * (4 - suit[1]) 

57 elif y == 6: 

58 forms_count[self.POSSIBLE_PENCHAN] = (4 - suit[8]) * (4 - suit[7]) 

59 

60 # kanchan 

61 if 1 <= y <= 7: 

62 tiles_cnt_left = 4 - suit[y - 1] 

63 tiles_cnt_right = 4 - suit[y + 1] 

64 forms_count[self.POSSIBLE_KANCHAN] = tiles_cnt_left * tiles_cnt_right 

65 

66 # ryanmen 

67 if 0 <= y <= 2: 

68 if not (tile_34_index + 3) in safe_tiles: 

69 forms_right = (4 - suit[y + 1]) * (4 - suit[y + 2]) 

70 if forms_right != 0: 

71 forms_count[self.POSSIBLE_RYANMEN_SIDES] = 1 

72 forms_count[self.POSSIBLE_RYANMEN] = (4 - suit[y + 1]) * (4 - suit[y + 2]) 

73 elif 3 <= y <= 5: 

74 if not (tile_34_index - 3) in safe_tiles: 

75 forms_left = (4 - suit[y - 1]) * (4 - suit[y - 2]) 

76 if forms_left != 0: 

77 forms_count[self.POSSIBLE_RYANMEN_SIDES] += 1 

78 forms_count[self.POSSIBLE_RYANMEN] += forms_left 

79 if not (tile_34_index + 3) in safe_tiles: 

80 forms_right = (4 - suit[y + 1]) * (4 - suit[y + 2]) 

81 if forms_right != 0: 

82 forms_count[self.POSSIBLE_RYANMEN_SIDES] += 1 

83 forms_count[self.POSSIBLE_RYANMEN] += forms_right 

84 else: 

85 if not (tile_34_index - 3) in safe_tiles: 

86 forms_left = (4 - suit[y - 1]) * (4 - suit[y - 2]) 

87 if forms_left != 0: 

88 forms_count[self.POSSIBLE_RYANMEN] = (4 - suit[y - 1]) * (4 - suit[y - 2]) 

89 forms_count[self.POSSIBLE_RYANMEN_SIDES] = 1 

90 

91 for tile_34_index in range(EAST, 34): 

92 if closed_hand_34[tile_34_index] == 0: 

93 continue 

94 

95 forms_count = self._init_zero_forms_count() 

96 possible_forms_34[tile_34_index] = forms_count 

97 

98 total_tiles = self.player.number_of_revealed_tiles(tile_34_index, closed_hand_34) 

99 

100 # tanki 

101 forms_count[self.POSSIBLE_TANKI] = 4 - total_tiles 

102 

103 # syanpon 

104 forms_count[self.POSSIBLE_SYANPON] = 3 - total_tiles if total_tiles < 3 else 0 

105 

106 return possible_forms_34 

107 

108 @staticmethod 

109 def calculate_possible_forms_total(forms_count): 

110 total = 0 

111 total += forms_count[PossibleFormsAnalyzer.POSSIBLE_TANKI] 

112 total += forms_count[PossibleFormsAnalyzer.POSSIBLE_SYANPON] 

113 total += forms_count[PossibleFormsAnalyzer.POSSIBLE_PENCHAN] 

114 total += forms_count[PossibleFormsAnalyzer.POSSIBLE_KANCHAN] 

115 total += forms_count[PossibleFormsAnalyzer.POSSIBLE_RYANMEN] 

116 return total 

117 

118 @staticmethod 

119 def calculate_possible_forms_danger(forms_count): 

120 danger = 0 

121 danger += forms_count[PossibleFormsAnalyzer.POSSIBLE_TANKI] * TileDanger.FORM_BONUS_TANKI 

122 danger += forms_count[PossibleFormsAnalyzer.POSSIBLE_SYANPON] * TileDanger.FORM_BONUS_SYANPON 

123 danger += forms_count[PossibleFormsAnalyzer.POSSIBLE_PENCHAN] * TileDanger.FORM_BONUS_PENCHAN 

124 danger += forms_count[PossibleFormsAnalyzer.POSSIBLE_KANCHAN] * TileDanger.FORM_BONUS_KANCHAN 

125 danger += forms_count[PossibleFormsAnalyzer.POSSIBLE_RYANMEN] * TileDanger.FORM_BONUS_RYANMEN 

126 return danger 

127 

128 def _init_zero_forms_count(self): 

129 forms_count = dict() 

130 forms_count[self.POSSIBLE_TANKI] = 0 

131 forms_count[self.POSSIBLE_SYANPON] = 0 

132 forms_count[self.POSSIBLE_PENCHAN] = 0 

133 forms_count[self.POSSIBLE_KANCHAN] = 0 

134 forms_count[self.POSSIBLE_RYANMEN] = 0 

135 forms_count[self.POSSIBLE_RYANMEN_SIDES] = 0 

136 return forms_count