private Result SolveRecursively(NodeState currentState)
        {
            // check if done:
            var collaboratingSensorGroups =
                currentState.Variables.Where(v => v.IsAssigned).GroupBy(v => v.AssignedValue).ToArray();
            var done = collaboratingSensorGroups.Length == DomainValues.Count &&
                       collaboratingSensorGroups.All(group => group.Count() == NeededSensorsForEachTargetNo);

            if (done)
            {
                return new Result()
                       {
                           AssignedVariables = currentState.Variables.ToDictionary(v => v.Name)
                       }
            }
            ;

            var variableToAssign = GetNextVariable(currentState);

            if (variableToAssign is null)
            {
                throw new CspPathFailure(currentState);
            }
            var stateBeforeGoingDeeper = currentState.Clone();

            foreach (var value in GetValueFor(variableToAssign))
            {
                if (!IsConsistent(currentState, variableToAssign, value))
                {
                    continue;
                }
                variableToAssign.AssignedValue = value.Value;
                variableToAssign.IsAssigned    = true;
                // forward checking
                UpdateCandidates(currentState.Variables, value);
                try
                {
                    return(SolveRecursively(currentState));
                }
                catch (CspPathFailure)
                {
                    currentState.GoBackToState(stateBeforeGoingDeeper);
                }
            }

            // try going deep leaving variableToAssign unassigned!
            variableToAssign.IsAncestorWithoutValue = true;
            try
            {
                return(SolveRecursively(currentState));
            }
            catch (CspPathFailure)
            {
                currentState.GoBackToState(stateBeforeGoingDeeper);
                throw;
            }
        }