Web Log di Adrian Florea

"You know you've achieved perfection in design, not when you have nothing more to add, but when you have nothing more to take away." Antoine de Saint-Exupery
posts - 440, comments - 2715, trackbacks - 3944

My Links

Archives

Post Categories

Image Galleries

.RO Blogs

.RO People

.RO Sites

Blogs

Furls

Links

vinCitori

RomanEval (i vincitori con le loro soluzioni)

Grande divertimento con questi quiz, ragazzi!... Alcune soluzioni sono degne di TheDailyWTF! (sì, WTF viene proprio da What The F**k :-))

Inizio come sempre con la soluzione a cui ho pensato io e lascio poi che le vostre parlino da sole:

private enum Roman
{
  UnFintoZeroRomano,
  I, II, III, IV, V, VI, VII, VIII, IX, X,
  XI, XII, XIII, XIV, XV, XVI, XVII, XVIII, XIX, XX
}

public static string RomanEval(string r)
{
  string[] split = r.Split('+', '-');
  int t1 = (int)Enum.Parse(typeof(Roman), split[0]);
  int t2 = (int)Enum.Parse(typeof(Roman), split[1]);
  Roman ret = (Roman)(t1 - t2 * ((int)r[split[0].Length] - 44));
  return ret.ToString().Substring(0, ret.ToString().Length % ((Roman)0).ToString().Length);
}

Si può notare l'uso di una enum, l'espressione di ritorno calcolata in base al codice ASCII dell'operatore, e il trattamento dello 0 con l'aiuto di un piccolo trucchetto: nella enum il nome dell'elemento corrispondente al valore 0, UnFintoZeroRomano, deve avere una lunghezza superiore a qualunque altro elemento per ottenere nella return una sottostringa di lunghezza 0 per esso (a questo serve il modulo %).

Il primo che mi ha mandato una soluzione corretta è stato (anche stavolta) Flavio Polesello:

// soluzione di Flavio Polesello (1)
public static string RomanEval(string r)
{
  string[] romanNumbers =
  {
    "",
    "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X",
    "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"
  };
  int[] opValues = {1, -1};
  string rWithSum = r.Replace("-", "+");
  string[] opNumbers = rWithSum.Split("+".ToCharArray());
  int op = opValues[Math.Abs(r.CompareTo(rWithSum))];
  int a = Array.IndexOf(romanNumbers, opNumbers[0]);
  int b = Array.IndexOf(romanNumbers, opNumbers[1]);
  int intResult = a + b * op;
  return romanNumbers[intResult];
}

Il giorno dopo, mi ha mandato una seconda soluzione, direi la più originale di tutte:

// soluzione di Flavio Polesello (3)
public class RomanQuiz
{
  private static string[] romanNumbers =
  {
    "",
    "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X",
    "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"
  };

  private delegate int ExecuteOpDelegate(int a, int b);

  private static int ExecuteAdd(int a, int b)
  {
    return a + b;
  }

  private static int ExecuteSub(int a, int b)
  {
    return a - b;
  }

  private static string ConvertInt32ToRoman(int number)
  {
    return romanNumbers[number];
  }

  private static int ConvertRomanToInt32(string number)
  {
    return Array.IndexOf(romanNumbers, number);
  }

  public static string RomanEval(string r)
  {
    System.Collections.Hashtable registeredOps = new System.Collections.Hashtable();

    // registra le operazioni eseguibili
    registeredOps.Add("+", new ExecuteOpDelegate(ExecuteAdd));
    registeredOps.Add("-", new ExecuteOpDelegate(ExecuteSub));

    // determina i numeri romani dell'espressione
    string[] opNumbers = r.Split("+-".ToCharArray());

    // determina l'operatore
    string op = r.Substring(opNumbers[0].Length, 1);

    // determina l'operazione che deve essere eseguita
    ExecuteOpDelegate executeOp = (ExecuteOpDelegate)registeredOps[op];

    // converte i numeri da romani a interi
    int a = ConvertRomanToInt32(opNumbers[0]);
    int b = ConvertRomanToInt32(opNumbers[1]);

    // esegue l'operazione
    int c = executeOp(a, b);

    // converte e restituisce il numero romano calcolato
    return ConvertInt32ToRoman(c);
  }
}

Il secondo che mi ha mandato una soluzione corretta è stato Lorenzo Melato:

