// Conversion de nombre romain en décimal
//
// On s'interesse à l'ecriture des "chiffres romains", utilisee dans l'antiquite pour
// representer les nombres positifs differents de 0. On se limite aux nombres de valeur
// inferieure a 400, qui peuvent s'ecrire avec les symboles suivants :
//  I vaut 1,
//  V vaut 5,
//  X vaut 10,
//  L vaut 50,
//  C vaut 100.
//
// Pour convertir un nombre romain en sa valeur decimale, on a les regles suivantes :
//   Une meme lettre ne peut pas etre utilisée 4 fois consecutivement,
//       par exemple XXXX est interdit
//   Une lettre placee a droite d'une autre lettre de valeur superieure ou égale,
//        vient s'ajouter à sa valeur. Par exemple XI vaut 10+1=11 et
//        XXX vaut 10+10+10=30.
//   On considère que I est une "unite" pour V et X, et que X est une "unite" pour L et C.
//   Une unique lettre d'unite placee a gauche d'une lettre correspondante doit lui etre
//         retranchee. Par exemple XIX vaut 10 + (-1 + 10) = 19. Autre exemple : 
//         XCIX vaut (-10 + 100) + (-1 + 10) = 99.
//   Les lettres sont ecrites par valeur decroissante de gauche à droite, a l'exception
//         des unites a retrancher selon la regle precedente. Par exemple 150 ne
//         peut se noter que CL, et la notation LC est interdite.
//         Notez bien que LC ne peut *pas* signifier (-50 + 100) = 50 car L n'est pas
//         une unite pour C et donc ne peut pas lui etre retranchee.
//

//
// nov 2008, oct 2011, Denis Robilliard


#include <stdio.h>

// taille de la chaîne contenant le nombre romain
#define MAX_TAILLE 100

// declarations preliminaires des fonctions auxilliaires
void saisir(char *ch_romain, int taille_max);
void afficher(int val_decimal);
void convertir(char *ch_romain, int *val);
int valeur(char c);
int possible(char p, char c);

int main() {
  char ch_romain[MAX_TAILLE];
  int val_decimal;

  saisir(ch_romain, MAX_TAILLE);

  convertir(ch_romain, &val_decimal);

  afficher(val_decimal);

  return 0;
} // main


void saisir(char *ch_romain, int taille_max) {
  printf("Entrez un chiffre romain entre 1 et 399 : ");
  // attention fgets recupere aussi le '\n' de fin de saisie
  fgets(ch_romain, taille_max, stdin);
}


void afficher(int val_decimal) {
  if (val_decimal <= 0)
    printf ("Erreur : nombre romain non valide\n");
  else 
    printf ("%d\n", val_decimal);
}

// conversion d'un caractere
int valeur(char c) {
  switch (c) {
  case 'I' : return 1;
  case 'V' : return 5;
  case 'X' : return 10;
  case 'L' : return 50;
  case 'C' : return 100;
  default : // pas un caractere correct !
    return 0; // code d'erreur (booleen faux)
  }
}

int possible(char p, char c) {
  if (p == 'I' && (c == 'V' || c== 'X'))
    return 1;
  if (p == 'X' && (c == 'L' || c== 'C'))
    return 1;
  // else
  return 0;
}

void convertir(char *ch_romain, int *val) {
  char cour, prec; // caractere courant et precedent
  int rep = 0; // nombre de repetition d'un caractere
  int somme = 0; // accumulation des valeurs en cours de conversion
  int i;

  cour = ch_romain[0];
  // test de correction
  if (! valeur(cour)) {
    *val = 0; // code d'erreur
    return;
  }
    
  rep = 1;
  // visiter tous les caractères utiles
  for (i = 1; ch_romain[i] != 0 && ch_romain[i] != '\n'; i++) {
    prec = cour;
    cour = ch_romain[i];
    // test de correction
    if (! valeur(cour)) {
      *val = 0; // code d'erreur
      return;
    }
    // repetition ?
    if (cour == prec) {
       rep++;
      // test : pas trop de repetitions ?
      if (rep > 3) {
	*val = 0; // code d'erreur
	return;
      }
      somme += valeur(prec); // ok => sommer
    }
    // décroissant ?
    if (valeur(prec) > valeur(cour)) {
      somme += valeur(prec); // sommer
      rep = 1;
    }
    // croissant ?
    if (valeur(prec) < valeur(cour)) {
      if (!possible(prec,cour) || // pas une unite correcte ou ...
	  (rep > 1)) { // ... pas de répétition possible
	*val = 0; // code d'erreur
	return;
      }
      // unite a retrancher
      somme -= valeur(prec);
    }
  } // for
  
  // ne pas oublier le dernier chiffre
  somme += valeur(cour);
  *val = somme;
}




