def _win_selections_in_tiles(self, hand: TileSet, max_used_tiles_count, ignore_4counts, current_state: WinPattern, borrow_limits: TileSet, searching_start: List[Tile]): if sum((-hand).values()) > max_used_tiles_count: return if ignore_4counts and not all(cnt >= borrow_limits[tile] for tile, cnt in hand.items()): return if current_state.has_win(): yield [], TileSet(-hand) if current_state.need_count() > sum((+hand).values()) + max_used_tiles_count: return hand = hand.copy() for tile in searching_start.copy(): for unit, state in current_state.next_states(tile): hand_temp = hand.copy() hand_temp.subtract(unit) yield from (([unit] + tail, remains) for tail, remains in self._win_selections_in_tiles(hand_temp, max_used_tiles_count, ignore_4counts, state, borrow_limits, searching_start.copy())) if hand[tile] >= 0: del hand[tile] searching_start.remove(tile)
def _win_selections_in_tiles(self, hand: TileSet, ignore_4counts, current_state: WinPattern, borrow_limits: TileSet, searching_group: List[List[Tile]], borrowed_stage, waiting_step_pruning): # if borrowed_tile_count(hand) > self.max_used_tiles: # return if ignore_4counts and not all(cnt >= borrow_limits[tile] for tile, cnt in hand.items()): return if current_state.has_win(): borrowed = TileSet(-hand) borrowed_count = sum(borrowed.values()) self.max_used_tiles = borrowed_count - waiting_step_pruning logging.debug("found borrowing %s", borrowed) yield borrowed_count, [], borrowed return # if current_state.need_count() > sum((+hand).values()) + self.max_used_tiles: # return hand = hand.copy() basic_hand_borrowed = borrowed_tile_count(hand) for can_borrowed in range(borrowed_stage, current_state.max_unit_length() + 1): min_used_tiles = current_state.need_units() * can_borrowed searching_round_old = searching_group[can_borrowed] searching_round = searching_round_old.copy() temp_searching_group = searching_group.copy() temp_searching_group[can_borrowed] = searching_round hand_round = hand for tile in searching_round.copy(): for unit, state in current_state.next_states(tile): if basic_hand_borrowed + min_used_tiles <= self.max_used_tiles: logging.debug("test %s in %s at borrow stage %d", unit, hand, can_borrowed) hand_temp = hand_round.copy() hand_temp.subtract(unit) borrowed_new = borrowed_tile_count(hand_temp) if borrowed_new - basic_hand_borrowed == can_borrowed: logging.debug("search %s in %s borrowed %s", unit, hand, TileSet(-hand)) yield from ((cnt, [unit] + patterns, borrowed) for cnt, patterns, borrowed in self._win_selections_in_tiles(hand_temp, ignore_4counts, state, borrow_limits, temp_searching_group, can_borrowed, waiting_step_pruning)) else: logging.debug("%s plan to borrowing out of range %d", hand, self.max_used_tiles - basic_hand_borrowed) return searching_round.remove(tile)
def need_to_borrow(hand: TileSet, unit: TileSet): hand = hand.copy() hand.subtract(unit) return borrowed_tile_count(hand)