/* Can only feed straight in, not from the side.
 */
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define ISODD(n) ((n)&1)
#define ISEVEN(n) (!((n)&1))
#define MOD(x,y) (((x) % (y)) >= 0 ? (x)%(y) : ((x)%(y)) + (y))
#define INNERLIM 10 
long V[INNERLIM];
long W[6]; /* each W[i] has value from 0 to 5 */
long initW[6];
long D; /* the orientation, from 0 to 5 */
long In; /* values D-1, D, or D+1, where 5 = -1 */
long Out; /* values D+2, D+3, or D+4 */
long m(long, long);
long orient; /* heading right or left, orient = 1 or -1 */
long EVENODD (long);
void T(long [], long , long , long *);
void putS (long [], long );
unsigned int encodeW (long []);
void decodeV (long, long []);
void decodeW(unsigned int , long []);
void printbase6(unsigned int );
void printdigits(unsigned int );
double seed;
double ran();
#define MAXTAL 46656
#define MAXTALS 20
unsigned int tal[MAXTAL];
long moves[MAXTAL];
unsigned int numm[MAXTAL];
long tals[MAXTALS];
void tally(unsigned int, long, long );
void outtally();
void dumptal();

void main(void)
{
   long i, j, k;
   double r;
   unsigned int enc;
   long innerlim, outerlim;
 /*  printf("Input integers for the inner and outer limits\n"); */
 /*  scanf("%ld %ld", &innerlim, &outerlim); */
   innerlim = INNERLIM; 
   outerlim = 1.0;
   for (i = 0; i < INNERLIM; i++) 
      outerlim = outerlim*6;
   printf("Inner: %ld, Outer:  %ld\n", innerlim, outerlim);
   fflush(stdout);
   for (i = 0; i < 6; i++){
      W[i] = 0;
      initW[i] = W[i];
   }
   printf("Initial config: ");
   for (i = 0; i < 6; i++)
      printf("%1ld, ", initW[i]);
   printf("\n");
   for (i = 0; i < MAXTAL; i++){
      tal[i] = 0;
      moves[i] = 0;
      numm[i] = -1;
   }
   seed = 17.0 * innerlim;
   for ( i = 0;i < outerlim ; i++) {
      for (j = 0; j < 6; j++)
         W[j] = 0;
      decodeV(i, V);
      for (j = 0; j < innerlim; j++) {
              D = V[j];
	      In = D;
     /*   printf("Iter: %2ld, D: % 2ld, In: %2ld\n", i, D, In);  */
         T(W, D, In, &Out);
     /*    putS(W, D);  */
         tally(encodeW(W), i, j);
     /*    getchar();  */
      } 
   } /* for i */
   outtally();
   fflush(stdout);
   dumptal();
} /* main */

long m(long i, long j)
{
   return( MOD((i + orient*j), 6));
}

void T(long W[6], long D, long In, long *Out)
{
   orient = 1;
   if (In == D) {
      if ( ISEVEN (m(D, W[D])) ) orient = 1;
      else orient = -1;
      W[D] = m( W[D], 1);
      /* head to W[D+1]  */
      if ( EVENODD( m(D, W[ m(D,1)])) )
         W[ m(D, 1) ] = m( W[ m(D, 1) ], -1);
      else
         W[ m(D, 1) ] = m( W[ m(D, 1) ], -2);
   }
   else if (In == m(D, 1)) {
      orient = 1;
      /* into W[D+1]  */
      if ( ISODD( m(D, W[ m(D,1)])) )
         W[ m(D, 1) ] = m( W[ m(D, 1) ],  1);
      else
         W[ m(D, 1) ] = m( W[ m(D, 1) ],  2);
   }
   else if (In == m(D, -1)) {
      orient = -1;
      /* into W[D+orient*1], i.e., into W[D-1]  */
      if ( ISEVEN( m(D, W[ m(D,1)])) )
         W[ m(D, 1) ] = m( W[ m(D, 1) ],  1);
      else
         W[ m(D, 1) ] = m( W[ m(D, 1) ],  2); 
   }
   /*****  else  ERROR */
   /* head to W[D+orient*2]  */
   if ( EVENODD( m(D, W[ m(D,2)])) ) {
      W[ m(D, 2) ] = m( W[ m(D, 2) ],  1);
      *Out = m(D, 2);
   }
   else {
      W[ m(D, 2) ] = m( W[ m(D, 2) ], -1);
      /* head to W[D+orient*3] */
      if ( EVENODD( m(D, W[ m(D, 3) ] )) )
         W[ m(D, 3) ] = m( W[ m(D, 3) ],  2);
      else  
         W[ m(D, 3) ] = m( W[ m(D, 3) ],  1);
      *Out = m(D, 3);
   }
}