// soluzione di Lorenzo Melato (2)
public static string RomanEval(string r)
{
  System.Text.RegularExpressions.Regex reRomanExpr = new System.Text.RegularExpressions.Regex
  (
    "\\A\\s*(?i?[xv]?|v?i{0,3})\\s*(?[+-]+)\\s*(?i?[xv]?|v?i{0,3})\\s*\\Z",
    System.Text.RegularExpressions.RegexOptions.IgnoreCase
  );
  string[] roman =
  {
    string.Empty,
    "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X",
    "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"
  };

  System.Text.RegularExpressions.Match m = reRomanExpr.Match(r);
  string expr = Array.IndexOf(roman, m.Groups["rn"].Value).ToString() + m.Groups["op"].Value + Array.IndexOf(roman, m.Groups["ln"].Value).ToString();
  Type t = Type.GetTypeFromProgID("MSScriptControl.ScriptControl");
  object obj = Activator.CreateInstance(t);
  t.InvokeMember("Language", System.Reflection.BindingFlags.SetProperty, Type.DefaultBinder, obj, new string[]{"VBScript"});
  int res = Convert.ToInt32(t.InvokeMember("Eval", System.Reflection.BindingFlags.InvokeMethod, null, obj, new string[]{expr}));
  return roman[res];
}

Lascio a voi i commenti :-)

L'idea di utilizzare le regular expression l'ha avuta anche M.rkino (in più, ha implementato anche il pattern Interpreter). Non è stato attento però al vincolo "è vietato l'uso di istruzioni di selezione"... Peccato, aveva fatto non una soluzione, ma una solution di ben 250 righe! :-)

Il terzo, Marco Poponi - con la sua dose di umorismo :-)

// soluzione di Marco Poponi (4)
public static string RomanEval(string r)
{
  r = r.Replace("IV", "IIII");
  r = r.Replace("V", "IIIII");
  r = r.Replace("IX", "IIIIIIIII");
  r = r.Replace("X", "IIIIIIIIII");

  int x=0;
  try
  {
    x = r.Split('+')[0].Length + r.Split('+')[1].Length;
  }
  catch(Exception E)
  {
    x = r.Split('-')[0].Length - r.Split('-')[1].Length;
  }

  string o = "";
  o = o.PadLeft(x, 'I');
  o = o.Replace("IIIIIIIIII", "X");
  o = o.Replace("IIIIIIIIII", "X");
  o = o.Replace("IIIIIIIII", "IX");
  o = o.Replace("IIIII", "V");
  o = o.Replace("IIII", "IV");
  return o;
}

Il quarto e ultimo, Daniele Proietti:

// soluzione di DanieleProietti (5)
public static string RomanEval(string r)
{
  r = r.ToUpper();

  System.Collections.ArrayList myAL = new System.Collections.ArrayList();
  myAL.Add("");
  myAL.Add("I");
  myAL.Add("II");
  myAL.Add("III");
  myAL.Add("IV");
  myAL.Add("V");
  myAL.Add("VI");
  myAL.Add("VII");
  myAL.Add("VIII");
  myAL.Add("IX");
  myAL.Add("X");
  myAL.Add("XI");
  myAL.Add("XII");
  myAL.Add("XIII");
  myAL.Add("XIV");
  myAL.Add("XV");
  myAL.Add("XVI");
  myAL.Add("XVII");
  myAL.Add("XVIII");
  myAL.Add("XIX");
  myAL.Add("XX");

  int operatorePos = r.IndexOfAny(new char[] {'+', '-'});
  string operatore = r.Substring(operatorePos, 1);

  int val1 = myAL.IndexOf(r.Substring(0, operatorePos));
  int val2 = myAL.IndexOf(r.Substring(operatorePos + 1));

  return myAL[val1 + (val2 * int.Parse(operatore + "1"))].ToString();
}

Per i prossimi sto pensando di cambiare il formato, rinunciare ai vincoli e premiare (soggettivamente per forza...) la bellezza della progettazione.

Grazie a tutti, il vostro Inquizzitore di fiducia :-)

adrian_floreachiocciolayahoopuntocom

Print | posted on mercoledì 28 luglio 2004 16:20 | Filed Under [ Test Sharp ]

Powered by:
Powered By Subtext Powered By ASP.NET