Example #1
0
        /// <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);
        }
Example #2
0
        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);
        }