/*****************************************************************/
/*                                                               */
/*   CASIO fx-9860G SDK Library                                  */
/*                                                               */
/*   File name : [ProjectName].c                                 */
/*                                                               */
/*   Copyright (c) 2006 CASIO COMPUTER CO., LTD.                 */
/*                                                               */
/*****************************************************************/
#include "fxlib.h"
#include "stdio.h"
#include "limits.h"
#include "stdlib.h"

#define PP   0   // deux plaques
#define RP   1   // un r‚sultat et une plaque
#define RR   2   // deux r‚sultats
#define RR2  3   // deux r‚sultats mais pas issus des 2 r‚sultats juste precedents (1 autre resultat entre les 2)

#define ADD    '+'
#define MUL    '*'
#define SOUS   '-'
#define DIV    '/'


//****************************************************************************
//  AddIn_main (Sample program main function)
//
//  param   :   isAppli   : 1 = This application is launched by MAIN MENU.
//                        : 0 = This application is launched by a strip in eACT application.
//
//              OptionNum : Strip number (0~3)
//                         (This parameter is only used when isAppli parameter is 0.)
//
//  retval  :   1 = No error / 0 = Error
//
//****************************************************************************



typedef struct
{
  int typeoperation[8];
} schema;

typedef struct
{
  long valeur1[16];
  char operation[16];
  long valeur2[16];
  long resultat[16];
} solution;

long PlaqueIni[16]={1,3,5,7,9,1};
long Resultat=377;

long MeilleurEcart;
int MeilleurNombrePlaques;

long NombreAppelCompte;

long Solutions;

long Plaque[16][16]; // 16*16 pour optimiser un peu
long ResultatLigne[16];

schema Cas[8][8]=
{{0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0},
 {{PP},0,0,0,0,0,0,0},
 {{PP,RP},0,0,0,0,0,0,0},
 {{PP,PP,RR},{PP,RP,RP},0,0,0,0,0,0},
 {{PP,RP,PP,RR},{PP,PP,RR,RP},{PP,RP,RP,RP},0,0,0,0,0},
 {{PP,PP,RR,PP,RR},{PP,RP,PP,RP,RR2},{PP,RP,PP,RR,RP},{PP,RP,RP,PP,RR},{PP,PP,RR,RP,RP},{PP,RP,RP,RP,RP},0,0},
 {0,0,0,0,0,0,0,0}};

int NombreConfigs[8]={0,0,1,1,2,3,6,0};

int NombrePlaques;
int Config;

solution SaveSolution;
solution BestSolution;

void AffichePresentation(void);
void AfficheErreurParametres(void);
void AfficheSolution(int l);
void Calcule(int l,int p, int plaquesPrises,long plaque1,long plaque2);
void compte(int l,int p);

void AffichePresentation()
{
    Bdisp_AllClr_DDVRAM();
    locate(1,1);
    Print((unsigned char*)"  Le Compte est Bon");
	locate(1,2);
	Print((unsigned char*)"rentrer les 6");
	locate(1,3);
	Print((unsigned char*)"nombres");
}

void AfficheErreurParametres()
{
	Bdisp_AllClr_DDVRAM();
    locate(1,1);
    Print((unsigned char*)"erreur");
}

int entree()
{
	unsigned int key;
    int resultat = 0;
	int k = 0;
	unsigned char* stri;
	
	locate(0,8);
	Print((unsigned char*)"                     ");
	
	while(k!=16)
	{
		GetKey(&key); // Getting key pressed
		
		switch(key) // Analyse key pressed
		{			
			case KEY_CHAR_1:
				k++;
				resultat = resultat*10 + 1;
				stri[0] = '1';
				break;
			
			case KEY_CHAR_2:
				k++;
				resultat = resultat*10 + 2;
				stri[0] = '2';
				break;
			
			case KEY_CHAR_3:
				k++;
				resultat = resultat*10 + 3;
				stri[0] = '3';
				break;
			
			case KEY_CHAR_4:
				k++;
				resultat = resultat*10 + 4;
				stri[0] = '4';
				break;
			
			case KEY_CHAR_5:
				k++;
				resultat = resultat*10 + 5;
				stri[0] = '5';
				break;
			
			case KEY_CHAR_6:
				k++;
				resultat = resultat*10 + 6;
				stri[0] = '6';
				break;
			
			case KEY_CHAR_7:
				k++;
				resultat = resultat*10 + 7;
				stri[0] = '7';
				break;
			
			case KEY_CHAR_8:
				k++;
				resultat = resultat*10 + 8;
				stri[0] = '8';
				break;
			
			case KEY_CHAR_9:
				k++;
				resultat = resultat*10 + 9;
				stri[0] = '9';
				break;
			
			case KEY_CHAR_0:
				k++;
				resultat = resultat*10;
				stri[0] = '0';
				break;
			
			case KEY_CTRL_DEL:
				resultat = resultat/10;
				key = 1;
				break;
			
			case KEY_CTRL_EXE:
				if (k!=0)
				{
					k = 16;
					stri[0] = ' ';
				}
				break;
		}
		
		if (key != 1)
		{
			locate(k,8);
			Print(stri);
		}
		else
		{
			locate(k,8);
			Print((unsigned char*)" ");
			if (k != 0)
				k--;
		}
	}
    return resultat; 
}


