Skip to content
This repository was archived by the owner on Jul 8, 2023. It is now read-only.

Commit 64df3fe

Browse files
committed
Trying to fix bad open hands behaviour
1 parent 3d7322d commit 64df3fe

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

project/game/ai/hand_builder.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
4141

4242
tiles_we_can_discard = [x for x in discard_options if x.danger.get_max_danger() <= x.danger.danger_border]
4343
if not tiles_we_can_discard:
44-
return self._chose_first_option_or_safe_tiles([], discard_options)
44+
return self._chose_first_option_or_safe_tiles([], discard_options, for_open_hand)
4545

4646
# our strategy can affect discard options
4747
if self.ai.current_strategy:
@@ -52,7 +52,7 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
5252
had_to_be_discarded_tiles = [x for x in tiles_we_can_discard if x.had_to_be_discarded]
5353
if had_to_be_discarded_tiles:
5454
tiles_we_can_discard = sorted(had_to_be_discarded_tiles, key=lambda x: (x.shanten, -x.ukeire, x.valuation))
55-
return self._chose_first_option_or_safe_tiles(tiles_we_can_discard, discard_options)
55+
return self._chose_first_option_or_safe_tiles(tiles_we_can_discard, discard_options, for_open_hand)
5656

5757
# remove needed tiles from discard options
5858
tiles_we_can_discard = [x for x in tiles_we_can_discard if not x.had_to_be_saved]
@@ -101,7 +101,7 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
101101
min_dora = min([x.count_of_dora for x in possible_options])
102102
min_dora_list = [x for x in possible_options if x.count_of_dora == min_dora]
103103
return self._chose_first_option_or_safe_tiles(
104-
sorted(min_dora_list, key=lambda x: -getattr(x, ukeire_field)), discard_options
104+
sorted(min_dora_list, key=lambda x: -getattr(x, ukeire_field)), discard_options, for_open_hand
105105
)
106106

107107
# only one option - so we choose it
@@ -113,6 +113,7 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
113113
return self._chose_first_option_or_safe_tiles(
114114
sorted(tiles_without_dora, key=lambda x: (-x.second_level_cost, -x.ukeire_second, x.valuation)),
115115
discard_options,
116+
for_open_hand,
116117
)
117118

118119
if first_option.shanten == 2 or first_option.shanten == 3:
@@ -139,13 +140,13 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
139140
if isolated_tiles:
140141
# let's sort tiles by value and let's choose less valuable tile to discard
141142
return self._chose_first_option_or_safe_tiles(
142-
sorted(isolated_tiles, key=lambda x: x.valuation), discard_options
143+
sorted(isolated_tiles, key=lambda x: x.valuation), discard_options, for_open_hand
143144
)
144145

145146
# there are no isolated tiles or we don't care about them
146147
# let's discard tile with greater ukeire/ukeire2
147148
filtered_options = sorted(filtered_options, key=lambda x: -getattr(x, ukeire_field))
148-
first_option = self._chose_first_option_or_safe_tiles(filtered_options, discard_options)
149+
first_option = self._chose_first_option_or_safe_tiles(filtered_options, discard_options, for_open_hand)
149150

