/*
test.c 組合せに対応する整数への変換とその逆変換のテストプログラム
programmed by Isaku WADA isaku@pb4.so-net.ne.jp
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "zcode.c"

#define SCR 23 /* 画面の行数 */

/*+----------+
 |配列の宣言|
 +----------+*/
char prev[80],next[80],buf[80]; int vec[80];

/*+------------------+
 |2つの表を書き出す|
 +------------------+*/
void Dump(int keta,int n,int r)
{
    int i,j;

    for (i=0;i<r;i++) {
        if (i==0) printf("A:"); else printf("  ");
        for (j=0;j<n;j++)
            printf("%*u",keta,DefaultCodeTable->a[i][j]);
        printf("%*s",keta,"");
        if (i==0) printf("B:"); else printf("  ");
        for (j=0;j<n;j++)
            printf("%*u",keta,DefaultCodeTable->b[i][j]);
        printf("\n");
    }
}

/*+------------------------------+
 |いわゆる組み合わせの変換テスト|
 +------------------------------+*/
void TestCombination(void)
{
    int n,r,j,err=0; unsigned k,s;

    printf("Combination(cn,r):checking ...\n     ");
    for (r=0;r<=11;r++) printf("  r=%2d",r);
    printf("\n");
    for (n=0;n<=18;n++) {
        printf("cn=%2d",n);
        for (r=0;r<=(n>11?11:n);r++) {
            s=InitComb(n,r);
            if (s==0) {
                err++;
                continue;
            }
            printf("%6u",s);
            for (k=0;k<s;k++) {
                NumToComb(vec,k);

                /* 小さい順かのテスト */
                for (j=1;j<r;j++) if (vec[j-1]>=vec[j])
                    err++;

                /* 辞書順で前の結果より大きいかどうかのテスト */
                for (j=0;j<r;j++) next[j]=(char)vec[j];
                if (k>=1&&memcmp(prev,next,r)>=0)
                    err++;
                memcpy(prev,next,r);

#ifndef NO_CODE_SORT
                for (j=0;j<r/2;j++)
                { int t=vec[j]; vec[j]=vec[r-j-1]; vec[r-j-1]=t; }
#endif
                /* 逆変換で元に戻るかのテスト */
                if (CombToNum(vec)!=k)
                    err++;
            }
        }
        printf("\n");
    }
    printf("ErrorCount=%d MaxCodeTableSize=%lu\n",err,MaxCodeTableSize);
}

/*+------------------------+
 |いわゆる組み合わせの確認|
 +------------------------+*/
void DemoCombination(void)
{
    int n,r,i,j; unsigned k,s;

    for (n=0;n<=9;n++) {
        for (r=0;r<=n;r++) {
            s=InitComb(n,r);
            if (s==0) continue;
            for (i=0;i<10;i++) printf("\n");
            printf(" InitComb(n,r)=(%d,%d) size=%u\n",n,r,s);
            Dump(4,n-r+1,r);
            if ((int)s>SCR-1-r) s=(unsigned)(SCR-1-r);
            for (k=0;k<s;k++) {
                NumToComb(vec,k);
                printf(" num=%-2u : ",k);
                if (r) {
                    printf("vec[]={%d",vec[0]);
                    for (j=1;j<r;j++) printf(",%d",vec[j]);
                    printf("}\n");
                } else printf("No Change\n");
            }
            for (i=0;i<SCR-1-r-(int)s;i++) printf("\n");
            printf(" HIT [ENTER] KEY > ");
            fgets(buf,sizeof buf,stdin);
        }
    }
}

/*+--------------------------+
 |分割組み合わせの変換テスト|
 +--------------------------+*/
