/// <summary> /// Computes each unique set of values of length <paramref name="boxSize"/> that can be /// formed from the given values. /// </summary> /// <param name="values"> /// All the possible values for the magic square. Each value must be unique. Values must /// have length `boxSize*boxSize`. /// </param> /// <param name="allPossibleValues"> /// The /// </param> public static HashSet <BitVector> ComputeSets(ReadOnlySpan <int> values, int boxSize, BitVector allPossibleValues) { if (values.Length != boxSize * boxSize) { throw new ArgumentException( $"{nameof(boxSize)} ({boxSize}) must be the exact square root of the length of {nameof(values)} ({values.Length})."); } if (allPossibleValues.ComputeCount() != values.Length) { throw new ArgumentException($"Expected {nameof(allPossibleValues)} to have the same length as {nameof(values)}."); } int magicSum = _ComputeSum(values, boxSize); var sets = new HashSet <BitVector>(); for (int i = 0; i < values.Length; ++i) { int possibleValue = values[i]; var set = new BitVector(); set.SetBit(possibleValue); BitVector possibleValues = allPossibleValues; possibleValues.UnsetBit(possibleValue); sets = new(sets.Union(_ComputeMagicSetsForRemainder(boxSize - 1, magicSum - possibleValue, possibleValues, set))); } return(sets); }
private static HashSet <BitVector> _ComputeMagicSetsForRemainder(int remainingSize, int remainder, BitVector possibleValues, BitVector partialSet) { var result = new HashSet <BitVector>(); if (remainingSize == 0) { if (remainder == 0) { result.Add(partialSet); } return(result); } Span <int> setBits = stackalloc int[BitVector.NumBits]; int numSetBits = possibleValues.PopulateSetBits(setBits); foreach (var possibleValue in setBits.Slice(0, numSetBits)) { if (remainder - possibleValue >= 0) { BitVector set = partialSet; set.SetBit(possibleValue); BitVector reducedPossibleValues = possibleValues; reducedPossibleValues.UnsetBit(possibleValue); result = new(result.Union(_ComputeMagicSetsForRemainder(remainingSize - 1, remainder - possibleValue, reducedPossibleValues, set))); } } return(result); }