void AfficheSolution(int l)
{
  int i;
  char* str = malloc(40);
  Bdisp_AllClr_DDVRAM();
  locate(1,1);
  for(i=0;i<6;i++) {
	sprintf(str, "%lu ",PlaqueIni[i]);
	Print(str);
  }
  sprintf(str, "%lu",Resultat);
  Print(str);
  for(i=0;i<l;i++) {
    locate(1,i+2);
	sprintf(str, "%lu %c %lu = %lu",BestSolution.valeur1[i],BestSolution.operation[i],BestSolution.valeur2[i],BestSolution.resultat[i]);
    Print(str);
  }
  locate(1,7);//1 l ,2 5,3 4,4 3,5 2,6 1,7 ,8
  sprintf(str,"nb sol %lu, Meq %lu",Solutions, MeilleurEcart);
  Print(str);
  locate(1,8);
  sprintf(str,"nb apl fx rec %lu",NombreAppelCompte);
  Print(str);
}

void Calcule(int l,int p, int plaquesPrises,long plaque1,long plaque2)
{
  long r;  
  ResultatLigne[l]=plaque1+plaque2;
  SaveSolution.valeur1[l]=plaque1;
  SaveSolution.operation[l]=ADD;
  SaveSolution.valeur2[l]=plaque2;
  SaveSolution.resultat[l]=ResultatLigne[l];
  compte(l+1,p-plaquesPrises);
  if(plaque1!=1 && plaque2!=1)
  {
    ResultatLigne[l]=plaque1*plaque2;
    SaveSolution.operation[l]=MUL;
    SaveSolution.resultat[l]=ResultatLigne[l];
    compte(l+1,p-plaquesPrises);


    if(plaque1>=plaque2)
    {
      ResultatLigne[l]=plaque1-plaque2;
      if(ResultatLigne[l])
      {
        SaveSolution.operation[l]=SOUS;
        SaveSolution.resultat[l]=ResultatLigne[l];
        compte(l+1,p-plaquesPrises);
      }
      r=plaque1%plaque2;
      if(!r)
      {
        ResultatLigne[l]=plaque1/plaque2;
        SaveSolution.operation[l]=DIV;
        SaveSolution.resultat[l]=ResultatLigne[l];
        compte(l+1,p-plaquesPrises);
      }
    }
    else
    {
      ResultatLigne[l]=plaque2-plaque1;
      SaveSolution.valeur1[l]=plaque2;
      SaveSolution.operation[l]=SOUS;
      SaveSolution.valeur2[l]=plaque1;
      SaveSolution.resultat[l]=ResultatLigne[l];
      compte(l+1,p-plaquesPrises);
     
      r=plaque2%plaque1;
      if(!r)
      {
        ResultatLigne[l]=plaque2/plaque1;
        SaveSolution.operation[l]=DIV;
        SaveSolution.resultat[l]=ResultatLigne[l];
        compte(l+1,p-plaquesPrises);
      }
    }
  }
  else if(plaque1>=plaque2)
  {
    ResultatLigne[l]=plaque1-plaque2;
    if(ResultatLigne[l])
    {
      SaveSolution.operation[l]=SOUS;
      SaveSolution.resultat[l]=ResultatLigne[l];
      compte(l+1,p-plaquesPrises);
    }
  }
  else
  {
    ResultatLigne[l]=plaque2-plaque1;
    SaveSolution.valeur1[l]=plaque2;
    SaveSolution.operation[l]=SOUS;
    SaveSolution.valeur2[l]=plaque1;
    SaveSolution.resultat[l]=ResultatLigne[l];
    compte(l+1,p-plaquesPrises);
  }
}

