/**********************************************************************/
/*                                                                    */
/* Program: marith.c                                                  */
/*                                                                    */
/* Description:                                                       */
/* ============                                                       */
/*                                                                    */
/* Practice mental arithmetic (+, -, * and /) with integer            */
/* numbers of a selected maximum size (the base).                     */
/*                                                                    */
/* If you make the base large, and want to rest your brain,           */
/* you can also test your typing skills with your pocket              */
/* calculator with this program.                                      */
/*                                                                    */
/* The file "marith.cfg" with parameters (the base etc) must be       */
/* available in the same directory as the executable for this         */
/* program. See parameter explanations and examples for this          */
/* file below.                                                        */
/*                                                                    */
/* Author:                                                            */          
/* =======                                                            */
/*                                                                    */
/* Stefan Spaennare, Lund, Sweden                                     */
/*                                                                    */
/* E-mail:          stefan@spaennare.se                               */
/*                                                                    */
/* First version:   2002-01-05                                        */
/* Latest update:   2007-07-28                                        */
/*                                                                    */
/* Reference:                                                         */
/* ==========                                                         */
/*                                                                    */
/* Random function (ran2) from "Numerical Recipes in C"               */ 
/* second edition.                                                    */
/*                                                                    */
/**********************************************************************/

/**********************************************************************************/
/*                                                                                */
/*                                                                                */
/* File: marith.cfg                                                               */
/* ----------------                                                               */
/*                                                                                */
/* Meaning of the 5 lines with numbers above:                                     */
/* ------------------------------------------                                     */
/*                                                                                */
/* Line 1: Arithmethic string. Must contain only +, -, *, and /. Selects          */
/*         the operations used in the questions. Max 256 characters.              */
/*         Default: +*-/                                                          */
/*                                                                                */
/* Line 2: Sequence flag. Linear sequence in arithmethic string (0) or            */
/*         random sequence in arithmethic string (1). Default: 1                  */
/*                                                                                */
/* Line 3: Wrong answer indicator. No indicator (0). Print correct answer (1).    */
/*         Or other arbitrary string not starting with 0 or 1 without spaces.     */
/*         For example: "Wrong_answer!". Default: 1                               */
/*                                                                                */
/* Line 4: Number base. (100 <= base <= 2000000000). Default: 1000                */
/*                                                                                */
/* Line 5: Random seed: (seed > 0). If seed = 0 the random numbers are            */
/*         initialized automatically. Default: 0                                  */
/*                                                                                */
/*                                                                                */
/**********************************************************************************/

/********************************************************************************/
/*                                                                              */
/* Notice                                                                       */
/* ======                                                                       */
/*                                                                              */
/* I make no warranties that this program is (1) free of errors, (2) consistent */
/* with any standard merchantability, or (3) meeting the requirements of a      */
/* particular application. This software shall not, partly or as a whole,       */
/* participate in a process, whose outcome can result in injury to a person or  */
/* loss of property. It is solely designed for analytical work. Permission to   */
/* use, copy and distribute is hereby granted without fee, providing that the   */
/* header above including this notice appears in all copies.                    */
/*                                                                              */
/*                                                            Stefan Spaennare  */
/*                                                                              */
/********************************************************************************/


#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>

double timetic=(double)(CLOCKS_PER_SEC);

char cfg_name[21]="marith.cfg";

#define IM1 2147483563
#define IM2 2147483399
#define AM (1.0/IM1)
#define IMM1 (IM1-1)
#define IA1 40014
#define IA2 40692
#define IQ1 53668
#define IQ2 52774
#define IR1 12211
#define IR2 3791
#define NTAB 32
#define NDIV (1+IMM1/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)

double ran2(idum)
long *idum;
{
   int j;
   long k;
   static long idum2=123456789;
   static long iy=0; 
   static long iv[NTAB];
   double temp;

   if (*idum <= 0) {
      if (-(*idum) < 1) {
         *idum=1;
      }
      else {
         *idum=-(*idum);
      } /* if */
      idum2=(*idum);
      for (j=NTAB+7; j>=0; j--) {
         k=(*idum)/IQ1;
	 *idum=IA1*(*idum-k*IQ1)-k*IR1;
	 if (*idum < 0) {
	    *idum += IM1;
	 } /* if */
	 if (j < NTAB) {
	    iv[j]=*idum;
	 } /* if */
      } /* for j */
      iy=iv[0];
   } /* if */
   k=(*idum)/IQ1;
   *idum=IA1*(*idum-k*IQ1)-k*IR1;
   if (*idum < 0) {
      *idum += IM1;
   } /* if */
   k=idum2/IQ2;
   idum2=IA2*(idum2-k*IQ2)-k*IR2;
   if (idum2 < 0) {
      idum2 += IM2;
   } /* if */
   j=iy/NDIV;
   iy=iv[j]-idum2;
   iv[j] = *idum;
   if (iy < 1) {
      iy += IMM1;
   } /* if */
   temp=AM*(double)(iy);
   if (temp > RNMX) {
      return(RNMX);
   }
   else {
      return(temp);
   } /* if */

} /* ran2 */


