private double solveRules(List<Solution<T>> solutions) {
		if (interruptCheck.isInterrupted()) {
    		throw new RuntimeTimeoutException();
		}
		
		if (this.rules.isEmpty()) {
			return 0;
        }

		FieldGroup<T> chosenGroup = getSmallestFieldGroup();
		if (chosenGroup == null) {
			throw new IllegalStateException("Chosen group is null: " + this.rules);
		}
		int groupSize = chosenGroup.size();
		
		if (groupSize == 0) {
			throw new IllegalStateException("Chosen group is empty. " + chosenGroup);
		}
		double total = 0;
		for (int i = 0; i <= groupSize; i++) {
			GroupValues<T> mapCopy = new GroupValues<T>(this.knownValues);
			mapCopy.put(chosenGroup, i);
			
			List<RuleConstraint<T>> rulesCopy = new ArrayList<RuleConstraint<T>>(); // deep copy!
			for (RuleConstraint<T> rule : this.rules) {
				rulesCopy.add(rule.copy());
			}

            GameAnalyze<T> copy = new GameAnalyze<T>(interruptCheck, mapCopy, rulesCopy, depth + 1, this.listener);
            int rulesCountBefore = copy.rules.size();
            listener.onValueSet(copy, chosenGroup, i);
            int rulesCountAfter = copy.rules.size();
            if (rulesCountBefore != rulesCountAfter) {
                // onValueSet has added rules
                AnalyzeFactory.splitFieldRules(copy.rules);
            }
			total += copy.solve(solutions);
		}
		return total;
	}