void TestPartition(void)
{
    int n,r,j,err=0,sum; unsigned k,s;

    printf("Partition(sn,sr):checking ...\n     ");
    for (r=1;r<=10;r++) printf("  sr=%2d",r);
    printf("\n");
    for (n=0;n<=9;n++) {
        printf("sn=%2d",n);
        for (r=1;r<=10;r++) {
            s=InitPart(n,r);
            if (s==0) {
                err++;
                continue;
            }
            printf("%7u",s);
            for (k=0;k<s;k++) {
                NumToPart(vec,k);

                /* 合計がnになっているかどうかのテスト */
                for (sum=j=0;j<r;j++) sum+=vec[j];
                if (sum!=n)
                    err++;

                /* 辞書順で前の結果より大きいかどうかのテスト */
                for (j=0;j<r;j++) next[j]=(char)vec[j];
                if (k>=1&&memcmp(prev,next,r)>=0)
                    err++;
                memcpy(prev,next,r);

                /* 逆変換で元に戻るかのテスト */
                if (PartToNum(vec)!=k)
                    err++;
            }
        }
        printf("\n");
    }
    printf("ErrorCount=%d MaxCodeTableSize=%lu\n",err,MaxCodeTableSize);
}

/*+--------------------+
 |分割組み合わせの確認|
 +--------------------+*/
void DemoPartition(void)
{
    int n,r,i,j; unsigned k,s;

    for (n=0;n<=6;n++) {
        for (r=1;r<=6;r++) {
            s=InitPart(n,r);
            if (s==0) continue;
            for (i=0;i<10;i++) printf("\n");
            printf(" InitPart(n,r)=(%d,%d) size=%u\n",n,r,s);
            Dump(4,n+1,r-1);
            if ((int)s>SCR-r) s=(unsigned)(SCR-r);
            for (k=0;k<s;k++) {
                NumToPart(vec,k);
                printf(" num=%-2u : ",k);
                if (r) {
                    printf("vec[]={%d",vec[0]);
                    for (j=1;j<r;j++) printf(",%d",vec[j]);
                    printf("}\n");
                } else printf("No Change\n");
            }
            for (i=0;i<SCR-r-(int)s;i++) printf("\n");
            printf(" HIT [ENTER] KEY > ");
            fgets(buf,sizeof buf,stdin);
        }
    }
}

/*+--------------------------+
 |重複組み合わせの変換テスト|
 +--------------------------+*/
void TestRepeated(void)
{
    int n,r,j,err=0; unsigned k,s;

    printf("Repeated(n,r):checking ...\n     ");
    for (r=0;r<=9;r++) printf("   r=%2d",r);
    printf("\n");
    for (n=1;n<=10;n++) {
        printf("n=%2d ",n);
        for (r=0;r<=9;r++) {
            s=InitRepe(n,r);
            if (s==0) {
                err++;
                continue;
            }
            printf("%7u",s);
            for (k=0;k<s;k++) {
                NumToRepe(vec,k);

                /* 小さい順かのテスト */
                for (j=1;j<r;j++) if (vec[j-1]>vec[j])
                    err++;

                /* 辞書順で前の結果より大きいかどうかのテスト */
                for (j=0;j<r;j++) next[j]=(char)vec[j];
                if (k>=1&&memcmp(prev,next,r)>=0)
                    err++;
                memcpy(prev,next,r);

#ifndef NO_CODE_SORT
                for (j=0;j<r/2;j++)
                { int t=vec[j]; vec[j]=vec[r-j-1]; vec[r-j-1]=t; }
#endif
                /* 逆変換で元に戻るかのテスト */
                if (RepeToNum(vec)!=k)
                    err++;
            }
        }
        printf("\n");
    }
    printf("ErrorCount=%d MaxCodeTableSize=%lu\n",err,MaxCodeTableSize);
}

/*+--------------------+
 |重複組み合わせの確認|
 +--------------------+*/
