• 1 Post
  • 3 Comments
Joined 3Y ago
cake
Cake day: May 05, 2022

help-circle
rss

::: spoiler alt ```c++ #include <type_traits> // from https://stackoverflow.com/a/8625010/12469275 // cmath's sqrt is constexpr from c++26 constexpr std::size_t isqrt_impl (std::size_t sq, std::size_t dlt, std::size_t value){ return sq <= value ? isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1; } constexpr std::size_t isqrt(std::size_t value){ return isqrt_impl(1, 3, value); } // because pack indexing is only in c++26 template <std::size_t I, typename T = void, std::size_t... V> struct At; template <std::size_t I> struct At<I, void> {}; template <std::size_t V0, std::size_t... V> struct At<0, void, V0, V...> { static const std::size_t value = V0; }; template <std::size_t I, std::size_t V0, std::size_t... V> struct At<I, std::enable_if_t<I != 0 && I <= sizeof...(V),void>, V0, V...> { static const std::size_t value = At<I-1, void, V...>::value; }; template <std::size_t A, std::size_t B> struct Add { static const std::size_t value = A + B; }; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, typename _, std::size_t... V> struct _ReduceFor; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V> struct _ReduceFor<begin, end, step, R, I, std::enable_if_t<(begin < end),void>, V...> { typedef R<At<begin,void, V...>::value,_ReduceFor<begin+step, end, step, R, I, void, V...>::type::value> type; }; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V> struct _ReduceFor<begin, end, step, R, I, std::enable_if_t<(begin >= end), void>, V...> { typedef std::integral_constant<std::size_t,I> type; }; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V> using ReduceFor = _ReduceFor<begin,end,step,R,I,void,V...>; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T, typename _> struct AllFor; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T> struct AllFor<begin, end, step, V, T, std::enable_if_t<(begin < end), void>> { typedef std::enable_if_t<std::is_same<typename V<begin, bool>::type, bool>::value, typename AllFor<begin+step, end, step, V, T, void>::type> type; }; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T> struct AllFor<begin, end, step, V, T, std::enable_if_t<(begin >= end), void>> { typedef T type; }; template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T> using AllFor_t = typename AllFor<begin, end, step, V, T, void>::type; template <std::size_t S, typename T, std::size_t... V> struct ValidRows { template <std::size_t I, typename T2> struct Inner { typedef std::enable_if_t<ReduceFor<I, I+S, 1, Add, 0, V...>::type::value == S * (S*S + 1)/2, T2> type; }; typedef AllFor_t<0, S*S, S, Inner, T> type; }; template <std::size_t S, typename T, std::size_t... V> struct ValidColumns { template <std::size_t I, typename T2> struct Inner { typedef std::enable_if_t<ReduceFor<I, I+S*S, S, Add, 0, V...>::type::value == S * (S*S + 1)/2, T2> type; }; typedef AllFor_t<0, S, 1, Inner, T> type; }; template <std::size_t S, typename T, std::size_t... V> struct ValidDiags { typedef std::enable_if_t<ReduceFor<0,S*S,S+1,Add, 0, V...>::type::value == S * (S*S + 1)/2 && ReduceFor<S-1,S*S-1,S-1,Add, 0, V...>::type::value == S * (S*S + 1)/2, T> type; }; template <typename T, std::size_t... V> struct Unique; template <typename T, std::size_t N, std::size_t... V> struct Unique<T,N,V...> { template <std::size_t I, typename T2> struct Inner { typedef std::enable_if_t<N != At<I,void,V...>::value,T2> type; }; typedef AllFor_t<0,sizeof...(V),1,Inner,T> type; }; template <typename T, std::size_t V> struct Unique<T, V> { typedef T type; }; template <typename T, std::size_t... V> struct InRange { template <std::size_t I, typename T2> struct Inner { typedef typename std::enable_if<1 <= At<I,void, V...>::value && At<I,void,V...>::value <= sizeof...(V), T2>::type type; }; typedef AllFor_t<0,sizeof...(V),1,Inner,T> type; }; template <typename T, std::size_t... V> struct Grid { static const std::size_t S = isqrt(sizeof...(V)); typedef std::enable_if_t<S*S == sizeof...(V), typename ValidRows<S, typename ValidColumns<S, typename ValidDiags<S, typename Unique<typename InRange<T,V...>::type, V...>::type, V...>::type, V...>::type, V...>::type> type; }; using ok = Grid<void, 2, 7, 6, 9, 5, 1, 4, 3, 8>::type; int main() {} ``` :::
fedilink


TL;DR: Grid<A,B,C,D,E,F,G,H> simplifies to true, if and only if it is a 3x3 magic square.

full explanation
  • Fifteen is an array of length 15
  • T<A,B,C> checks if an array of length A+B+C is equivalent to an array of length 15, thus checking if A+B+C is equal to 15
  • And<A,X> is simplifies to X if A is true, else it simplifies to false
  • Df<A,B,X> checks if A and B are Diffrent , simplifying to X if they are
  • Grid<A,B,C,D,E,F,G,H> first checks if every row, column and diagonal is equal to 15, then checks if every item is unique.