/*

 Provide "int limits[MAXMARKS]" to the rest of the algorithm
 Uses: MAXMARKS, maxmarks, maxlength, depth, dist[][0]
 
 */

#include "chooseV3_12_12.h"
//#include "chooseV3_15_13!.h"
//#include "chooseV3_16_12.h"
#define MINIMUM(x,y) ((x<y) ? (x) : (y))
#define KTEST 1  /* NOTE: KTEST restricts your ability to find very short OGRs
                         e.g. using KTEST=0 you can find all OGRs (except OGR-0 though OGR-2 but these are trivial)
                              using KTEST=1 you cannot reliably find OGRs <= OGR-4
                              using KTEST=2 you cannot reliably find OGRs <= OGR-6 */

/* Use KTEST=0 for <= OGR-14
   Use KTEST=1 for >= OGR-15 (reduces the nodecount!!!)
   Use KTEST=2 ???
*/

#if (KTEST>0) && (CHOOSEMARKS<=(KTEST*2)+1)
/* calculation of halflength requires (CHOOSEMARKS>halfdepth2-halfdepth1) */
/* e.g.: COOSEMARKS > 3 for KTEST 1, > 5 for KTEST 2, > 7 for KTEST 3,... */
#error please use a choosefile with more CHOOSEMARKS or reduce KTEST
#endif


