/* matrix.c  by Scott McClelland 07/92, 01/07/94
   copyright (c) 1994 WordPro Information Systems
   ------------------------------------------------------------
   Compiled with Turbo C using tiny memory model, and linked
   to a .COM file for optimum speed.
   Translation from BASIC to C 12/93
   Optimizations for speed added 01/94
   ------------------------------------------------------------ */
/* Designed to calculate a linear algebra problem while the
   computer is idle.  Program uses nine nested for loops to
   check values of 200^9 posible combinations, and finds the
   determinant of a 3 X 3 matrix for each combination.  Intermediate
   values are stored in a log file after a time delay (based on loop
   iterations), or keystroke.
   -------------------------------------------------------------
   The program attempts to find a matrix with a determinant equal
   to one, and the matrix formed by squaring all terms also equal
   to one.
   -------------------------------------------------------------*/

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

  int a, b, c, d, e, f, g, h, i,        /* a - i are counters */
      x, y,                     /* x, y are answers  */
      min, max, midval,         /* range to chk */
      found = 0;                /* flag whether soln found or not */
  int a2,b2,c2,d2,e2,f2,g2,h2,i2;       /* terms squared */
  int mina, minb, minc, mind, mine, minf, ming, minh, mini; /* min values */
  int maxa, maxb, maxc, maxd, maxe, maxf, maxg, maxh, maxi; /* max values */
  int col, row;                                   /* screen positions */


  static char *help[] =
    {
      "\t\t- - - - -  MATRIX.C - - - - - ",
      " ",
      "Program runs a screen saver while testing a mathematical problem in",
      "linear algebra.  The program attempts to find a 3 x 3 matrix with",
      "a determinant equal to one, and when all terms are squared, the",
      "determinant is also equal to one.  Zeros are not allowed as terms. ",
      " ",
      ""        /* Null char terminates string */
    };

    /* function prototypes */
void show_help();
void pause(void);
void init( void);
void initmax(void);
void readlog(void);
void showcount(void);
savelog(void);
void quitprog(void);
saveanswer(void);


main()
{
  int cont = 0;
  clrscr();
  /* initialize vars & read values */
  readlog( ); /* sets new starting values from file */
while(cont == 0) /* loop forever */
{
  initmax();
  midval = ((min < 0 ) ? max+min : max-min ); /* middle value assuming max > 0 */
  for( a = mina; a <= maxa; ++a ){
    if( a == 0 ) ++a;               /* zeros not allowed in calc (skip them) */
    if ( a == mina + 1)         /* first time through loop */
        if ( minb > min) minb = min;      /* Resets min value when different */
    for( b = minb; b <= maxb; ++b ){
      if ( b == 0 ) ++b;
      if ( b == minb + 1)
        if ( minc > min) minc = min;
      for( c = minc; c <= maxc; ++c ){
        if ( c == 0 ) ++c;
        if ( c == minc + 1)
          if ( mind > min) mind = min;
        for( d = mind; d <= maxd; ++d ){
          if ( d == 0 ){
            ++d;
        /* chk for 'time' elapse to write to file at d, e, f or g  */
            savelog();
          }
          if ( d == mind + 1)
            if ( mine > min) mine = min;
          for( e = mine; e <= maxe; ++e ){
            if (e == 0) ++e;
            if ( e == mine + 1)
              if ( minf > min) minf = min;
            for( f = minf; f <= maxf; ++f ){
              if ( f == 0 )
                ++f;
              if ( f == minf + 1)
                if ( ming > min) ming = min;
              for( g = ming; g <= maxg; ++g ){
                if ( g == 0 ){
                  ++g;
 /* display current values, and show that any key will terminate program */
 /* moved to main to avoid the overhead of a fuction call */
  /* set col, row to some random value */
  randomize();
  col = random(47);  /* use fibronichi method for more speed (write funct later) */
  row = random(22) + 1 ;
  clrscr();
  gotoxy( col, row);                 /* show value of counters */
  if (found == 0)
    printf("Press any key to restore screen...\n" );
  else
    printf("Found %d Soln(s)! Press any key...\n", found);
  gotoxy( col, row+1);
  printf("%d %d %d %d %d %d ... ",a,b,c,d,e,f);
                } /* if g == 0*/

              /* chk for keystroke to write to file & quit at g or h */
                if (kbhit())  /* allow user to exit by pressing any key */
                  quitprog();
                if ( g == ming + 1)
                  if ( minh > min) minh = min;
                for( h = minh; h <= maxh; ++h ){
                  if ( h == 0 ) ++h;
                  if ( h == minh + 1)
                    if ( mini > min) mini = min;
                  for( i = mini; i <= maxi; ++i ) {
                    if ( i == 0 ) ++i;
                    /* main calculation */
                        x = a * ((e * i)-(f * h)) - b *
                        ((d * i)-(g * f)) + c *((d * h)-(g * e));
                        if (x == 1){  /* x is first determinant */
 /* calcmatrix2(); function used to determine placement in loop structure */
         /* calculate in main to save time by avoiding a function call */
                /* square the terms, find 2nd determinant */
                          a2 = a * a; b2 = b * b; c2 = c * c;
                          d2 = d * d; e2 = e * e; f2 = f * f;
                          g2 = g * g; h2 = h * h; i2 = i * i;
                          y = a2 * ((e2 * i2)-(f2 * h2)) - b2 *
                          ((d2 * i2)-(g2 * f2)) + c2 * ((d2 * h2)-(g2 * e2));
                          if (y == 1)  /* check 2nd determ equal to one */
                            saveanswer(); /* save solutions */
                        } /* if x == 1 */
                  }       /* end for i */
                }         /* end for h */
              }           /* end for g */
            }             /* end for f */
          }               /* end for e */
        }                 /* end for d */
      }                   /* end for c */
    }                     /* end for b */
  }                       /* end for a */

/* resets min & max values if numbers reach the end of test range */
   min = -999; max = 999;
   found = 0;
   init(); /* reset loop counter values */
} /* end while */

  return(0);
} /* main */
/* ---------------------------------------------------------------------- */

