public AnalyzeResult<T> solve() {
		List<RuleConstraint<T>> original = new ArrayList<RuleConstraint<T>>(this.rules.size());
		for (RuleConstraint<T> rule : this.rules) {
			original.add(rule.copy());
		}
		
		List<RuleConstraint<T>> inProgress = new ArrayList<RuleConstraint<T>>(this.rules.size());
		for (RuleConstraint<T> rule : this.rules) {
			inProgress.add(rule.copy());
		}
		
		final List<Solution<T>> solutions = new ArrayList<Solution<T>>();
		
		this.splitFieldRules(inProgress);

        SolveListener<T> solveListener = listener != null ? listener : new SolveListener<T>() {
            @Override
            public void onValueSet(Analyze<T> analyze, FieldGroup<T> group, int value) {
                // no operation
            }
        };
        GameAnalyze<T> analyze = new GameAnalyze<T>(interruptCheck, null, inProgress, 0, solveListener);
		double total = analyze.solve(solutions);
		
		for (Solution<T> solution : solutions) {
			solution.setTotal(total);
		}
		
		List<FieldGroup<T>> groups = new ArrayList<FieldGroup<T>>();
		if (!solutions.isEmpty()) {
			for (FieldGroup<T> group : solutions.get(0).getSetGroupValues().keySet()) {
				// All solutions should contain the same fieldgroups.
				groups.add(group);
			}
		}
		AnalyzeResultsImpl<T> result = new AnalyzeResultsImpl<T>(original, inProgress, groups, solutions, total);
		return result;
	}