const uint32_t OGRdist[32][16] = {
/* OGR-01 */ {
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-02 */ {
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-03 */ {
/* 11100000000000000000000000000000 */ 0xe0000000,
/* 10100000000000000000000000000000 */ 0xa0000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-04 */ {
/* 11111100000000000000000000000000 */ 0xfc000000,
/* 11010000000000000000000000000000 */ 0xd0000000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-05 */ {
/* 11111011101000000000000000000000 */ 0xfba00000,
/* 11100000100000000000000000000000 */ 0xe0800000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-06 */ {
/* 11111110101010011000000000000000 */ 0xfea98000,
/* 11111110001000000000000000000000 */ 0xfe200000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-07 */ {
/* 11111110100001000110011010000000 */ 0xfe846680,
/* 11100100100000000000000000000000 */ 0xe4800000,
/* 11100000000000000000000000000000 */ 0xe0000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-08 */ {
/* 11111111111111101110111010010111 */ 0xfffeee97,
/* 11111101101100000010000000000000 */ 0xfdb02000,
/* 11111100000000000000000000000000 */ 0xfc000000,
/* 11010000000000000000000000000000 */ 0xd0000000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-09 */ {
/* 11111111111111111011011111101101 */ 0xffffb7ed,
/* 11111111111111110000001101101000 */ 0xffff0368,
/* 11111110111001110000000000100000 */ 0xfee70020,
/* 11101110000000010000000000000000 */ 0xee010000,
/* 10100000000000000000000000000000 */ 0xa0000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-10 */ {
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111101111111111011111 */ 0xfffeffdf,
/* 11111111111111100111111000001101 */ 0xfffe7e0d,
/* 10101110111000100000000000000000 */ 0xaee20000,
/* 00001100000000000000000000000000 */ 0x0c000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-11 */ {
/* 11111111110111111111101110110011 */ 0xffdffbb3,
/* 11111111110111111111101110110011 */ 0xffdffbb3,
/* 11111111100000110010100000000000 */ 0xff832800,
/* 10111100100000000000000000000000 */ 0xbc800000,
/* 00100000000000000000000000000000 */ 0x20000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-12 */ {
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111110110101001100111000100 */ 0xffda99c4,
/* 11111010110010000001100000000000 */ 0xfac81800,
/* 11011000000010000000000000000000 */ 0xd8080000,
/* 11000000000000000000000000000000 */ 0xc0000000,
/* 01000000000000000000000000000000 */ 0x40000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-13 */ {
/* 11111111111111111111111011111101 */ 0xfffffefd,
/* 11111111111111111111111011111101 */ 0xfffffefd,
/* 11111111111111111111111011111101 */ 0xfffffefd,
/* 11111111111101110111001011100101 */ 0xfff772e5,
/* 11111110111001110111001011100001 */ 0xfee772e1,
/* 11111000110000010101000011000000 */ 0xf8c150c0,
/* 11100000000000000000000000000000 */ 0xe0000000,
/* 01000000000000000000000000000000 */ 0x40000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-14 */ {
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111111111111 */ 0xffffffff,
/* 11111111111111111111111110101000 */ 0xffffffa8,
/* 11111111111111110111111110000000 */ 0xffff7f80,
/* 11110111111110100101000110000000 */ 0xf7fa5180,
/* 11110111011100100001000010000000 */ 0xf7721080,
/* 11110100001100000000000010000000 */ 0xf4300080,
/* 11110100001000000000000000000000 */ 0xf4200000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-15 */ {
/* 11111111111111111011111111111101 */ 0xffffbffd,
/* 11111111111111111010110101011100 */ 0xffffad5c,
/* 11111111111111110010110100011000 */ 0xffff2d18,
/* 11111111111111110010110100011000 */ 0xffff2d18,
/* 10111111111111110010100100001000 */ 0xbfff2908,
/* 10111101111010100010100100001000 */ 0xbdea2908,
/* 10100000111010000000000000000000 */ 0xa0e80000,
/* 10100000111010000000000000000000 */ 0xa0e80000,
/* 10000000000000000000000000000000 */ 0x80000000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-16 */ {
/* 11111111111111111111110111111111 */ 0xfffffdff,
/* 11111111111111111111110111101110 */ 0xfffffdee,
/* 11111111111111111111100111001110 */ 0xfffff9ce,
/* 11111111111111111011000111001110 */ 0xffffb1ce,
/* 11111111111111101011000001000110 */ 0xfffeb046,
/* 11110110101110001010000000000000 */ 0xf6b8a000,
/* 11100110001110000010000000000000 */ 0xe6382000,
/* 10000010001000000000000000000000 */ 0x82200000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-17 */ {
/* 11111111111111111011111111111111 */ 0xffffbfff,
/* 11111111111111111011111111111111 */ 0xffffbfff,
/* 11111111111111111011111111111111 */ 0xffffbfff,
/* 11111111111111111011111111111111 */ 0xffffbfff,
/* 11111111111110011011111111011111 */ 0xfff9bfdf,
/* 11111111111110011011111111011111 */ 0xfff9bfdf,
/* 11111111110110011011111011001111 */ 0xffd9becf,
/* 11111111110100011011111001001111 */ 0xffd1be4f,
/* 11111111110100011011011001001111 */ 0xffd1b64f,
/* 11111111110100011011001001001111 */ 0xffd1b24f,
/* 11111001110100011010000000001101 */ 0xf9d1a00d,
/* 11111000110000001010000000001101 */ 0xf8c0a00d,
/* 01111000110000000010000000001001 */ 0x78c02009,
/* 00110000110000000000000000000000 */ 0x30c00000,
/* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-18 */ { /* 11111111111111111111111111111111 */ 0xffffffff ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-19 */ { /* 11111111111111111111111111111111 */ 0xffffffff ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-20 */ { /* 11111111111111111111111111111111 */ 0xffffffff ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-21 */ { /* 11111111111111111111111111110111 */ 0xfffffff7 ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-22 */ { /* 11111111111111111111111011111110 */ 0xfffffefe ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-23 */ { /* 11111111111111111111111111111111 */ 0xffffffff ,
               /* 00000000000000000000000000000000 */ 0x00000000},
/* OGR-24 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-25 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-26 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-27 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-28 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-29 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-30 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-31 */ { /* 00000000000000000000000000000000 */ 0x00000000 },
/* OGR-32 */ { /* 00000000000000000000000000000000 */ 0x00000000 }
};


#if (KTEST>1)

/*#define SETUP_LIMITS(MAXMARKS)                                                        		*/
#define SETUP_LIMITS                                                                 			\
const int OGR[32] = { /*  1 */    0,   1,   3,   6,  11,  17,  25,  34,  44,  55,  72,			\
                      /* 12 */   85, 106, 127, 151, 177, 199, 216, 246, 283, 333, 356,			\
                      /* 23 */  372, 425, 480, 492, 553, 585, 623, 680, 747, 784 };			\
const int halfdepth1 = (maxmarks/2)-KTEST;								\
const int halfdepth2 = (maxmarks/2)+(maxmarks%2)+KTEST;							\
int limit[MAXMARKS];	/* current limit, populated by limits.h (based on CHOOSE, MIDPOINT, etc.) */


/*#define CALCULATE_LIMITS(depth)									*/
#define CALCULATE_LIMITS	                 							\
/* CHOOSE */												\
if (CHOOSEMARKS>maxmarks-depth) {									\
    limit[depth] = maxlength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(maxmarks-depth)];		\
} else {												\
    int i=0;												\
    while ((GET_DIST_32 & OGRdist[maxmarks-depth][i]) != 0) {i++;}					\
    limit[depth] = maxlength-(OGR[maxmarks-depth]+i);							\
}													\
/* MIDPOINT */												\
if (depth <= halfdepth2) {										\
    if (depth <= halfdepth1) {										\
        int tempLimit;											\
        const int halflength = (maxlength-1-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth2-halfdepth1)])/2;	\
        if (CHOOSEMARKS>halfdepth1-depth) {								\
            tempLimit = halflength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth1-depth)];	\
        } else {											\
            tempLimit = halflength-OGR[halfdepth1-depth];						\
        }												\
        limit[depth]=MINIMUM(limit[depth],tempLimit);							\
    } else {												\
        const int tempLimit = (maxlength-1-count[halfdepth1])-(chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth2-depth)]);	\
        limit[depth]=MINIMUM(limit[depth],tempLimit);							\
    }													\
}


#elif (KTEST==1)

/*#define SETUP_LIMITS(MAXMARKS)                                                        		*/
#define SETUP_LIMITS                                                                 			\
const int OGR[32] = { /*  1 */    0,   1,   3,   6,  11,  17,  25,  34,  44,  55,  72,			\
                      /* 12 */   85, 106, 127, 151, 177, 199, 216, 246, 283, 333, 356,			\
                      /* 23 */  372, 425, 480, 492, 553, 585, 623, 680, 747, 784 };			\
const int halfdepth1 = (maxmarks/2)-KTEST;								\
const int halfdepth2 = (maxmarks/2)+(maxmarks%2)+KTEST;   						\
const int symmetry = (maxmarks%2 + maxlength%2 != 1) ? (maxlength-2) : (maxlength-1) ;			\
int limit[MAXMARKS];	/* current limit, populated by limits.h (based on CHOOSE, MIDPOINT, etc.) */


/*#define CALCULATE_LIMITS(depth)									*/
#define CALCULATE_LIMITS	                 							\
/* CHOOSE */												\
if (CHOOSEMARKS>maxmarks-depth) {									\
    limit[depth] = maxlength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(maxmarks-depth)];		\
} else {												\
    int i=0;												\
    while ((GET_DIST_32 & OGRdist[maxmarks-depth][i]) != 0) {i++;}					\
    limit[depth] = maxlength-(OGR[maxmarks-depth]+i);							\
}													\
/* MIDPOINT */												\
if (depth <= halfdepth2) {										\
    if (depth <= halfdepth1) {										\
        int tempLimit;											\
        /* halflength can be one less if certain symmetries apply */					\
        const int halflength = ((symmetry-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth2-halfdepth1)])/2);	\
        if (CHOOSEMARKS>halfdepth1-depth) {								\
            tempLimit = halflength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth1-depth)];	\
        } else {											\
            tempLimit = halflength-OGR[halfdepth1-depth];						\
        }												\
        limit[depth]=MINIMUM(limit[depth],tempLimit);							\
    } else {												\
        const int tempLimit = (maxlength-1-count[halfdepth1])-(chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth2-depth)]);	\
        limit[depth]=MINIMUM(limit[depth],tempLimit);							\
    }													\
}

#else // (KTEST==0)

/*#define SETUP_LIMITS(MAXMARKS)                                                        		*/
#define SETUP_LIMITS                                                                 			\
const int OGR[32] = { /*  1 */    0,   1,   3,   6,  11,  17,  25,  34,  44,  55,  72,			\
                      /* 12 */   85, 106, 127, 151, 177, 199, 216, 246, 283, 333, 356,			\
                      /* 23 */  372, 425, 480, 492, 553, 585, 623, 680, 747, 784 };			\
const int halfdepth1 = (maxmarks/2);									\
const int halflength = (!(maxmarks%2) && (maxlength%2)) ? (maxlength/2) : (maxlength/2)-1;		\
int limit[MAXMARKS];	/* current limit, populated by limits.h (based on CHOOSE, MIDPOINT, etc.) */


/*#define CALCULATE_LIMITS(depth)									*/
#define CALCULATE_LIMITS	                 							\
/* CHOOSE */												\
if (CHOOSEMARKS>maxmarks-depth) {									\
    limit[depth] = maxlength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(maxmarks-depth)];		\
} else {												\
    limit[depth] = maxlength-OGR[maxmarks-depth]; /* midpoint reduction may supercede this */		\
}													\
/* MIDPOINT */												\
if (depth<=halfdepth1) {										\
    int tempLimit;											\
    if (CHOOSEMARKS>halfdepth1-depth) {									\
        tempLimit = halflength-chooseV3[(GET_DIST_32>>(32-CHOOSEBITS))][(halfdepth1-depth)];		\
    } else {												\
        tempLimit = halflength-OGR[halfdepth1-depth];							\
    }													\
    limit[depth]=MINIMUM(limit[depth],tempLimit);							\
} else if ((depth==(halfdepth1+1)) && (maxmarks%2)) {							\
    const int tempLimit = maxlength-1-count[halfdepth1];						\
    limit[depth]=MINIMUM(limit[depth],tempLimit);							\
    /*printf("l%d r%d\n",count[halfdepth1],maxlength-1-count[halfdepth1]);*/				\
}



#endif