void show_help()  /* explain program as processing begins */
{    /* *help defined above as static char pointer */
  int index;
  clrscr();
  for ( index=0; *help[index]; index++ ) puts( help[index] );
}


void pause(void)
{
  char ch;
  printf("Press any key to continue...");
  ch = getch();
  printf("%c", ch);
}

void init( void) /* sets values if loop reaches end */
{
  mina = minb = minc = mind = mine = minf = ming = minh = mini = min;
  maxa = maxb = maxc = maxd = maxe = maxf = maxg = maxh = maxi = max;
}

void initmax(void) /* sets max values, although max could be used for
        all 9 vars, rather than using nine different vars. */
{
  maxa = maxb = maxc = maxd = maxe = maxf = maxg = maxh = maxi = max;
}

/* ---------------------------------------------------------------------- */
void readlog(void)
{

  FILE *fp, *fopen();
  if ((fp = fopen("matrix.log", "r" )) == NULL) {
    printf("Can't open log file\nChange to directory containing MATRIX.LOG,\nor create new log file with SETUP\n");
    pause();
    exit(1);
  }
  /* read loop counter values from log file */
  fscanf( fp, "%d %d %d %d %d %d %d %d %d %d %d",
        &mina,&minb,&minc,&mind,&mine,&minf,&ming,&minh,&mini,&min,&max );
  fclose(fp);
  show_help(); /* explain program while calculating */
  printf("Calculating...\n\nStarting with matrix:\n\n");
  printf("\t %5d %5d %5d \n\t %5d %5d %5d \n\t %5d %5d %5d \n\nin the range of %d to %d\n",
        mina,minb,minc,mind,mine,minf,ming,minh,mini,min,max);
        printf("\nPress any key to restore screen at any time during execution of program..." );
}

void showcount(void) /* move to main to save funct call time */
{
  int col, row;
  /* set col, row to some random value */
  randomize();
  col = random(47);  /* use fibronichi method for more speed (write funct later) */
  row = random(22) + 1 ;
  clrscr();
/* value of counters may be one more then max.  If so, decrement counter. */
/* (not needed if function is eliminated and operations are moved to main) */
  if (a > maxa) a--; if (b > maxb) b--; if (c > maxc) c--; if (d > maxd) d--;
  if (e > maxe) e--; if (f > maxf) f--; if (g > maxg) g--; if (h > maxh) h--;
  if (i > maxi) i--; /* not needed in main */

  gotoxy( col, row);                 /* show value of counters */
  if (found == 0)
    printf("Press any key to restore screen...\n" );
  else
    printf("Found %d Soln(s)! Press any key...\n", found);
  gotoxy( col, row+1);
  printf("%d %d %d %d %d %d %d %d %d\n",a,b,c,d,e,f,max, max, max);
}

savelog(void) /* saves current values of a through i */
{
  FILE *fp, *fopen();
  if ((fp = fopen("matrix.log", "w" )) == NULL) {
    printf("Can't open log file\n");
    pause();
    return(1);
  }
  /* value of counters may be one more then max.  If so, decrement counter */
  if (a > maxa) a--; if (b > maxb) b--; if (c > maxc) c--; if (d > maxd) d--;
  if (e > maxe) e--; if (f > maxf) f--; if (g > maxg) g--; if (h > maxh) h--;
  if (i > maxi) i--;

  fprintf( fp, "%d %d %d %d %d %d %d %d %d %d %d ",a,b,c,d,e,f,g,h,i,min,max );
  fclose(fp);

/*  gotoxy(1,3);
  printf("\nSaving log file...\n%d %d %d %d %d %d %d %d %d %d %d\n",
                a,b,c,d,e,f,g,h,i,min,max );  */       /* beta */
  return(0);
}

void quitprog(void)
{
  savelog();
  /* reset screen - white foreground, black background */
  textattr( BLACK * 16 + LIGHTGRAY );
  clrscr();
  gotoxy(20,3);
  printf("\nSaving log file...\n%d %d %d %d %d %d %d %d %d range: %d to %d\n",
                  a,b,c,d,e,f,g,h,i,min,max );
  exit(0);
}

saveanswer(void)
{
  FILE *fp, *fopen();
  if ((fp = fopen("answer.log", "a" )) == NULL) {
    printf("Can't open answer file");
    pause();
    return(1);
  }
  fprintf( fp, "%d %d %d %d %d %d %d %d %d %d %d\n",a,b,c,d,e,f,g,h,i,min,max );
  fclose(fp);

  found++;
  printf("\nfound %d answer(s): \n%d %d %d\n%d %d %d\n%d %d %d\n",
          "in the range of %d to %d\n",found,a,b,c,d,e,f,g,h,i,min,max );
  return(0);
}

/* moved to main for faster processing */
calcmatrix2(void) /* called if first determ = 1 */
{
  /* square the terms, find 2nd determinant */
  a2 = a * a; b2 = b * b; c2 = c * c; d2 = d * d; e2 = e * e;
  f2 = f * f; g2 = g * g; h2 = h * h; i2 = i * i;
y = a2 * ((e2 * i2)-(f2 * h2)) - b2 * ((d2 * i2)-(g2 * f2)) + c2 * ((d2 * h2)-(g2 * e2));
  if (y == 1)  /* check if equal to one */
    saveanswer(); /* save solutions */
  return(0);
}