Una solution per il RomanEval...

Quando Andrian ha postato il Quiz sull'implementazione della funzione RomanEval mi sa che mi son fatto prendere un po la mano e mi sono un po sbizzarrito.... non ho rispettato le regole, come dice Adrian annunciando i vincitori, ma ne ho ricavato un solvitore semplice di espressioni romane che va ben oltre i numeri dall'1 al 10.... e se proprio vogliamo dirla tutta: chi non ha bisogno? :-D

Se siete tutti curiosi di vedere cosa ho sfornatao ecco qui come mi sono mosso. La base di partenza è l'esempio reale del pattern Interpreter proposto da doFactory. L'esempio si limitava a fare il parser di una cifra romana per ricavarne un intero... io ho esteso l'esempio per il tanto che mi serviva.

Prima cosa fatto  refeactoring dell'oggetto Context, di cui fondamentalmente non mi piacevano i nomi :-p


class Context
{
  // Fields
  private string romanExpression;
  private int number;
  
  // Constructors
  public Context()
  {
  }
  
  // Properties
  public string RomanExpression
  {
    get{ return romanExpression; }
    set{ romanExpression = value; }
  }
  
  public int Number
  {
    get{ return number; }
    set{ number = value; }
  }
}

Quindi ho implementato e aggiunto il metodo Format nella classe astratta Expression.


abstract class Expression
{
  
  // ..
  
  #region Format
  public void Format(Context context)
  {
  
    int a = (int)(context.Number / Multiplier()); 
    int x;
    Math.DivRem(a, 10, out x);
    if(x == 9)
    {
      context.RomanExpression += Nine(); 
    }
    else if(x >= 5)
    {
      context.RomanExpression += Five();
      int ones = x - 5;
      for(int i = 0; i < ones; i++)
      {
        context.RomanExpression += One();
      }
    }
    else if(x == 4)
    {
      context.RomanExpression += Four();
    }
    else
    {
      for(int i = 0; i < x; i++)
      {
        context.RomanExpression += One();
      }
    }
  }
  #endregion
  
  // ..
  
}

Infine ho implementato una classe di utility/calsse facciata per aiutarmi a usare/_coordinare_ le strutture implementate.


public sealed class SimpleRomanEvaluetor
{

  #region Expression Interpreters   static ThousandExpression M = new ThousandExpression();   static HundredExpression C = new HundredExpression();   static TenExpression X = new TenExpression();   static OneExpression I = new OneExpression();   #endregion      #region Constructors   private SimpleRomanEvaluetor(){;}   #endregion      #region Eval   public static string Eval(string expression)   {     Regex expressionInterpreter = new Regex(@"(?<a>\w+[^+-])(?<op>[+-])(?<b>\w+[^+-])");     Match expressionMatch = expressionInterpreter.Match(expression);     string a = expressionMatch.Groups["a"].Value;     string op = expressionMatch.Groups["op"].Value;     string b = expressionMatch.Groups["b"].Value;     int intValueOfA = ToInt(a);     int intValueOfB = ToInt(b);          int resultOfExpression = 0;     switch(op)     {       case "+":         resultOfExpression = intValueOfA + intValueOfB;         break;       case "-":         resultOfExpression = intValueOfA - intValueOfB;         break;       default:         throw new NotSupportedException("Operatore non supportato.");     }     return ToString(resultOfExpression);        }   #endregion        #region Conversions methods   public static int ToInt(string expression)   {       Context context = new Context();       context.RomanExpression = expression;       context.Number = 0;       M.Interpret(context);       C.Interpret(context);       X.Interpret(context);       I.Interpret(context);       return context.Number;   }        public static string ToString(int number)   {       Context context = new Context();       context.RomanExpression = string.Empty;       context.Number = number;       M.Format(context);       C.Format(context);       X.Format(context);       I.Format(context);          return context.RomanExpression;   }   #endregion }

...beh a questo punto manca solo un main dove fare qualche test del buon funzionamento :-p

static void Main(string[] args)
{
  string expression = "VIII+XII";
  string result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  expression = "XV-VII";
  result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  expression = "III-III";
  result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  expression = "XIV-III";
  result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  expression = "IX+IV";
  result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  expression = "MIX+CIV";
  result = SimpleRomanEvaluetor.Eval(expression);
  Console.WriteLine("{0}={1}", expression, result);
  
  Console.ReadLine();
}

Lo lancio... ed ecco qui il risultato!

VIII+XII=XX
XV-VII=VIII
III-III=
XIV-III=XI
IX+IV=XIII
MIX+CIV=MCXIII

Semplicente fantastico! :-D Peccato che sono un poco uscito dalle righe e non ho centrato l'obbiettivo! :-o

«luglio»
domlunmarmergiovensab
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567