void compte(int l,int p)     // l= numeroligne, p=plaqueRestantes
{
  int i,j,k,n;
  long ecart;
  long plaque1,plaque2;

  NombreAppelCompte++;

  if(l==NombrePlaques-1)
  {
    ecart=Resultat-ResultatLigne[l-1];
    if(ecart<0)
      ecart=-ecart;
    if(ecart<=MeilleurEcart)
    {
      if(ecart<MeilleurEcart)
      {
        MeilleurEcart=ecart;
        BestSolution=SaveSolution;
        MeilleurNombrePlaques=NombrePlaques;
        if(!ecart)
        {
          Solutions++;
          AfficheSolution(l);
        }
      }
      else     // (ecart==MeilleurEcart)
      {
        if(!ecart)
          Solutions++;
        if(NombrePlaques<MeilleurNombrePlaques)
        {
          BestSolution=SaveSolution;
          MeilleurNombrePlaques=NombrePlaques;
          if(!ecart)
            AfficheSolution(l);
        }
      }
    }

    return;
  }

  switch(Cas[NombrePlaques][Config].typeoperation[l])
  {
    case PP :

    for(i=0;i<p-1;i++)
    {
      for(j=i+1;j<p;j++)
      {
        plaque1=Plaque[l][i];   // prend 2 plaques parmi les C(p,2)=(p*(p-1))/2
        plaque2=Plaque[l][j];   // couples possibles de plaques restantes
  
        n=0;
        for(k=0;k<p;k++)
        {
          if(k!=i && k!=j)
          {
            Plaque[l+1][n]=Plaque[l][k];
            n++;
          }
        }

        Calcule(l,p,2,plaque1,plaque2);

      }
    }

    break;

    case RP :

    for(i=0;i<p;i++)
    {
      plaque1=ResultatLigne[l-1];  // prend 1 plaque parmi les p plaques restantes
      plaque2=Plaque[l][i];        // et le resultat precedent

      n=0;
      for(k=0;k<p;k++)
      {
        if(k!=i)
        {
          Plaque[l+1][n]=Plaque[l][k];
          n++;
        }
      }

      Calcule(l,p,1,plaque1,plaque2);
    }

    break;
    
    case RR :

    plaque1=ResultatLigne[l-2];   // prend les 2 resultats pr‚c‚dents :
    plaque2=ResultatLigne[l-1];
    
    for(k=0;k<p;k++)                  // simple recopie au niveau suivant
      Plaque[l+1][k]=Plaque[l][k];

    Calcule(l,p,0,plaque1,plaque2);

    break;

    case RR2 : // meme chose que "case RR" sauf la ligne qui suit :

    plaque1=ResultatLigne[l-3];   // prend les 2 resultats pr‚c‚dents
    plaque2=ResultatLigne[l-1];   // avec un resultat intermediaire : ResultatLigne[l-2] 
    
    for(k=0;k<p;k++)                  // simple recopie au niveau suivant
      Plaque[l+1][k]=Plaque[l][k];

    Calcule(l,p,0,plaque1,plaque2);

    break;

    default :
    AfficheErreurParametres();
  }
}

int AddIn_main(int isAppli, unsigned short OptionNum)
{
	
    unsigned int key;
	int i;
start:
	
	AffichePresentation();
	for(i=0;i<6;i++)  // rentre la liste
		PlaqueIni[i]=entree();
	
	locate(1,4);
	Print((unsigned char*)"et le resultat");
	Resultat = entree();

	for(i=0;i<6;i++)  // initialise plaque[][]
		Plaque[0][i]=PlaqueIni[i];
	MeilleurEcart=LONG_MAX; //ecart maximal
	MeilleurNombrePlaques=INT_MAX;

	NombreAppelCompte=0;

	Solutions=0;

	for(NombrePlaques=6;NombrePlaques>=2;NombrePlaques--)
		for(Config=0;Config<NombreConfigs[NombrePlaques];Config++)
			compte(0,6);

    if(MeilleurEcart>0)
    {
      AfficheSolution(MeilleurNombrePlaques-1);
    }
	
    while(1){
        GetKey(&key);
		if (key==KEY_CTRL_AC)
			goto start;
    }

    return 1;
}




//****************************************************************************
//**************                                              ****************
//**************                 Notice!                      ****************
//**************                                              ****************
//**************  Please do not change the following source.  ****************
//**************                                              ****************
//****************************************************************************


#pragma section _BR_Size
unsigned long BR_Size;
#pragma section


#pragma section _TOP

//****************************************************************************
//  InitializeSystem
//
//  param   :   isAppli   : 1 = Application / 0 = eActivity
//              OptionNum : Option Number (only eActivity)
//
//  retval  :   1 = No error / 0 = Error
//
//****************************************************************************
int InitializeSystem(int isAppli, unsigned short OptionNum)
{
    return INIT_ADDIN_APPLICATION(isAppli, OptionNum);
}

#pragma section