void putS (long W[6], long D)
{
   long i;
   printf("D: %2ld, W: [", D);
   for (i = 0; i < 5; i++)
      /**** printf("W[%1ld]:%2ld, ", i, W[i]); ***/
      printf("%2ld, ", W[i]);
   printf("%2ld], ", W[5]);
   printf("Out:%2ld", Out);
   printf("\n");
}

long EVENODD (long i)
{
   if (orient == 1) return(ISEVEN(i));
   else return(ISODD(i));
}
   
unsigned int encodeW (long W[6])
{
   long i, ans = 0;
   for (i = 5; i >= 0; i--)
      ans = W[i] + ans*6;
   return( (unsigned int) ans);
}

void decodeW(unsigned int enc, long W[6])
{
   long i;
   for (i = 0; i < 6; i++) {
      W[i] = enc % 6;
      enc = enc / 6;
   }
}

void decodeV(long encv, long V[INNERLIM])
{
   long i;
   for (i = 0; i < INNERLIM; i++) {
      V[i] = encv % 6;
      encv = encv / 6;
   }
}

void printbase6(unsigned int enc)
{
   unsigned int i = enc / 6;
   if (i) printbase6(i);
   printf("%1hu", enc % 6);
}

void printdigits(unsigned int enc)
{
   unsigned int i;
   for (i = 0; i < 6; i++) {
      printf("%1hu", enc % 6);
      enc = enc / 6;
   }
}

double ran()
/* a simple linear cong generator used to initialize
   the array t used in the main generator.
   "seed" should be a double between 1.0 and 2^31-1.
 */
{
   static double a = 16807.0,
                 m = 2147483647.0,
                 q = 127773.0,
                 r = 2836.0;
          double hi, lo, test;
   hi = (double) ( (long) (seed/q));
   lo = seed - q*hi;
   test = a*lo - r*hi;
   if (test > 0.0) seed = test;
   else seed = test + m;
   return(seed/m);
}

void tally(unsigned int enc, long i, long j)
{
   /* i is the encoded sequence of moves */
   /* j is the number of moves (actually j+1) */
   /* enc is an encoding of the final position */
   tal[enc] = tal[enc] + 1;
   if (moves[enc] == 0) {
      moves[enc] = i;
      numm[enc] = j;
   }
   else { /* let's get the SHORTEST one */
      if (j < numm[enc]) {
         moves[enc] = i;
	 numm[enc] = j;
      }
   }
}

void outtally()
{
   long i;
   printf("***** Start of Outtally\n");
   for (i = 0; i < MAXTALS; i++)
      tals[i] = 0;
   for (i = 0; i < MAXTAL; i++) {
      if ( tal[i] >= MAXTALS - 1) 
      tals[MAXTALS - 1] = tals[MAXTALS - 1] + 1;
      else tals[tal[i]] = tals[tal[i]] + 1;
   }
   for (i = 0; i < MAXTALS; i++)
      printf("%5ld\n", tals[i]);
}

void dumptal()
{
   FILE *output;
	int i, j, k;
	output = fopen("output10.dat","wt");
	if ( !output ) {
		fprintf(stderr,"cannot open file\n");
		exit(1);
	}
	
        fprintf(output, "Initial config: ");
        for (i = 0; i < 6; i++)
          fprintf(output, "%1ld, ", initW[i]);
	fprintf("\n");
	for (k = INNERLIM; k >= 0; k--) {
           for (i = 0; i < MAXTAL; i++) {
             if (numm[i] == k) {
	        decodeW(i, W);
		for (j = 0; j < 6; j++)
		   fprintf(output, "%ld", W[j]);
		fprintf(output,"% 1d ",tal[i]);
		if (tal[i] != 0) {
                   decodeV(moves[i], V);
                   for (j = 0; j <= numm[i]; j++) 
                      fprintf(output,"%1ld", V[j]);
		}
		fprintf(output,"\n");
             } /* if */
           } /* for i */
           fprintf(output, "*************\n");
	}
	fclose(output);
}