150151
other_tiles_with_same_ukeire = [
151152
x for x in filtered_options if getattr(x, ukeire_field) == getattr(first_option, ukeire_field)
@@ -155,7 +156,7 @@ def choose_tile_to_discard(self, tiles, closed_hand, melds, for_open_hand=False)
155156
# or in tempai we can have several tiles with same ukeire
156157
if other_tiles_with_same_ukeire:
157158
return self._chose_first_option_or_safe_tiles(
158-
sorted(other_tiles_with_same_ukeire, key=lambda x: x.valuation), discard_options
159+
sorted(other_tiles_with_same_ukeire, key=lambda x: x.valuation), discard_options, for_open_hand
159160
)
160161

161162
# we have only one candidate to discard with greater ukeire
@@ -397,9 +398,15 @@ def calculate_second_level_ukeire(self, discard_option, tiles, melds):
397398
# restore original state of player hand
398399
self.player.tiles = player_tiles_original
399400

400-
def _chose_first_option_or_safe_tiles(self, chosen_candidates, all_discard_options):
401+
def _chose_first_option_or_safe_tiles(self, chosen_candidates, all_discard_options, for_open_hand):
402+
# it looks like everything is fine
401403
if len(chosen_candidates):
402404
return chosen_candidates[0]
405+
# we don't want to open hand in that case
406+
elif for_open_hand:
407+
return None
408+
409+
# we can't discard effective tile from the hand, let's fold
403410
DecisionsLogger.debug(log.DISCARD_SAFE_TILE, "There are only dangerous tiles. Discard safest tile.")
404411
return sorted(all_discard_options, key=lambda x: x.danger.get_max_danger())[0]
405412

project/game/ai/strategies/main.py

+52-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import utils.decisions_constants as log
22
from mahjong.tile import TilesConverter
3-
from mahjong.utils import is_aka_dora, is_chi, is_honor, is_man, is_pin, is_pon, is_sou, is_terminal, plus_dora
3+
from mahjong.utils import (
4+
is_aka_dora,
5+
is_chi,
6+
is_honor,
7+
is_man,
8+
is_pin,
9+
is_pon,
10+
is_sou,
11+
is_terminal,
12+
plus_dora,
13+
simplify,
14+
)
415
from utils.decisions_logger import DecisionsLogger, MeldPrint
516

617

@@ -178,7 +189,11 @@ def try_to_call_meld(self, tile, is_kamicha_discard, new_tiles):
178189
if not possible_melds:
179190
return None, None
180191

181-
chosen_meld = self._find_best_meld_to_open(possible_melds, new_tiles, closed_hand, tile)
192+
chosen_meld = self._find_best_meld_to_open(tile, possible_melds, new_tiles, closed_hand, tile)
193+
# we didn't find a good discard candidate after open meld
194+
if not chosen_meld:
195+
return None, None
196+
182197
selected_tile = chosen_meld["discard_tile"]
183198
meld = chosen_meld["meld"]
184199

@@ -232,7 +247,7 @@ def calculate_dora_count(self, tiles_136):
232247
self.dora_count_central += self.aka_dora_count
233248
self.dora_count_total = self.dora_count_central + self.dora_count_not_central
234249

235-
def _find_best_meld_to_open(self, possible_melds, new_tiles, closed_hand, discarded_tile):
250+
def _find_best_meld_to_open(self, call_tile_136, possible_melds, new_tiles, closed_hand, discarded_tile):
236251
discarded_tile_34 = discarded_tile // 4
237252

238253
final_results = []
@@ -264,6 +279,36 @@ def _find_best_meld_to_open(self, possible_melds, new_tiles, closed_hand, discar
264279
new_tiles, closed_hand_copy, melds, for_open_hand=True
265280
)
266281

282+
# we can't find a good discard candidate, so let's skip this
283+
if not selected_tile:
284+
continue
285+
286+
# kuikae
287+
# we can't discard the same tile
288+
# or tile from the same suji
289+
if not is_honor(selected_tile.tile_to_discard):
290+
call_tile_34 = call_tile_136 // 4
291+
292+
if is_sou(selected_tile.tile_to_discard) and is_sou(call_tile_34):
293+
same_suit = True
294+
elif is_man(selected_tile.tile_to_discard) and is_man(call_tile_34):
295+
same_suit = True
296+
elif is_pin(selected_tile.tile_to_discard) and is_pin(call_tile_34):
297+
same_suit = True
298+
else:
299+
same_suit = False
300+
301+
if same_suit:
302+
simplified_call = simplify(call_tile_136 // 4)
303+
simplified_discard = simplify(selected_tile.tile_to_discard)
304+
if simplified_discard in [simplified_call - 3, simplified_call, simplified_call + 3]:
305+
tile_str = TilesConverter.to_one_line_string([selected_tile.tile_to_discard * 4])
306+
DecisionsLogger.debug(
307+
log.MELD_DEBUG,
308+
f"Kuikae discard {tile_str} candidate. Abort this tile melding.",
309+
)
310+
continue
311+
267312
final_results.append(
268313
{
269314
"discard_tile": selected_tile,
@@ -272,6 +317,10 @@ def _find_best_meld_to_open(self, possible_melds, new_tiles, closed_hand, discar
272317
}
273318
)
274319

320+
if not final_results:
321+
DecisionsLogger.debug(log.MELD_DEBUG, "There are no good discards after melding.")
322+
return None
323+
275324
final_results = sorted(
276325
final_results,
277326
key=lambda x: (x["discard_tile"].shanten, -x["discard_tile"].ukeire, x["discard_tile"].valuation),

0 commit comments

Comments
 (0)