void DemoRepeated(void)
{
    int n,r,i,j; unsigned k,s;

    for (n=1;n<=6;n++) {
        for (r=0;r<=6;r++) {
            s=InitRepe(n,r);
            if (s==0) continue;
            for (i=0;i<10;i++) printf("\n");
            printf(" InitRepe(n,r)=(%d,%d) size=%u\n",n,r,s);
            Dump(4,n,r);
            if ((int)s>SCR-1-r) s=(unsigned)(SCR-1-r);
            for (k=0;k<s;k++) {
                NumToRepe(vec,k);
                printf(" num=%-2u : ",k);
                if (r) {
                    printf("vec[]={%d",vec[0]);
                    for (j=1;j<r;j++) printf(",%d",vec[j]);
                    printf("}\n");
                } else printf("No Change\n");
            }
            for (i=0;i<SCR-1-r-(int)s;i++) printf("\n");
            printf(" HIT [ENTER] KEY > ");
            fgets(buf,sizeof buf,stdin);
        }
    }
}

/*+----------------+
 |順列の変換テスト|
 +----------------+*/
void TestPermutation(void)
{
    int n,r,j,err=0; unsigned k,s;

    printf("Permutation(n,r):checking ...\n     ");
    for (r=1;r<=8;r++) printf("   r=%2d",r);
    printf("\n");
    for (n=1;n<=8;n++) {
        printf("n=%2d ",n);
        for (r=1;r<=n;r++) {
            s=InitPerm(n,r);
            if (s==0) {
                err++;
                continue;
            }
            printf("%7u",s);
            for (k=0;k<s;k++) {
                NumToPerm(vec,k);

                /* 辞書順で前の結果より大きいかどうかのテスト */
                for (j=0;j<r;j++) next[j]=(char)vec[j];
                if (k>=1&&memcmp(prev,next,r)>=0)
                    err++;
                memcpy(prev,next,r);

                /* 逆変換で元に戻るかのテスト */
                if (PermToNum(vec)!=k)
                    err++;
            }
        }
        printf("\n");
    }
    printf("ErrorCount=%d MaxCodeTableSize=%lu\n",err,MaxCodeTableSize);
}

/*+----------+
 |順列の確認|
 +----------+*/
void DemoPermutation(void)
{
    int n,r,i,j; unsigned k,s;

    for (n=1;n<=7;n++) {
        for (r=1;r<=n;r++) {
            s=InitPerm(n,r);
            if (s==0) continue;
            for (i=0;i<10;i++) printf("\n");
            printf(" InitPerm(n,r)=(%d,%d) size=%u\n",n,r,s);
            for (i=0;i<r;i++) {
                for (j=0;j<n-i;j++)
                    printf("%*u",5,DefaultCodeTable->a[i][j]);
                printf("\n");
            }
            if ((int)s>SCR-r) s=(unsigned)(SCR-r);
            for (k=0;k<s;k++) {
                NumToPerm(vec,k);
                printf(" num=%-2u : ",k);
                if (r) {
                    printf("vec[]={%d",vec[0]);
                    for (j=1;j<r;j++) printf(",%d",vec[j]);
                    printf("}\n");
                } else printf("No Change\n");
            }
            for (i=0;i<SCR-r-(int)s;i++) printf("\n");
            printf(" HIT [ENTER] KEY > ");
            fgets(buf,sizeof buf,stdin);
        }
    }
}

/*+--------------+
 |メインルーチン|
 +--------------+*/
int main(void)
{
    for (;;) {
        MaxCodeTableSize=0;
        printf("\n");
        printf(" 1:comb test   3:part test  ");
        printf(" 5:repe test   7:perm test\n");
        printf(" 2:comb demo   4:part demo  ");
        printf(" 6:repe demo   8:perm demo  ");
        printf(" 0:quit > ");
        fgets(buf,sizeof buf,stdin);
        switch (buf[0]) {
        case 0 :return 0;
        case'1':TestCombination();break;
        case'2':DemoCombination();break;
        case'3':TestPartition();  break;
        case'4':DemoPartition();  break;
        case'5':TestRepeated();   break;
        case'6':DemoRepeated();   break;
        case'7':TestPermutation();break;
        case'8':DemoPermutation();break;
        case'0':exit(0);
       }
    }
}