int addadd(base,idum)
int base;
long *idum;
{

   int term1,term2,term3;

   double dterm1,dterm2,max,min;

   min=10.0;
   max=(double)(base-1)-min;

   dterm1=(max-min+1.0)*ran2(idum)+min;
   dterm2=(max-dterm1+1.0)*ran2(idum)+min;

   term1=(int)(dterm1);
   term2=(int)(dterm2);
   term3=term1+term2;

   printf("%d + %d = ",term1,term2);

   return(term3);

} /* addadd */


int subsub(base,idum)
int base;
long *idum;
{

   int term1,term2,term3;

   double dterm1,dterm2,max,min;

   min=10.0;
   max=(double)(base-1)-min;

   dterm1=(max-min+1.0)*ran2(idum)+min;
   dterm2=(max-dterm1+1.0)*ran2(idum)+min;

   term1=(int)(dterm1);
   term2=(int)(dterm2);
   term3=term1+term2;

   printf("%d - %d = ",term3,term1);

   return(term2);

} /* subsub */


int mulmul(base,idum)
int base;
long *idum;
{

   int term1,term2,term3,temp;

   double dterm1,dterm2,max,min,max2;

   max=(double)(base-1);
   max2=0.1*(double)(base)-1.0;
   min=2.0;

   dterm1=(max2-min+1.0)*ran2(idum)+min;
   temp=(int)(max/dterm1);
   dterm2=((double)(temp)-min+1.0)*ran2(idum)+min;

   term1=(int)(dterm1);
   term2=(int)(dterm2);
   term3=term1*term2;

   printf("%d * %d = ",term1,term2);

   return(term3);

} /* mulmul */


int divdiv(base,idum)
int base;
long *idum;
{

   int term1,term2,term3,temp;

   double dterm1,dterm2,max,min,max2;

   max=(double)(base-1);
   max2=0.1*(double)(base)-1.0;
   min=2.0;

   dterm1=(max2-min+1.0)*ran2(idum)+min;
   temp=(int)(max/dterm1);
   dterm2=((double)(temp)-min+1.0)*ran2(idum)+min;

   term1=(int)(dterm1);
   term2=(int)(dterm2);
   term3=term1*term2;

   printf("%d / %d = ",term3,term1);

   return(term2);

} /* divdiv */


