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