class RandomCartesianProductMoveIterator extends SelectionIterator<Move<Solution_>> {

        private List<Iterator<Move<Solution_>>> moveIteratorList;
        private Boolean empty;

        public RandomCartesianProductMoveIterator() {
            moveIteratorList = new ArrayList<>(childMoveSelectorList.size());
            empty = null;
            for (MoveSelector<Solution_> moveSelector : childMoveSelectorList) {
                moveIteratorList.add(moveSelector.iterator());
            }
        }

        @Override
        public boolean hasNext() {<FILL_FUNCTION_BODY>}

        @Override
        public Move<Solution_> next() {
            List<Move<Solution_>> moveList = new ArrayList<>(moveIteratorList.size());
            for (int i = 0; i < moveIteratorList.size(); i++) {
                Iterator<Move<Solution_>> moveIterator = moveIteratorList.get(i);
                boolean skip = false;
                if (!moveIterator.hasNext()) {
                    MoveSelector<Solution_> moveSelector = childMoveSelectorList.get(i);
                    moveIterator = moveSelector.iterator();
                    moveIteratorList.set(i, moveIterator);
                    if (!moveIterator.hasNext()) {
                        if (ignoreEmptyChildIterators) {
                            skip = true;
                        } else {
                            throw new NoSuchElementException("The iterator of childMoveSelector (" + moveSelector
                                    + ") is empty.");
                        }
                    }
                }
                if (!skip) {
                    moveList.add(moveIterator.next());
                }
            }
            if (ignoreEmptyChildIterators) {
                if (moveList.isEmpty()) {
                    throw new NoSuchElementException("All iterators of childMoveSelectorList (" + childMoveSelectorList
                            + ") are empty.");
                } else if (moveList.size() == 1) {
                    return moveList.get(0);
                }
            }
            return new CompositeMove<>(moveList.toArray(new Move[0]));
        }

    }

            if (empty == null) { // Only done in the first call
                int emptyCount = 0;
                for (Iterator<Move<Solution_>> moveIterator : moveIteratorList) {
                    if (!moveIterator.hasNext()) {
                        emptyCount++;
                        if (!ignoreEmptyChildIterators) {
                            break;
                        }
                    }
                }
                empty = ignoreEmptyChildIterators ? emptyCount == moveIteratorList.size() : emptyCount > 0;
            }
            return !empty;
        
<methods>public List<MoveSelector<Solution_>> getChildMoveSelectorList() ,public boolean isCountable() ,public boolean supportsPhaseAndSolverCaching() ,public java.lang.String toString() <variables>protected final non-sealed List<MoveSelector<Solution_>> childMoveSelectorList,protected final non-sealed boolean randomSelection