int main(argc,argv) 
int argc;
char *argv[];
{

   FILE *cfgfile;
  
   int i,n,flag,rndflag,alen,answ;
   int k,endflag,answ2;
   int cadd,csub,cmul,cdiv;
   int cadd2,csub2,cmul2,cdiv2;
   int totcorrect,base,seed,seed2;

   long idum;

   double ttt1,ttt2,tottime;

   char astring[257];
   char corrstring[257];
   char tempstring[21];

   time_t tt;

   struct timeb tstart,tend;


   if ((cfgfile = fopen(cfg_name,"r")) == NULL) {
      printf("File %s not found.\n",cfg_name);
      exit(0);
   } /* if */


   fscanf(cfgfile,"%s",astring);
   fscanf(cfgfile,"%d",&rndflag);
   fscanf(cfgfile,"%s",corrstring);
   fscanf(cfgfile,"%d",&base);
   fscanf(cfgfile,"%d",&seed);


seed2=seed;   

if (seed == 0) {
   tt=time(0);
   ttt1=(double)(tt)+0.5;
   ttt2=fmod(ttt1,2147483647.0);
   seed=(long)(ttt2);
   idum=-seed-1;
}
else {
   idum=-abs(seed)-1;
} /* if */


printf("\n");
printf("Practise Mental Arithmetic\n");
printf("==========================\n");
printf("\n");

flag=1;

alen=strlen(astring);

if (alen <= 0) {
   flag=1;
}
else {
   i=0;

   while (((astring[i] == '+') || (astring[i] == '-') || 
          (astring[i] == '*') || (astring[i] == '/')) && (i < alen)) {
      i++;
   } /* while */

   
   if (i == alen) {
      flag=0;
   } /* if */

} /* if */

if (flag == 1) {
   printf("\n");
   printf("Wrong arithmethic string: %s. The string must contain only +, -, * and /.\n",astring);
   printf("Edit the file: %s\n",cfg_name);
   printf("\n");
   exit(0);
} /* if */

if (base > 2000000000) {
   base=2000000000;
} /* if */

if (base < 100) {
   base=100;
} /* if */

if (rndflag != 1) {
   rndflag=0;
} /* if */

printf("Change the parameters by editing the file %s.\n",cfg_name);
printf("\n");
printf("Arithmethic string: %s\n",astring);
printf("\n");
if (rndflag == 1) {
   printf("Random sequence in arithmethic string.\n");
}
else {
   printf("Linear sequence in arithmethic string.\n");
} /* if */
printf("\n");
printf("Base: %d\n",base);
printf("\n");
if (seed2 == 0) {
   printf("Automatically generated random seed.\n");
}
else {
   printf("Random seed: %d\n",seed2);
} /* if */
printf("\n");
printf("------------------------------------------------------\n");

printf("\n");
printf("Start by pressing the key s and then RETURN: ");
scanf("%s",tempstring);
printf("\n");
printf("Type the answers and press RETURN.\n");
printf("\n");
printf("Quit by pressing the key q and then RETURN.\n");
printf("\n");
printf("------------------------------------------------------\n");
printf("\n");

ftime(&tstart);

cadd=0;
csub=0;
cmul=0;
cdiv=0;

cadd2=0;
csub2=0;
cmul2=0;
cdiv2=0;

i=0;
endflag=0;

do {

   if (rndflag == 1) {
      k=(int)((double)(alen)*ran2(&idum));
   }
   else {
      k=i % alen;
   } /* if */

   i++;

   printf("%4d:   ",i);

   if (astring[k] == '+') {
      answ=addadd(base,&idum);
   } /* if */   

   if (astring[k] == '-') {
      answ=subsub(base,&idum);
   } /* if */   

   if (astring[k] == '*') {
      answ=mulmul(base,&idum);
   } /* if */   
   
   if (astring[k] == '/') {
      answ=divdiv(base,&idum);
   } /* if */   

   scanf("%s",tempstring);

   if (strncmp(tempstring,"q",1) == 0) {
      endflag=1;
   }
   else {
      answ2=atoi(tempstring);

         if (astring[k] == '+') {
            cadd2++;
         } /* if */   

         if (astring[k] == '-') {
            csub2++;
         } /* if */   

         if (astring[k] == '*') {
            cmul2++;
         } /* if */   
   
         if (astring[k] == '/') {
            cdiv2++;
         } /* if */   

      if (answ2 != answ) {

         if (corrstring[0] != '0') {
            if (corrstring[0] == '1') {
               printf("                                         %d\n",answ);
	    }
	    else {
               printf("                                         %s\n",corrstring);
	    } /* if */
	 } /* if */

      }
      else {
      
         if (astring[k] == '+') {
            cadd++;
         } /* if */   

         if (astring[k] == '-') {
            csub++;
         } /* if */   

         if (astring[k] == '*') {
            cmul++;
         } /* if */   
   
         if (astring[k] == '/') {
            cdiv++;
         } /* if */   

      } /* if */

      endflag=0;

    } /* if */

    printf("\n");

} while (endflag == 0);

ftime(&tend);

tottime=(double)(tend.time)+0.001*(double)(tend.millitm)
       -(double)(tstart.time)-0.001*(double)(tstart.millitm);

printf("------------------------------------------------------\n");

n=i-1;
totcorrect=cadd+csub+cmul+cdiv;

if (n > 0) {

printf("\n");
printf("Statistics\n");
printf("==========\n");
printf("\n");

printf("Number of answers n:            %4d\n",n);
printf("Number of correct answers:      %4d",totcorrect);

if (totcorrect == n) {
   printf("             Good!\n");
}
else {
   printf("\n");
} /* if */

printf("Total answering time:           %7.2f s\n",tottime);
printf("Average time per answer:        %7.2f s\n",tottime/(double)(n));
printf("\n");

printf("Tot = Total; Corr = Correct; Fractions are given in %%:\n");
printf("\n");

printf("Type              Tot  Corr    Tot/n Corr/Tot   Corr/n\n");
printf("------------------------------------------------------\n");

printf("Answers:         %4d  %4d  %7.2f  %7.2f  %7.2f\n",
        n,totcorrect,100.0*(double)(n)/(double)(n),
        100.0*(double)(totcorrect)/(double)(n),100.0*(double)(totcorrect)/(double)(n));

printf("------------------------------------------------------\n");

if (cadd2 > 0) {
printf("Additions:       %4d  %4d  %7.2f  %7.2f  %7.2f\n",
        cadd2,cadd,100.0*(double)(cadd2)/(double)(n),
        100.0*(double)(cadd)/(double)(cadd2),100.0*(double)(cadd)/(double)(n));
} /* if */

if (csub2 > 0) {
printf("Subtractions:    %4d  %4d  %7.2f  %7.2f  %7.2f\n",
        csub2,csub,100.0*(double)(csub2)/(double)(n),
        100.0*(double)(csub)/(double)(csub2),100.0*(double)(csub)/(double)(n));
} /* if */

if (cmul2 > 0) {
printf("Multiplications: %4d  %4d  %7.2f  %7.2f  %7.2f\n",
        cmul2,cmul,100.0*(double)(cmul2)/(double)(n),
        100.0*(double)(cmul)/(double)(cmul2),100.0*(double)(cmul)/(double)(n));
} /* if */

if (cdiv2 > 0) {
printf("Divisions:       %4d  %4d  %7.2f  %7.2f  %7.2f\n",
        cdiv2,cdiv,100.0*(double)(cdiv2)/(double)(n),
        100.0*(double)(cdiv)/(double)(cdiv2),100.0*(double)(cdiv)/(double)(n));
} /* if */

printf("------------------------------------------------------\n");


printf("\n");

} /* if */


fclose(cfgfile);


} /* End */
