sábado, 12 de febrero de 2011

[Video y Ejercicio] Agiles @ Buenos Aires: Coding Dojo

Agiles.org

La semana pasada se realizó la reunión mensual de Agiles @ Buenos Aires, como anuncié en un post anterior.

No voy a repetir todo el detalle, sino a dejar el video de la introducción de Adrián Eidelman, y el arranque del ejercicio con el primer par frente a la computadora.

El resto se los ahorro porque son dos horas en las que no se llega a leer claramente el código y la conversación entre los pares no llega a distinguirse claramente. Es un tipo de actividad que requiere presencia directa para disfrutarla, y recomiendo que estén atentos si les interesa porque ya hay en marcha una iniciativa de Katayunos (desayunos entre tres o cuatro personas para practicar Code Katas), y cualquiera puede organizar algo así con sus compañeros de trabajo o de estudio.

Pero para que no se pierdan el total (aunque la gracia es el camino recorrido más que el punto final), dejo el ejercicio tal cuál como quedó resuelto durante la reunión (sin edición ni retoque), cortesía de Adrián. La plataforma y lenguajes son anecdóticos, pero en este caso se realizó en C# utilizando Visual Studio 2010 y NUnit como framework de testing.

Van primero los tests (un primer ejercicio puede ser tomar los tests y tratar de escribir el código sobre ellos):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Moq;
using NUnit.Framework;
using NumerosRomanos;

namespace NumerosRomanos.Tests
{
    [TestFixture]
    public class Tests
    {
        Conversor conversor;

        Dictionary<int, string> valores;

        [TestFixtureSetUp]
        public void setUp()
        {
            conversor = new Conversor();
            valores = new Dictionary<int, string>();
            valores.Add(1, "I");
            valores.Add(5, "V");
            valores.Add(10, "X");
            valores.Add(50, "L");
            valores.Add(100, "C");
            valores.Add(500, "D");
            valores.Add(1000, "M");
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void El0ArrojaExcepcion()
        {
            int numeroArabigo = 0;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void NumeroNegativoArrojaExcepcion()
        {
            int numeroArabigo = -1;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void El4000ArrojaExcepcion()
        {
            int numeroArabigo = 4000;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);
        }

        [Test]
        public void El1DeberiaDevolverI()
        {
            int numeroArabigo = 1;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("I", numeroRomano);
        }

        [Test]
        public void El5DeberiaDevolverV()
        {
            int numeroArabigo = 5;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("V", numeroRomano);
        }

        [Test]
        public void El10DeberiaDevolverX()
        {
            int numeroArabigo =10;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("X", numeroRomano);
        }

        [Test]
        public void El2DeberiaDevolverII()
        {
            int numeroArabigo = 2;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("II", numeroRomano);
        }

        [Test]
        public void El3DeberiaDevolverIII()
        {
            int numeroArabigo = 3;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("III", numeroRomano);
        }

        [Test]
        public void El15DeberiaDevolverXV()
        {
            int numeroArabigo = 15;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("XV", numeroRomano);
        }

        [Test]
        public void El4DeberiaDevolverIV()
        {
            int numeroArabigo = 4;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("IV", numeroRomano);
        }
        [Test]
        public void El48DeberiaDevolverXLVIII()
        {
            int numeroArabigo = 48;

            string numeroRomano = conversor.ANumerosRomanos(numeroArabigo);

            Assert.AreEqual("XLVIII", numeroRomano);
        }

        [Test]
        public void RetornaValoreConocidos()
        {
        
            foreach(var i in valores.Keys)
                Assert.AreEqual(valores[i], conversor.ANumerosRomanos(i));

        }
    }
}

Y aquí está finalmente la implementación misma (para quienes quieran hacer trampa):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NumerosRomanos
{
    public class Conversor
    {
        List<int> valoresArabigos = new List<int> 
            {1,4,5,9,10,40,50,90,100,400,500,900,1000};
        List<string> valoresRomanos = new List<string> 
            {"I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M"};
    
        public Conversor()
        {
            valoresArabigos.Reverse();
            valoresRomanos.Reverse();
        }

        public string ANumerosRomanos(int numeroArabigo)
        {
            if (numeroArabigo<=0 || numeroArabigo>3999)
                throw new ArgumentException();


            string resultado="";

            while (numeroArabigo > 0)
            {
                foreach (var i in valoresArabigos)
                {
                    if (i <= numeroArabigo)
                    {
                        resultado += valoresRomanos[valoresArabigos.IndexOf(i)];
                        numeroArabigo -= i;
                    }
                }
            }

            return resultado;
       }
    }
}