/// <summary> /// Introduces a new object and handles all the needed communicated with the normalization helper. /// </summary> /// <returns> /// <param name="theoremsToProve">The theorems that are still left to be proven.</param> /// The tuple of objects that got removed and the object that got introduced. The object list will never /// be null, but might be empty. Also, the number of removed objects might be bigger than the number of /// previously introduced ones, because the normalization helper might have found equal ones in the meantime. /// If there has been no introduces, then the new object will be null. /// </returns> public (IReadOnlyList <ConstructedConfigurationObject> removedObjects, ConstructedConfigurationObject newObject) IntroduceObject(IEnumerable <Theorem> theoremsToProve) { #region Handle object removal // Prepare the removed objects var removedObjects = new List <ConstructedConfigurationObject>(); // If the last introduced object was a point if (_lastIntroducedObject != null && _lastIntroducedObject.ObjectType == ConfigurationObjectType.Point) { // Let the normalization helper remove it, while returning everything what's been removed _helper.RemoveIntroducedObject(_lastIntroducedObject, out var removedObjectsLocal); // Mark the removed objects removedObjects.Add(removedObjectsLocal); } #endregion #region Handle object introduction // Find the object to introduce by calling the introducer var newObject = _introducer // With the available objects equal to those .IntroduceObjects(_helper.AllObjects // That are in the original configuration (otherwise it would be explosive) .Where(_helper.IsInOriginalConfiguration) // Enumerated .ToArray()) // Concat object introduced based on theorems to be proven .Concat(theoremsToProve.SelectMany(PerformTheoremBasedIntroduction)) // The introducer offers us some options that we need to normalize by copying the construction .Select(newObject => new ConstructedConfigurationObject(newObject.Construction, // And normalizing each of the argument objects newObject.PassedArguments.FlattenedList.Select(_helper.GetNormalVersionOfObjectOrNull).ToArray())) // When we have options normalize, we need to filter those objects that have been introduced already .Where(newObject => !_allIntroducedObjects.Contains(newObject) // And aren't already known to the helper && !_helper.AllObjects.Contains(newObject) // And haven't been ever known to the helper && !_helper.AllRemovedObjects.Contains(newObject)) // Enumerate .ToArray() // Sort them so that we first introduce non-points (lines and circles) .OrderBy(newObject => newObject.ObjectType == ConfigurationObjectType.Point ? 1 : 0) // Take the first option .FirstOrDefault(); // If there is something to be introduced if (newObject != null) { // Let the normalization helper know _helper.IntroduceNewObject(newObject); // Add the object to the set of all objects ever introduced _allIntroducedObjects.Add(newObject); } // Set the last introduced object _lastIntroducedObject = newObject; #endregion // Return the removed objects together with the new ones return(removedObjects, newObject); }