def test_dont_go_for_honitsu_with_ryanmen_in_other_suit(self): table = Table() player = table.player strategy = HonitsuStrategy(BaseStrategy.HONITSU, player) tiles = self._string_to_136_array(man='14489', sou='45', pin='67', honors='44456') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False)
def determine_strategy(self): # for already opened hand we don't need to give up on selected strategy if self.player.is_open_hand and self.current_strategy: return False old_strategy = self.current_strategy self.current_strategy = None # order is important strategies = [ YakuhaiStrategy(BaseStrategy.YAKUHAI, self.player), HonitsuStrategy(BaseStrategy.HONITSU, self.player), ] if self.player.table.has_open_tanyao: strategies.append(TanyaoStrategy(BaseStrategy.TANYAO, self.player)) for strategy in strategies: if strategy.should_activate_strategy(): self.current_strategy = strategy if self.current_strategy: if not old_strategy or self.current_strategy.type != old_strategy.type: message = '{} switched to {} strategy'.format(self.player.name, self.current_strategy) if old_strategy: message += ' from {}'.format(old_strategy) logger.info(message) logger.info('With such a hand: {}'.format(TilesConverter.to_one_line_string(self.player.tiles))) if not self.current_strategy and old_strategy: logger.debug('{} gave up on {}'.format(self.player.name, old_strategy)) return self.current_strategy and True or False
def test_open_suit_same_shanten(self): table = Table() player = table.player player.scores = 25000 table.count_of_remaining_tiles = 100 tiles = self._string_to_136_array(man='1134556', pin='3', sou='78', honors='777') player.init_hand(tiles) meld = self._make_meld(Meld.CHI, man='345') player.add_called_meld(meld) strategy = HonitsuStrategy(BaseStrategy.HONITSU, player) self.assertEqual(strategy.should_activate_strategy(player.tiles), True) tile = self._string_to_136_tile(man='1') meld, _ = player.try_to_call_meld(tile, True) self.assertNotEqual(meld, None) self.assertEqual(self._to_string(meld.tiles), '111m')
def test_should_activate_strategy(self): table = Table() player = table.player strategy = HonitsuStrategy(BaseStrategy.HONITSU, player) tiles = self._string_to_136_array(sou='12355', man='12389', honors='123') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) tiles = self._string_to_136_array(sou='12355', man='238', honors='11234') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), True) # with hand without pairs we not should go for honitsu, # because it is far away from tempai tiles = self._string_to_136_array(sou='12358', man='238', honors='12345') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False) # with chitoitsu-like hand we don't need to go for honitsu tiles = self._string_to_136_array(pin='77', man='3355677899', sou='11') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(), False)
def test_suitable_tiles(self): table = Table() player = table.player strategy = HonitsuStrategy(BaseStrategy.HONITSU, player) tiles = self._string_to_136_array(sou='12355', man='238', honors='23455') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), True) tile = self._string_to_136_tile(man='1') self.assertEqual(strategy.is_tile_suitable(tile), False) tile = self._string_to_136_tile(pin='1') self.assertEqual(strategy.is_tile_suitable(tile), False) tile = self._string_to_136_tile(sou='1') self.assertEqual(strategy.is_tile_suitable(tile), True) tile = self._string_to_136_tile(honors='1') self.assertEqual(strategy.is_tile_suitable(tile), True)
def determine_strategy(self, tiles_136): # for already opened hand we don't need to give up on selected strategy if self.player.is_open_hand and self.current_strategy: return False old_strategy = self.current_strategy self.current_strategy = None # order is important, we add strategies with the highest priority first strategies = [] if self.player.table.has_open_tanyao: strategies.append(TanyaoStrategy(BaseStrategy.TANYAO, self.player)) strategies.append(YakuhaiStrategy(BaseStrategy.YAKUHAI, self.player)) strategies.append(HonitsuStrategy(BaseStrategy.HONITSU, self.player)) strategies.append(ChinitsuStrategy(BaseStrategy.CHINITSU, self.player)) strategies.append(ChiitoitsuStrategy(BaseStrategy.CHIITOITSU, self.player)) strategies.append(FormalTempaiStrategy(BaseStrategy.FORMAL_TEMPAI, self.player)) for strategy in strategies: if strategy.should_activate_strategy(tiles_136): self.current_strategy = strategy break if self.current_strategy: if not old_strategy or self.current_strategy.type != old_strategy.type: DecisionsLogger.debug( log.STRATEGY_ACTIVATE, context=self.current_strategy, ) if not self.current_strategy and old_strategy: DecisionsLogger.debug(log.STRATEGY_DROP, context=old_strategy) return self.current_strategy and True or False
def should_activate_strategy(self, tiles_136): """ We can go for chinitsu strategy if we have prevalence of one suit """ result = super(ChinitsuStrategy, self).should_activate_strategy(tiles_136) if not result: return False # when making decisions about chinitsu, we should consider # the state of our own hand, tiles_34 = TilesConverter.to_34_array(self.player.tiles) suits = count_tiles_by_suits(tiles_34) suits = [x for x in suits if x['name'] != 'honor'] suits = sorted(suits, key=lambda x: x['count'], reverse=True) suit = suits[0] count_of_shuntsu_other_suits = 0 count_of_koutsu_other_suits = 0 count_of_shuntsu_other_suits += HonitsuStrategy._count_of_shuntsu(tiles_34, suits[1]['function']) count_of_shuntsu_other_suits += HonitsuStrategy._count_of_shuntsu(tiles_34, suits[2]['function']) count_of_koutsu_other_suits += HonitsuStrategy._count_of_koutsu(tiles_34, suits[1]['function']) count_of_koutsu_other_suits += HonitsuStrategy._count_of_koutsu(tiles_34, suits[2]['function']) # we need to have at least 9 tiles of one suit to fo for chinitsu if suit['count'] < 9: return False # here we only check doras in different suits, we will deal # with honors later self._initialize_chinitsu_dora_count(tiles_136, suit) # 3 non-isolated doras in other suits is too much # to even try if self.dora_count_not_suitable >= 3: return False if self.dora_count_not_suitable == 2: # 2 doras in other suits, no doras in our suit # let's not consider chinitsu if self.dora_count_suitable == 0: return False # we have 2 doras in other suits and we # are 1 shanten, let's not rush chinitsu if self.player.ai.shanten == 1: return False # too late to get rid of doras in other suits if self.player.round_step > 8: return False # we are almost tempai, chinitsu is slower if suit['count'] == 9 and self.player.ai.shanten == 1: return False # only 10 tiles by 8th turn is too slow, considering alternative if suit['count'] == 10 and self.player.ai.shanten == 1 and self.player.round_step > 8: return False # if we have a pon of honors, let's not go for chinitsu honor_pons = len([x for x in range(0, 34) if is_honor(x) and tiles_34[x] >= 3]) if honor_pons >= 1: return False # if we have a valued pair, let's not go for chinitsu valued_pairs = len([x for x in self.player.valued_honors if tiles_34[x] == 2]) if valued_pairs >= 1: return False # if we have a pair of honor doras, let's not go for chinitsu honor_doras_pairs = len([x for x in range(0, 34) if is_honor(x) and tiles_34[x] == 2 and plus_dora(x * 4, self.player.table.dora_indicators)]) if honor_doras_pairs >= 1: return False # if we have a honor pair, we will only throw them away if it's early in the game # and if we have lots of tiles in our suit honor_pairs = len([x for x in range(0, 34) if is_honor(x) and tiles_34[x] == 2]) if honor_pairs >= 2: return False if honor_pairs == 1: if suit['count'] < 11: return False if self.player.round_step > 8: return False # if we have a complete set in other suits, we can only throw it away if it's early in the game if count_of_shuntsu_other_suits + count_of_koutsu_other_suits >= 1: # too late to throw away chi after 8 step if self.player.round_step > 8: return False # already 1 shanten, no need to throw away complete set if self.player.round_step > 5 and self.player.ai.shanten == 1: return False # dora is not isolated and we have a complete set, let's not go for chinitsu if self.dora_count_not_suitable >= 1: return False self.chosen_suit = suit['function'] return True
def test_should_activate_strategy(self): table = Table() player = table.player strategy = HonitsuStrategy(BaseStrategy.HONITSU, player) table.add_dora_indicator(self._string_to_136_tile(pin='1')) table.add_dora_indicator(self._string_to_136_tile(honors='5')) tiles = self._string_to_136_array(sou='12355', man='12389', honors='123') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # many tiles in one suit and yakuhai pair, but still many useless winds tiles = self._string_to_136_array(sou='12355', man='23', pin='68', honors='2355') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # many tiles in one suit and yakuhai pair and another honor pair, so # now this is honitsu tiles = self._string_to_136_array(sou='12355', man='238', honors='22355') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), True) # same conditions, but ready suit with dora in another suit, so no honitsu tiles = self._string_to_136_array(sou='12355', pin='234', honors='22355') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # same conditions, but we have a pon of yakuhai doras, we shouldn't # force honitsu with this hand tiles = self._string_to_136_array(sou='12355', pin='238', honors='22666') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # if we have a complete set with dora, we shouldn't go for honitsu tiles = self._string_to_136_array(sou='11123688', pin='123', honors='55') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # even if the set may be interpreted as two forms tiles = self._string_to_136_array(sou='1223688', pin='2334', honors='55') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # even if the set may be interpreted as two forms v2 tiles = self._string_to_136_array(sou='1223688', pin='2345', honors='55') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False) # if we have a long form with dora, we shouldn't go for honitsu tiles = self._string_to_136_array(sou='1223688', pin='2333', honors='55') player.init_hand(tiles) self.assertEqual(strategy.should_activate_strategy(player.tiles), False)