/*
Test.c 組合せに対応する整数への変換とその逆変換のテストプログラム
programmed by Isaku WADA 2003 isaku@pb4.so-net.ne.jp
*/
#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++) {
        for (j=0;j<n;j++)
            printf("%*u",keta,DefaultCodeTable->a[i][j]);
        printf("%*s",keta,"");
        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::自己診断中\n");
    for (n=0;n<=18;n++) {
        for (r=0;r<=(n>12?12: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]+'A');
                next[r]=0;
                if (k>=1&&strcmp(prev,next)>=0) err++;
                strcpy(prev,next);

#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");
    }
    if (err) printf(" %d 個のエラーが見つかりました\n",err);
    else printf(" エラーはありません(MaxCodeTableSize=%lu byte)\n",
                 MaxCodeTableSize);
}

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

    for (n=1;n<=9;n++) {
        for (r=0;r<=n;r++) {
            s=InitComb(n,r);
            if (s==0) continue;
            printf(" Combination(n,r)=(%d,%d) size=%u\n",n,r,s);
            Dump(4,n-r+1,r);
            if ((int)s>SCR-1-r) s=(unsigned int)(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::自己診断中\n");
    for (n=0;n<=9;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]+'A');
                next[r]=0;
                if (k>=1&&strcmp(prev,next)>=0) err++;
                strcpy(prev,next);

                /* 逆変換で元に戻るかのテスト */
                if (PartToNum(vec)!=k) err++;
            }
        }
        printf("\n");
    }
    if (err) printf(" %d 個のエラーが見つかりました\n",err);
    else printf(" エラーはありません(MaxCodeTableSize=%lu byte)\n",
                 MaxCodeTableSize);
}

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

    for (n=0;n<=6;n++) {
        for (r=1;r<=6;r++) {
            s=InitPart(n,r);
            if (s==0) continue;
            printf(" Partition(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");
    for (n=1;n<=10;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]+'A');
                next[r]=0;
                if (k>=1&&strcmp(prev,next)>=0) err++;
                strcpy(prev,next);

#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");
    }
    if (err) printf(" %d 個のエラーが見つかりました\n",err);
    else printf(" エラーはありません(MaxCodeTableSize=%lu byte)\n",
                 MaxCodeTableSize);
}

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

    for (n=1;n<=6;n++) {
        for (r=0;r<=6;r++) {
            s=InitRepe(n,r);
            if (s==0) continue;
            printf(" Repeated(n,r)=(%d,%d) size=%u\n",n,r,s);
            Dump(4,n,r);
            if ((int)s>SCR-1-r) s=(unsigned int)(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");
    for (n=1;n<=8;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]+'A');
                next[r]=0;
                if (k>=1&&strcmp(prev,next)>=0) err++;
                strcpy(prev,next);

                /* 逆変換で元に戻るかのテスト */
                if (PermToNum(vec)!=k) err++;
            }
        }
        printf("\n");
    }
    if (err) printf(" %d 個のエラーが見つかりました\n",err);
    else printf(" エラーはありません(MaxCodeTableSize=%lu byte)\n",
                 MaxCodeTableSize);
}

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

    for (n=1;n<=7;n++) {
        for (r=1;r<=n;r++) {
            s=InitPerm(n,r);
            if (s==0) continue;
            printf(" Permutation(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",4,DefaultCodeTable->a[i][j]);
                printf("\n");
            }
            if ((int)s>23-r) s=(unsigned int)(23-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<23-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_t test   3:part_t test  ");
        printf(" 5:repe_t test   7:perm_t test\n");
        printf(" 2:comb_t demo   4:part_t demo  ");
        printf(" 6:repe_t demo   8:perm_t 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);
       }
    }
}