Coverage for project/game/ai/strategies_v2/common_open_tempai.py : 69%

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.main import BaseStrategy
3from mahjong.tile import TilesConverter
4from utils.test_helpers import tiles_to_string
7class CommonOpenTempaiStrategy(BaseStrategy):
8 min_shanten = 1
10 def should_activate_strategy(self, tiles_136, meld_tile=None):
11 """
12 We activate this strategy only when we have a chance to meld for good tempai.
13 """
14 result = super(CommonOpenTempaiStrategy, self).should_activate_strategy(tiles_136)
15 if not result:
16 return False
18 # we only use this strategy for meld opportunities, if it's a self draw, just skip it
19 if meld_tile is None:
20 assert tiles_136 == self.player.tiles
21 return False
23 # only go from 1-shanten to tempai with this strategy
24 if self.player.ai.shanten != 1:
25 return False
27 tiles_copy = self.player.closed_hand[:] + [meld_tile]
28 tiles_34 = TilesConverter.to_34_array(tiles_copy)
29 # we only open for tempai with that strategy
30 new_shanten = self.player.ai.calculate_shanten_or_get_from_cache(tiles_34, use_chiitoitsu=False)
32 # we always activate this strategy if we have a chance to get tempai
33 # then we will validate meld to see if it's really a good one
34 return self.player.ai.shanten == 1 and new_shanten == 0
36 def is_tile_suitable(self, tile):
37 """
38 All tiles are suitable for formal tempai.
39 :param tile: 136 tiles format
40 :return: True
41 """
42 return True
44 def validate_meld(self, chosen_meld_dict):
45 # if we have already opened our hand, let's go by default riles
46 if self.player.is_open_hand:
47 return True
49 # choose if base method requires us to keep hand closed
50 if not super(CommonOpenTempaiStrategy, self).validate_meld(chosen_meld_dict):
51 return False
53 selected_tile = chosen_meld_dict["discard_tile"]
54 logger_context = {
55 "hand": tiles_to_string(self.player.closed_hand),
56 "meld": chosen_meld_dict,
57 "new_shanten": selected_tile.shanten,
58 "new_ukeire": selected_tile.ukeire,
59 }
61 if selected_tile.shanten != 0:
62 self.player.logger.debug(
63 log.MELD_DEBUG,
64 "Common tempai: for whatever reason we didn't choose discard giving us tempai, so abort melding",
65 logger_context,
66 )
67 return False
69 if not selected_tile.tempai_descriptor:
70 self.player.logger.debug(
71 log.MELD_DEBUG, "Common tempai: no tempai descriptor found, so abort melding", logger_context
72 )
73 return False
75 if selected_tile.ukeire == 0:
76 self.player.logger.debug(log.MELD_DEBUG, "Common tempai: 0 ukeire, abort melding", logger_context)
77 return False
79 if selected_tile.tempai_descriptor["hand_cost"]:
80 hand_cost = selected_tile.tempai_descriptor["hand_cost"]
81 else:
82 hand_cost = selected_tile.tempai_descriptor["cost_x_ukeire"] / selected_tile.ukeire
84 if hand_cost == 0:
85 self.player.logger.debug(log.MELD_DEBUG, "Common tempai: hand costs nothing, abort melding", logger_context)
86 return False
88 # maybe we need a special handling due to placement
89 # we have already checked that our meld is enough, now let's check that maybe we don't need to aim
90 # for higher costs
91 enough_cost = 32000
92 if self.player.ai.placement.is_oorasu:
93 placement = self.player.ai.placement.get_current_placement()
94 if placement and placement["place"] == 4:
95 enough_cost = self.player.ai.placement.get_minimal_cost_needed_considering_west()
97 if self.player.round_step <= 6:
98 if hand_cost >= min(7700, enough_cost):
99 self.player.logger.debug(log.MELD_DEBUG, "Common tempai: the cost is good, call meld", logger_context)
100 return True
101 elif self.player.round_step <= 12:
102 if self.player.is_dealer:
103 if hand_cost >= min(5800, enough_cost):
104 self.player.logger.debug(
105 log.MELD_DEBUG,
106 "Common tempai: the cost is ok for dealer and round step, call meld",
107 logger_context,
108 )
109 return True
110 else:
111 if hand_cost >= min(3900, enough_cost):
112 self.player.logger.debug(
113 log.MELD_DEBUG,
114 "Common tempai: the cost is ok for non-dealer and round step, call meld",
115 logger_context,
116 )
117 return True
118 else:
119 self.player.logger.debug(
120 log.MELD_DEBUG, "Common tempai: taking any tempai in the late round", logger_context
121 )
122 return True
124 self.player.logger.debug(log.MELD_DEBUG, "Common tempai: the cost is meh, so abort melding", logger_context)
125 return False