class KOptListMoveSelectorFactory<Solution_>
        extends AbstractMoveSelectorFactory<Solution_, KOptListMoveSelectorConfig> {

    private static final int DEFAULT_MINIMUM_K = 2;
    private static final int DEFAULT_MAXIMUM_K = 2;

    public KOptListMoveSelectorFactory(KOptListMoveSelectorConfig moveSelectorConfig) {
        super(moveSelectorConfig);
    }

    @Override
    protected MoveSelector<Solution_> buildBaseMoveSelector(HeuristicConfigPolicy<Solution_> configPolicy,
            SelectionCacheType minimumCacheType, boolean randomSelection) {<FILL_FUNCTION_BODY>}

    private EntityIndependentValueSelector<Solution_> buildEntityIndependentValueSelector(
            HeuristicConfigPolicy<Solution_> configPolicy,
            EntityDescriptor<Solution_> entityDescriptor,
            ValueSelectorConfig valueSelectorConfig,
            SelectionCacheType minimumCacheType,
            SelectionOrder inheritedSelectionOrder) {
        ValueSelector<Solution_> valueSelector = ValueSelectorFactory.<Solution_> create(valueSelectorConfig)
                .buildValueSelector(configPolicy, entityDescriptor, minimumCacheType, inheritedSelectionOrder);
        if (!(valueSelector instanceof EntityIndependentValueSelector)) {
            throw new IllegalArgumentException("The kOptListMoveSelector (" + config
                    + ") for a list variable needs to be based on an "
                    + EntityIndependentValueSelector.class.getSimpleName() + " (" + valueSelector + ")."
                    + " Check your valueSelectorConfig.");

        }
        return (EntityIndependentValueSelector<Solution_>) valueSelector;
    }
}

        ValueSelectorConfig originSelectorConfig =
                Objects.requireNonNullElseGet(config.getOriginSelectorConfig(), ValueSelectorConfig::new);
        ValueSelectorConfig valueSelectorConfig =
                Objects.requireNonNullElseGet(config.getValueSelectorConfig(), ValueSelectorConfig::new);

        EntityDescriptor<Solution_> entityDescriptor = getTheOnlyEntityDescriptor(configPolicy.getSolutionDescriptor());

        EntityIndependentValueSelector<Solution_> originSelector =
                buildEntityIndependentValueSelector(configPolicy, entityDescriptor, originSelectorConfig, minimumCacheType,
                        SelectionOrder.fromRandomSelectionBoolean(randomSelection));
        EntityIndependentValueSelector<Solution_> valueSelector =
                buildEntityIndependentValueSelector(configPolicy, entityDescriptor, valueSelectorConfig, minimumCacheType,
                        SelectionOrder.fromRandomSelectionBoolean(randomSelection));
        // TODO support coexistence of list and basic variables https://issues.redhat.com/browse/PLANNER-2755
        GenuineVariableDescriptor<Solution_> variableDescriptor = getTheOnlyVariableDescriptor(entityDescriptor);
        if (!variableDescriptor.isListVariable()) {
            throw new IllegalArgumentException("The kOptListMoveSelector (" + config
                    + ") can only be used when the domain model has a list variable."
                    + " Check your @" + PlanningEntity.class.getSimpleName()
                    + " and make sure it has a @" + PlanningListVariable.class.getSimpleName() + ".");
        }

        int minimumK = Objects.requireNonNullElse(config.getMinimumK(), DEFAULT_MINIMUM_K);
        if (minimumK < 2) {
            throw new IllegalArgumentException("minimumK (" + minimumK + ") must be at least 2.");
        }
        int maximumK = Objects.requireNonNullElse(config.getMaximumK(), DEFAULT_MAXIMUM_K);
        if (maximumK < minimumK) {
            throw new IllegalArgumentException("maximumK (" + maximumK + ") must be at least minimumK (" + minimumK + ").");
        }

        int[] pickedKDistribution = new int[maximumK - minimumK + 1];
        // Each prior k is 8 times more likely to be picked than the subsequent k
        int total = 1;
        for (int i = minimumK; i < maximumK; i++) {
            total *= 8;
        }
        for (int i = 0; i < pickedKDistribution.length - 1; i++) {
            int remainder = total / 8;
            pickedKDistribution[i] = total - remainder;
            total = remainder;
        }
        pickedKDistribution[pickedKDistribution.length - 1] = total;
        return new KOptListMoveSelector<>(((ListVariableDescriptor<Solution_>) variableDescriptor),
                originSelector, valueSelector, minimumK, maximumK, pickedKDistribution);
    
<methods>public void <init>(org.optaplanner.core.config.heuristic.selector.move.generic.list.kopt.KOptListMoveSelectorConfig) ,public MoveSelector<Solution_> buildMoveSelector(HeuristicConfigPolicy<Solution_>, org.optaplanner.core.config.heuristic.selector.common.SelectionCacheType, org.optaplanner.core.config.heuristic.selector.common.SelectionOrder) <variables>