Contraseñas y entropía

Contraseñas y entropía

Hoy un amigo nos ha enviado un mensaje al grupo de la Promoción para ver que opinábamos al respecto de la siguiente imagen

IMG-20200902-WA0018.jpg

y yo que la he visto, instantáneamente me he acordado del cálculo necesario para rellenar esta tabla.

Lo primero de todo se debe calcular la entropía. La entropía de una contraseña es calculo matemático que representa un indicador de como se encuentra esta contraseña sobre una población, si incluimos en nuestra contraseña mayúsculas, minúsculas, números y símbolos, la entropía de nuestra contraseña será mayor puesto que la población de caracteres usados es mucho mayor, en este caso, unos 94 (26 minúsculas, 26 mayúsculas, 10 números y 32 símbolos). La fórmula es la siguiente:

entropia.png

o lo que es lo mismo, es el logaritmo en base de 2 de la cantidad de elementos de la población por la longitud de la cadena. Si efectuamos el cálculo inverso, 2 elevado a la entropía debe ser igual a la población elevada al número de caracteres de  nuestra contraseña, que esto serían el número máximo de operaciones necesarias para intentar reventar nuestra password por fuerza bruta.

Si nuestra contraseña usa solo las minúsculas, su «pool» sería de 26 y por tanto la contraseña tendría una entropía baja y fácil de descubrir.

Si hay alguien que quiera comprobar la fuerza de su contraseña online puede hacerlo desde Kaspersky
Bien, pero lo que a mi me importa es como sabemos, con código. En la clase le he incluido una penalización si nuestra contraseña se encuentra entre las más conocidas.

En C#

    /*
************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         PasswordEntropy.cs
    * Descripción:     Clase que calcula la entropia y el tiempo en descifrar por fuerza bruta de de una contraseña
    * Historial:
    *                  1. Joaquin Martínez Rus - 02 sep 2020. Creación
    *
    * Comentarios:
    *
    *
    ****************************************************************/
    public class PasswordEntropy
    {
        public PasswordEntropy(string password)
        {
            Password = password;

        }

        public string Password { get; set; }
        public double Entropy => GetEntropy();
        public string EntropyToString => GetTimeByEntropy(Entropy);

        private double GetEntropy()
        {
            //Pools
            double pool = 0;

            // Numbers
            pool += Password.Any(k => char.IsDigit(k)) ? 10 : 0;
            // Lower 26
            pool += Password.Any(k => char.IsLower(k)) ? 26 : 0;
            // Upper 26
            pool += Password.Any(k => char.IsUpper(k)) ? 26 : 0;
            // Simbols 30
            pool += Password.Any(k => (char.IsSymbol(k) || char.IsPunctuation(k))) ? 32 : 0;

            if (pool == 0) return pool;
            // entropy = Lenght * log pool / log2
            var p = Math.Log(pool, 2);
            var entropy = Password.Length * Math.Log(pool, 2);

            // el uso de una contraseña famosa, indica una falta de seguridad absoluta
            // por lo que no se incluye como deducción de entropía, sino que se incluye en el
            // mismo cálculo de la entropía
            if (IsFamous(Password))
            {
                entropy = (int)Entropies.NoSecurity - 1; // Inexistencia de seguridad
            }
            return entropy;
        }

        private const double OPERATIONPERSECOND = 4*10E12;

        private bool IsFamous(string password)
        {
            var list = new List()
            {
                "1234",
                "2000",
                "12345",
                "111111",
                "123123",
                "123456",
                "654321",
                "696969",
                "1234567",
                "12345678",
                "abc123",
                "alejandra",
                "america",
                "baseball",
                "bonita",
                "daniel",
                "dragon",
                "estrella",
                "football",
                "harley",
                "iloveyou",
                "jennifer",
                "jesus",
                "jordan",
                "letmein",
                "mariposa",
                "master",
                "michael",
                "monkey",
                "mustang",
                "password",
                "pussy",
                "qwerty",
                "roberto",
                "sebastian",
                "shadow",
                "superman",
                "Tequiero"
            };
            return list.Contains(password);
        }

        public enum Entropies
        {
            Blank = 0,
            NoSecurity =10,
            TooWeak=20,
            VeryWeak=28,
            Weak=35,
            Medium=55,
            Strong=75,
            Stronger=127,
            OverTheTopStrong = 190
        }

        private string GetTimeByEntropy(double entropy)
        {
            if (entropy == 0) return string.Empty;
            string output = "";

            double value = Math.Pow(2, entropy) / OPERATIONPERSECOND;
            double ms = 0;
            double seconds = value;
            double minutes = seconds / 60;
            double hours = minutes / 60;
            double days = hours / 24;
            double months = days / 30;
            double years = months / 12;
            double centuries = years / 100;
            double millennium = centuries / 10;

            seconds = value;
            if (value == 0) return "";

            if (seconds > 0 && seconds  59 && hours > 24 && days  11 && years < 100 && centuries < 1000000)
            {
                output = "Tu contraseña puede ser descifrada en más de un millón de años!";
            }
            else
            {
                millennium = Math.Round(millennium, 1);
                output = $"Tu contraseña puede ser descifrada en {millennium}, {(millennium == 1 ? "milenio" : "milenios")}";
            }

            return output;
        }
    }

static void Main(string[] args)
        {
            var password = "x#Pr0m0cio_N";

            for (int i = 1; i <= password.Length; i++)
            {
                var pwd = new PasswordEntropy(password.Substring(0,i));
                Console.WriteLine($"Password: {pwd.Password}\n{pwd.EntropyToString}");
                Console.WriteLine("Press any key");
            }

            Console.ReadKey();
        }

el resultado iterando por la contraseña que he creado


Password: x
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#P
Tu contraseña puede ser descifrada en 0, milisegundos
Press any key
Password: x#Pr
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0m
Tu contraseña puede ser descifrada en 17 milisegundos
Press any key
Password: x#Pr0m0
Tu contraseña puede ser descifrada en 2 segundos
Press any key
Password: x#Pr0m0c
Tu contraseña puede ser descifrada en 3 minutos
Press any key
Password: x#Pr0m0ci
Tu contraseña puede ser descifrada en 4 horas
Press any key
Password: x#Pr0m0cio
Tu contraseña puede ser descifrada en 15,6 dias
Press any key
Password: x#Pr0m0cio_
Tu contraseña puede ser descifrada en 4,1 años
Press any key
Password: x#Pr0m0cio_N
Tu contraseña puede ser descifrada en 3,8 siglos
Press any key

y en Kotlin

class PasswordEntropy(val password: String) {

    init {

    }

    fun entropy(): Double {

        //Pools
        var pool = 0.0

        // Numbers
        pool += if (password.any { c -> c.isDigit() }) 10.0 else 0.0
        // Lower 26
        pool += if (password.any { c -> c.isLowerCase() }) 26.0 else 0.0
        // Upper 26
        pool += if (password.any { c -> c.isUpperCase() }) 26.0 else 0.0
        val (noSymbols, symbols) = password.partition { it.isLetter() || it.isDigit() }
        // Simbols 32
        pool += if (symbols.count()>0) 32.0 else 0.0
        if (pool == 0.0) return pool
        // entropy = Lenght * log pool / log2

        var entropy = password.length * log2(pool)

        // el uso de una contraseña famosa, indica una falta de seguridad absoluta
        // por lo que no se incluye como deducción de entropía, sino que se incluye en el
        // mismo cálculo de la entropía
        if (isFamous()) {
            entropy = 9.0 // Inexistencia de seguridad
        }
        return entropy
    }

    private fun isFamous(): Boolean{
        return listOf(
            "1234",
            "2000",
            "12345",
            "111111",
            "123123",
            "123456",
            "654321",
            "696969",
            "1234567",
            "12345678",
            "abc123",
            "alejandra",
            "america",
            "baseball",
            "bonita",
            "daniel",
            "dragon",
            "estrella",
            "football",
            "harley",
            "iloveyou",
            "jennifer",
            "jesus",
            "jordan",
            "letmein",
            "mariposa",
            "master",
            "michael",
            "monkey",
            "mustang",
            "password",
            "pussy",
            "qwerty",
            "roberto",
            "sebastian",
            "shadow",
            "superman",
            "Tequiero").contains(password)

    }
    private val OPERATION_PER_SECOND: Double = 4*10E12

    fun entropyToString(): String {
        val entropy = entropy()
        if (entropy == 0.0) return ""

        val value = 2.0.pow(entropy) / OPERATION_PER_SECOND
        var ms = 0
        var seconds = value
        val minutes = seconds / 60.0
        val hours = minutes / 60.0
        val days = hours / 24.0
        val months = days / 30.0
        val years = months / 12.0
        val centuries = years / 100.0
        val millennium = centuries / 10.0

        seconds = value
        if (value == 0.0) return ""

        return "Contraseña: $password\n${if (ifa) "Es una contraseña conocida!\n" else ""}${when {
                    ms in 1..999 ->"Tu contraseña puede ser descifrada inmediatamente, yo no lo llamaría contraseña"
                    seconds > 0 && seconds  "Tu contraseña puede ser descifrada en ${seconds.toInt()} ${if (seconds.toInt() == 1) "segundo" else "segundos"}"
                    seconds > 59 && minutes   "Tu contraseña puede ser descifrada en ${minutes.toInt()} ${if (minutes.toInt() == 1) "minuto" else "minutos"}"
                    minutes > 59 && hours "Tu contraseña puede ser descifrada en ${hours.toInt()} ${if (hours.toInt() == 1) "hora" else "horas"}"
                    hours > 24 && days  "Tu contraseña puede ser descifrada en ${days.toInt()} ${if (days.toInt() == 1) "dia" else "dias"}"
                    days > 30 && months  "Tu contraseña puede ser descifrada en ${months.toInt()} ${if (months.toInt() == 1) "mes" else "meses"}"
                    months > 11 && years   "Tu contraseña puede ser descifrada en ${years.toInt()} ${if (years.toInt() == 1) "año" else "años"}"
                    years > 99 && centuries  "Tu contraseña puede ser descifrada en ${"%.1f".format(centuries)} ${if (centuries == 1.0) "siglo" else "siglos"}"
                    millennium > 1000000 -> "Tu contraseña puede ser descifrada en más de un millón de años!"
            else -> "Tu contraseña puede ser descifrada en ${millennium.toInt()} ${if (millennium.toInt() == 1) "milenio" else "milenios"}"}}"
}

fun main(){
    val password = "x#Pr0m0cio_N";

    for (i in (1..password.length)) {
        val pwd = PasswordEntropy(password.substring(0,i))
        println("Password: ${pwd.password}\n${pwd.entropyToString()}\n")

    }
}

el resultado para Kotlin


Password: x
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#P
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0m
Tu contraseña puede ser descifrada en 17 milisegundos
Press any key
Password: x#Pr0m0
Tu contraseña puede ser descifrada en 2 segundos
Press any key
Password: x#Pr0m0c
Tu contraseña puede ser descifrada en 3 minutos
Press any key
Password: x#Pr0m0ci
Tu contraseña puede ser descifrada en 4 horas
Press any key
Password: x#Pr0m0cio
Tu contraseña puede ser descifrada en 15,6 dias
Press any key
Password: x#Pr0m0cio_
Tu contraseña puede ser descifrada en 4,1 años
Press any key
Password: x#Pr0m0cio_N
Tu contraseña puede ser descifrada en 3,8 siglos
Press any key

El archivo jar podéis descargarlo desde aquí

Archivo ZIP

SHA256 9314879A535675E813EAC13CEC9B056CAADC4C080E5E033E239E2D88A60F55E3

Archivo jar

SHA256 CA942FB971E34CB775E14F12C5B25E5E456044F02DD54447F5690FA05469C3C8

Saludos a la X Promoción del IPE 2!!!

 

Anuncio publicitario

Interface. Genetic Algorithm II

Interface. Genetic Algorithm II
En este post veremos como un algoritmo genético es capaz de ordenar un tablero de ajedrez. Es como si un niño de 2 años pusiera las piezas aleatoriamente en el tablero y el algoritmo se encargara de poner cada una en su sitio.

Crearemos una clase ChessPiece para cada figura de ajedrez y una clase ChessBoard que implementará la interfaz IMutable. Esto quiere decir que nuestro cromosoma es una lista de piezas de ajedrez y que el Fitness es del tipo doble.
Acto seguido, creamos el geneset o conjunto de genes que formarán el cromosoma donde incluiremos también la casilla vacía. Luego le daremos un valor a cada pieza y otro valor a cada casilla, cada vez que se acierte, el fitness se verá incrementado hasta el 100%.

class ChessBoard : IMutable {
    override val geneset = mutableListOf(
            ChessPiece("T",ChessPieceColor.BLACK,11),
            ChessPiece("C",ChessPieceColor.BLACK,13),
            ChessPiece("A",ChessPieceColor.BLACK,15),
            ChessPiece("D",ChessPieceColor.BLACK,16),
            ChessPiece("R",ChessPieceColor.BLACK,18),
            ChessPiece("A",ChessPieceColor.BLACK,15),
            ChessPiece("C",ChessPieceColor.BLACK,13),
            ChessPiece("T",ChessPieceColor.BLACK,11),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("T",ChessPieceColor.WHITE,10),
            ChessPiece("C",ChessPieceColor.WHITE,12),
            ChessPiece("A",ChessPieceColor.WHITE,14),
            ChessPiece("D",ChessPieceColor.WHITE,17),
            ChessPiece("R",ChessPieceColor.WHITE,19),
            ChessPiece("A",ChessPieceColor.WHITE,14),
            ChessPiece("C",ChessPieceColor.WHITE,12),
            ChessPiece("T",ChessPieceColor.WHITE,10),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5))

    init {

        geneset.addAll((1..32).map { ChessPiece("_",ChessPieceColor.EMPTY,0) })
    }

    override val target: Double = 64.0
    override var bestParent = createParent(0)
    override var bestFitness: Double = 0.0
    private val values = mutableListOf(11,13,15,16,18,15,13,11,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,10,12,14,17,19,14,12,10)

    override fun isSuccess(): Boolean = bestFitness == 1.0

    var result=""
    override fun start() {
        bestFitness = getFitness(bestParent)
        var childFitness: Double
        var child: MutableList
        //Display(bestParent, bestFitness)
        var attemps=0

        do {
            do {
                child = mutate(bestParent)
                childFitness = getFitness(child)

            } while (bestFitness > childFitness)

            bestFitness = childFitness
            bestParent = child
            result +=toShortString() + "\n\n\n"
            attemps ++
            println(toShortString() + "\n")
        } while (!isSuccess())
        println("Nº de intentos: $attemps")
    }

    override fun createParent(param: Any): MutableList {
        // llena el tablero con las 32 fichas piezas + 32 vacias
        return geneset.shuffled().toMutableList()
    }

    override fun getFitness(obj: MutableList): Double = obj.mapIndexed { index, chessPiece -> if (values[index] == chessPiece.value) 1.0 else 0.0  }.sum() / target

    override fun mutate(parent: MutableList): MutableList {
        val parentFitness: Double = getFitness(parent)
        var childFitness = 0.0
        var child = mutableListOf()

        do {
            child.clear()
            child.addAll(parent)

            val startIndex = Random.nextInt(bestParent.size)
            val endIndex = Random.nextInt(bestParent.size)
            val start = parent[startIndex]
            val end = parent[endIndex]
            child[startIndex] = end
            child[endIndex] = start
            childFitness = getFitness(child)

        }while (childFitness chessPiece.toString() + if ((index+1) % 8 ==0) "\n" else "\t" }
            .joinToString("")}\nFitness: $bestFitness"

    fun toShortString(): String ="${bestParent
                    .mapIndexed { index, chessPiece -> (if (chessPiece.value==0) " " else if (chessPiece.value == values[index]) (if (chessPiece.color==ChessPieceColor.WHITE) "○" else "●") else "#")+if ((index+1) % 8 == 0) "\n" else "" }
                    .joinToString("")
        }\nFitness: ${"%.3f".format(bestFitness)}"
    fun  foo(collection: MutableList){

    }
}

fun main(){
    val chessBoard = ChessBoard()
    chessBoard.start()
    println(chessBoard.bestParent)
}

Y este es el resultado del progreso de los cromosomas para 36 intentos
cromosomas.png

TN	CN	AN	DN	RN	AN	CN	TN
PN	PN	PN	PN	PN	PN	PN	PN
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
PB	PB	PB	PB	PB	PB	PB	PB
TB	CB	AB	DB	RB	AB	CB	TB

Fitness: 1.0

Y ahora implementaremos la interfaz con mi mejor amigo, C#

 public class ChessPiece
    {
        public ChessPiece(string name, Colors color, int value)
        {
            Name = name;
            ChessPieceColor = color;
            Value = value;
        }

        public string Name { get; set; }
        public int Value { get; set; }
        public Colors ChessPieceColor { get; set; }

        public enum Colors
        {
            Black,
            White,
            Empty
        }

        public string ColorToString => ValueToString(ChessPieceColor);

        public new string ToString => $"{Name}{ColorToString}";

        private string ValueToString(Colors color)
        {
            switch (color)
            {
                case Colors.Black:
                    return "N";
                case Colors.White:
                    return "B";
                case Colors.Empty:
                    return "_";
                default:
                    return "";
            }
        }

    }

    public class ChessBoard : IMutable
    {
        public ChessBoard()
        {
            Geneset = new List()
            {
                    new ChessPiece("T", ChessPiece.Colors.Black, 11),
                    new ChessPiece("C", ChessPiece.Colors.Black, 13),
                    new ChessPiece("A", ChessPiece.Colors.Black, 15),
                    new ChessPiece("D", ChessPiece.Colors.Black, 16),
                    new ChessPiece("R", ChessPiece.Colors.Black, 18),
                    new ChessPiece("A", ChessPiece.Colors.Black, 15),
                    new ChessPiece("C", ChessPiece.Colors.Black, 13),
                    new ChessPiece("T", ChessPiece.Colors.Black, 11),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("T", ChessPiece.Colors.White, 10),
                    new ChessPiece("C", ChessPiece.Colors.White, 12),
                    new ChessPiece("A", ChessPiece.Colors.White, 14),
                    new ChessPiece("D", ChessPiece.Colors.White, 17),
                    new ChessPiece("R", ChessPiece.Colors.White, 19),
                    new ChessPiece("A", ChessPiece.Colors.White, 14),
                    new ChessPiece("C", ChessPiece.Colors.White, 12),
                    new ChessPiece("T", ChessPiece.Colors.White, 10),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5)
            };

            Geneset.AddRange(Enumerable.Range(0, 32).ToList().Select(k => new ChessPiece("_", ChessPiece.Colors.Empty, 0)));           

        }

        public List Geneset { get; set; }
        public double Target { get; set; } = 64;
        public List BestParent { get; set; }
        public double BestFitness { get; set; }

        private Random rnd = new Random();
        private IList Values = new List() { 11, 13, 15, 16, 18, 15, 13, 11, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 10, 12, 14, 17, 19, 14, 12, 10 };
        private string result = "";

        public List CreateParent(object param) => Suffled(Geneset);

        public double GetFitness(List obj) => obj
            .Select((item, index) => new { Item = item, Index = index })
            .Select(k => k.Item.Value == Values[k.Index] ? 1.0 : 0.0)
            .Sum()/Target;

        public bool IsSuccess() => BestFitness == 1.0;

        public List Mutate(List parent)
        {

            var parentFitness = GetFitness(parent);
            var childFitness = 0.0;
            var child = new List();

            do
            {
                child.Clear();
                child.AddRange(parent);

                var startIndex = rnd.Next(BestParent.Count());
                var endIndex = rnd.Next(BestParent.Count());
                var start = parent[startIndex];
                var end = parent[endIndex];

                child.RemoveAt(startIndex);
                child.Insert(startIndex, end);
                child.RemoveAt(endIndex);
                child.Insert(endIndex, start);

                childFitness = GetFitness(child);
                //print(child);
            } while (childFitness k.Value)));
        }

        public void Start()

        {
            BestParent = CreateParent(null);
            BestFitness = GetFitness(BestParent);
            var childFitness = 0.0;
            var child = new List();

            var attemps = 0;
            do
            {
                do
                {
                    child = Mutate(BestParent);
                    childFitness = GetFitness(child);
                } while (BestFitness > childFitness);

                BestFitness = childFitness;
                BestParent = child;
                result += ToShortString + "\n\n\n";
                Console.WriteLine(result);
                attemps++;
            } while (!IsSuccess());

            Console.WriteLine(ToShortString + "\n");
            Console.WriteLine($"Nº intentos: {attemps}");
        }

        private List Suffled(List source) => source
            .Select(x => new { value = x, order = rnd.Next() })
            .OrderBy(x => x.order).Select(x => x.value).ToList();

        public new string ToString => $"{string.Join("",BestParent.Select((item, index) => new { Item = item, Index = index }).Select(k => k.Item.ToString + (((k.Index + 1) % 8 == 0) ? '\n' : ' '))) }";
        public string ToShortString => $"{string.Join("",BestParent.Select((item, index) => new { Item = item, Index = index }).Select(k => (k.Item.Value == 0 ? " " : (k.Item.Value == Values[k.Index]) ? (k.Item.ChessPieceColor == ChessPiece.Colors.White ? "O" : "■") : "#") + (((k.Index + 1) % 8 == 0) ? '\n' : ' '))) }";

    }
 class Program
    {
        static void Main(string[] args)
        {
            var chessboard = new ChessBoard();
            chessboard.Start();
            Console.WriteLine(chessboard.ToString);
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }

Si quieres leer mi anterior post sobre la interface de algoritmos genéticos, aquí lo tienes.

Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Interface. Genetic Algorithm I

Interface. Genetic Algorithm I

¿Cómo conseguir un objetivo por los mismos medios por los que una especie sobrevive? La respuesta es, mutando y cruzándo sus individuos para obtener ese objetivo.

Los algoritmos genéticos desde el punto de vista del desarrollo de software, tienen casi todos un patrón único y si tienen un patrón único atienden a una estructura común, por tanto es como cualquier interface, atienden siempre a la misma composición, de modo que ¿Por qué no generamos una interface que implemente este comportamiento? ¿Por qué crear una interface? Generamos una interface porque esperamos que cualquier clase que implemente esta interface haga lo mismo y la interface es el elemento adecuado. (¿he entrado en bucle? uhmmm). Para saber más acerca de interfaces, aquí tiene un artículo de Wakicode.

Bien, la verdad que he buscado y «requetebuscado» (que dicen en mi tierra) y no he visto nada parecido acerca de una interface de algoritmo genéticos.

Un algoritmo genético tiene los siguientes elementos:

  • Un conjunto de genes en los que se basan cada uno de objetos generados
  • Un patrón inicial o digamos un Adán o una Eva
  • Un candidato a ser el mejor de la especie
  • Un indicador métrico de aptitud del mejor de la especie

y efectua las siguientes tareas:

  • Inicia el algoritmo
  • Crea el patrón inicial
  • Obtiene la métrica de cualquier objeto de la especie. Función de Aptitud
  • Ejecuta un cruce entre individuos de la especie. Cruce
  • Ejecuta una mutación sobre un objeto. Mutación
  • Comprueba si se ha cumplido con el objetivo. Criterio de parada
  • Si no se ha conseguido el objetivo, volvemos a realizar la tarea
  • Obtención de la solucióndiagrama algoritmo genetico.png

Además un algoritmo genético no tiene porque realizar un cruce porque a lo mejor nuestro problema lo podemos solucionar mutando solamente sus genes sin realizar cruce. Cada algoritmo hay que estudiarlo

Dicho esto nos ponemos manos a la obra y vamos a desarrollar una interfaz que tenga estos elementos y que nos permita realizar estas acciones con diferentes tipos. En principio voy a crear una interface del tipo Mutable y luego heredaré de esta para crear una nueva Crossover  con funciones de cruce.

En Kotlin

/**
 * @author Joaquin Martinez Rus ©
 * @since 15AGO20
 * version 1.1
 */
interface IMutable
{
    val geneset: T
    val target: F
    var bestParent: T
    var bestFitness: F

    /**
     * Return true when target is reached
     * @return Boolean
     */
    fun isSuccess(): Boolean

    /**
     * Start algorithm
     * @sample
     * CreateParent
     * Mutate
     * GetFitness
     * Compare
     * IsSuccess
     */
    fun start()

    /**
     * Return a new parent object
     * @param Parameter of generation
     * @return Type T
     */
    fun createParent(param: Any): T

    /**
     * Get object fitness
     * @return F value
     */
    fun getFitness(obj: T): F

    /**
     * Return a mutation of a parent object
     * @param Parent element
     * @return type T mutated
     */
    fun mutate (parent: T): T
}

/**
 * @author Joaquin Martinez Rus ©
 * @since 15AGO20
 * version 1.1
 */
interface ICrossOver : IMutable
{
    /**
     * Return a crossover of two objects of same type
     * @param Parent element
     * @return type T crossed over
     */
    fun crossOver(father: T, mother: T): T
}

y en C#

/* ************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         Imutable.cs
    * Descripción:     Interface que implementa un algoritmo genético de mutación
    * Historial:
    *                  1. Joaquin Martínez Rus - 15 ago 2020. Creación
    *
    * Comentarios:
    *
    *
    **************************************************************************************************************************************************/
    public interface IMutable where F : IComparable
    {
        public T Geneset { get; set; }
        public F Target { get; set; }
        public T BestParent { get; set; }
        public F BestFitness { get; set; }

        ///
        /// Return true when target is reached
        /// 

        /// Boolean
        bool IsSuccess();

        ///
        ///  Start algorithm
        ///  Example
        ///  CreateParent
        ///  Mutate
        ///  Getfitness
        ///  Compare
        ///  IsSuccess
        /// 

        void Start();

        ///
        /// Return a new parent object
        /// 

        /// Parameter of generation
        /// Type T
        T CreateParent(object param);

        ///
        /// Get object fitness
        /// 

        /// Object from which the fitness is obtained
        /// F Value
        F GetFitness(T obj);

        ///
        /// Return a mutation of a parent object
        /// 

        /// Parent element
        /// T mutated
        T Mutate(T parent);

    }

    /* ************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         ICrossOver.cs
    * Descripción:     Interface que implementa un algoritmo genético de mutación y cruce
    * Historial:
    *                  1. Joaquin Martínez Rus - 15 ago 2020. Creación
    *
    * Comentarios:
    *
    *
    **************************************************************************************************************************************************/
    public interface ICrossOver : IMutable where F: IComparable
    {
        ///
        /// Return a crossover of two objects of same type
        /// 

        /// Fateher
        /// Mother
        /// type T crossed over
        T CrossOver(T father, T mother);

    }

Analicemos la interface.Lo primero. La interface es una interface genérica con dos tipos, T es el tipo del objeto del algoritmo y F es el tipo de la propiedad Fitness que obligatoriamente debe ser comparable. Este será el cromosoma.
Cuatro propiedades, un geneset o conjunto de genes, el objetivo que pretenderá alcanzar el algoritmo (target), un objeto genérico como mejor individuo de su especie (bestParent) y un indicador de aptitud del mejor de los individuos (bestFitness).
Luego tenemos 5 métodos, método start para iniciar el algoritmo, un método createParent que creará el primero de la especie al cual le he incluido un parámetro por si quisiéramos determinar alguna particularidad sobre él, un método mutate que mutará un objeto en otro, un método getFitness que obtiene la aptitud y por último otro método booleano que determina si el algoritmo ha cumplido su objetivo (isSuccess).La interface ICrossOver hereda de esta añadiéndole un método más llamado crossOver con dos parámetros o padre y madre del objeto resultante.Si ahora creamos una clase que implemente esta interface, nos aseguramos que como mínimo tendremos que desarrollar los elementos de la interface, más fácil imposible. ¿Dónde tenemos que estrujarnos el cerebro? en diseñar el tipo de cromosoma, el objetivo como debe alcanzarse o en como debe mutar. No es poco, pero si tienes poca experiencia con algoritmos genéticos, esta es tu interface.

En la práctica, vamos a generar un algoritmo sencillo que adivine una frase. Esto tan fácil como crear una clase que implemente IMutable y en nuestro IDE nos aparecerá en rojo indicándonos que algo mal. La mayoría de los IDE,s tiene un asistente, una bombilla, una herramienta, un algo que al pulsar sobre él nos indica que algo está pasando y este dirá «implement as constructor parameters», seleccionamos las propiedades y et voilá, propiedades en la clase, pulsamos de nuevo y nos dirá implement members.

genetics01.jpg.png

Al pulsar, seleccionamos todos lo métodos y clase lista. Ahora el código

genetics02.png
Y aquí la clase con su código, esta solo mutará por tanto implementa IMutable, donde el algoritmo intentará adivinar unos preciosos versos de Mario Benedetti «Corazón coraza» con 334 caracteres.
El algoritmo creará una cadena aleatoria inicialmente e irá mutando hasta llegar al objetivo deseado.

class GuessString (override val target: Double, override val geneset: String) : IMutable{
    val guess = "Porque te tengo y no porque te pienso\n" +
            "porque la noche está de ojos abiertos\n" +
            "porque la noche pasa y digo amor\n" +
            "porque has venido a recoger tu imagen\n" +
            "y eres mejor que todas tus imágenes\n" +
            "porque eres linda desde el pie hasta el alma\n" +
            "porque eres buena desde el alma a mí\n" +
            "porque te escondes dulce en el orgullo\n" +
            "pequeña y dulce\n" +
            "corazón coraza"
    override var bestParent: String = createParent(guess.length)
    override var bestFitness: Double = getFitness(bestParent)
    private var attempts = 0

    init {
        start()
    }

    override fun start()
    {
        var childFitness: Double
        var child: String

        do {
            do {
                child = mutate(bestParent)
                childFitness = getFitness(child)
            } while (bestFitness >= childFitness)

            bestFitness = childFitness
            bestParent = child
            attempts ++
        } while (!isSuccess())
        println("Intentos: $attempts")
    }

    override fun isSuccess(): Boolean {
        val value = (bestFitness.toString().toDouble() / guess.length)
        return value >= target
    }

    override fun createParent(param: Any) : String {
        val genes = StringBuilder()
        val length = geneset.length
        (0 until param.toString().toInt()).forEach {
            genes.append(geneset[Random.nextInt(length)])
        }

        return genes.toString()
    }

    override fun getFitness(obj: String): Double = guess.mapIndexed { i, c -> if (c==obj[i]) 1.0 else 0.0}.sum()

    override fun mutate(parent: String): String {
        var index = 0
        val parentFitness: Double = getFitness(parent)
        var childFitness = 0.0

        var newGene: Char
        var alternate: Char
        var definitive: Char
        var indexGeneset: Int
        var child: String

        var length =  geneset.length

        do {
            index = Random.nextInt(parent.length)
            indexGeneset = Random.nextInt( length)

            newGene = geneset[indexGeneset]

            indexGeneset = Random.nextInt( length)
            alternate = geneset[indexGeneset]
            //definitivo
            definitive = if (newGene == parent[index]) alternate else newGene

            child = parent.replaceRange(index,index+1, definitive.toString())

            childFitness = getFitness(child)

        } while (parentFitness >= childFitness)

        return child
    }
}

fun main() {
val guess =GuessString(
        1.0,
        " áéíóúabcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,\n")
println(guess.bestParent)
}

Y el resultado

Intentos: 328
Porque te tengo y no porque te pienso
porque la noche está de ojos abiertos
porque la noche pasa y digo amor
porque has venido a recoger tu imagen
y eres mejor que todas tus imágenes
porque eres linda desde el pie hasta el alma
porque eres buena desde el alma a mí
porque te escondes dulce en el orgullo
pequeña y dulce
corazón coraza

Pues aquí tenéis mi interface para algoritmos genéticos.
En el próximo post, veremos un algoritmo genético que posicionará las piezas de ajedrez en su sitio.
Pd: En realidad, la clase de adivinar no es gran cosa, porque se podría haber conseguido por iteración, pero entonces no habriáis aprendido el algortimo genético. Entonces, espero que os haya servido. 😉
Podía haber elegido a Antonio Machado a Calderón de la Barca o a cualquier otro poeta o poema, pero, este me parece especialmente bello. Leedlo completo, es corto, tres estrofas.
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Interfaces

Interfaces

Cuando se empieza a programar, el uso de interfaces es un poco abstracto ya que no se le ve utilidad, pero las interfaces son de los más útiles. ¿Qué es una interface? es un contrato por el que una clase se ve obligada a cumplir en todos sus términos. Es decir, la interface contiene métodos y propiedades y cuando una clase implementa esta interface, la clase debe tener absolutamente todos los métodos y todas las propiedades que la interface le ha dicho.

Un objeto en la mayoría de los lenguajes, solo puede heredar de una clase, pero si puede implementar varias interfaces.

Un ejemplo. Quiero crear una colección de figuras de ajedrez; si quisiera ordenar la colección por valor y color en el que las negras valiesen más, al usar el método sort(), orderby() o el que sea, el objeto como mínimo deberá contener algún método que use ese método para ordenar sus elementos, compararlos y decidir cual va primero y cual después, ¿no?, pues yo lo que haría sería por ejemplo en Kotlin, es que la clase FiguraAjedrez implemente la interface Comparable (lo normal es que las interfaces, dependen del lenguaje comiencen por I, pero todas acaben con -able) que a su vez contiene un método compareTo.

Pues si la FiguraAjedrez tiene ese método, la colección cuando use el método sort encontrará el método compareTo donde nosotros escribiremos nuestro código, comparamos por el valor de la figura y le añadimos un extra por el color.

También, cuando pasamos como argumento una interface, nos estamos asegurando que el objeto que se pasa cumple con las expectativas. En C# si pasamos como argumento en un método un objeto del tipo IEnumerable, no estamos asegurando que el objeto que se pasa, tiene como mínimo un enumerador y que pude moverse por los elementos de la colección. O si le pasamos como argumento la interface IList, nos estamos asegurando que esta interface está heredando de ICollection, IEnumerable<T> e IEnumerable, de modo que puede moverse por sus elementos, puede borrar la colección, añadir, eliminar objetos, saber si tiene un objeto en la colección y hacer copias, todo esto. En Kotlin pasa algo parecido con la interface MutableList que hereda de las interfaces List y MutableCollection para hacer estas mismas acciones y algunas más.

        private static void Foo(IList collection)
        {
            // Do something
        }
         fun  foo(collection: MutableList){
            // Do something
         }

A continuación vamos ver un ejemplo de interface y de una clase que la implemente

interface IChessPiece: Comparable{
    fun doSomething()
    fun move()
    val isBlack: Boolean
    val value: Int
    val piece: String
}
class ChessPiece(override val piece: String, override val isBlack: Boolean, override val value: Int) : IChessPiece {
    override fun doSomething() {
        TODO("Not yet implemented")
    }

    override fun move() {
        TODO("Not yet implemented")
    }

    override fun compareTo(other: ChessPiece): Int {
        // Aqui incluimos el código de comparación
    }

}

fun foo(chessPiece: IChessPiece){

}

En el ejemplo, vemos que la interface IChessPiece implementa IComparable, así que podremos comparar objetos con otros del mismo tipo y luego le añadimos algunas propiedades y métodos, así que la clase ChessPiece obligatoriamente, debe tener cada uno de los métodos y propiedades establecidos en la interface.
En el método foo pasamos como argumento un objeto que implemente la interface, ASEGURANDO que va a hacer y va a tener lo que queremos que haga y que tenga. si mañana cambiamos el código de la clase o creamos una nueva con más funciones, lo que nos importa para que se entienda con el resto del código es que cumpla como mínimo con lo esperado.Usa las interfaces, sobre todo en los modelos y viewmodel, más tarde te alegraras enormemente.
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Sistema D’Hont con C#

Sistema D’Hont con C#

Semáforo II

Semáforo II
En esta entrega vamos a crear el semáforo. Aunque no lo parezca, pero un semáforo a pesar de su simplicidad visual, tiene aspectos bastante complejos y sobre todo cuando tienen que estar sincronizados o comunicados con otros, existen muchas matemáticas detrás de los modelos de tráfico de las grandes ciudades.

Sin darle más complejidad que la que necesitamos para nuestro proyecto final, que es un sistema de control de semáforos en una avenida para poder cruzarla de una sola vez sin pararnos, le asignaremos las siguientes características:

  • Tiempo en verde
  • Tiempo en amarillo
  • Tiempos en rojo
  • Tiempo de retardo para sincronziación de semáforos
  • Estado en el que se encuentra
  • Función de funcionamiento en manual o automático
  • Función de inicio automático
  • Función de parpadeo

En el diseño XAML, creamos unos objetos rectangle y le incluimos los controles de usuario creados en el post Semáforo I. El cambio de color lo podiamos haber hecho con converter, con propiedades, pero esta vez he optado por hacerlo con estilos y DataTrigger. A cada objeto LEDLight (luz del semáforo) le asigno un estilo genérico con algún efecto de fundido para que parezca más real; luego este estilo es heredado por otros tres estilos, uno por cada color donde los DataTrigger hacen su trabajo comprobando el estado del semáforo y activando la propiedad LightIsEnabled a Truesi cumple con la condición del DataTrigger. (Código al final del post)

Luego en el código de clase, le añado un DispatcherTime que nos hará las funciones de temporizador, creamos unas cuantas propiedades de dependencia para cumplir con nuestras características.
Tiene un método privado que será llamado desde el temporizador y este asignará el estado al semáforo y como consecuencia activando el color correspondiente.

        void changingState()
        {
            // Retardo inicial
            if (DelayTime > 0)
            {
                timer.Interval = new TimeSpan(0, 0, (int)DelayTime);
                DelayTime = 0;
                return;
            }

            // Parpadeando
            if (IsFlashingAmberLight)
            {
                if (State.Equals(LEDTrafficLightState.Yellow))
                {
                    State = LEDTrafficLightState.None;
                    timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
                }
                else
                {
                    State = LEDTrafficLightState.Yellow;
                    timer.Interval = new TimeSpan(0, 0, 0, 1);
                }

                return;
            }

            // Cambio de color
            switch (State)
            {
                case LEDTrafficLightState.Red:
                    // SEMÁFORO EN VERDE
                    State = LEDTrafficLightState.Green;
                    
                    timer.Interval = new TimeSpan(0, 0, GreenTime);
                    break;
                case LEDTrafficLightState.Yellow:
                    // SEMÁFORO EN VERDE
                    State = LEDTrafficLightState.Red;
                    timer.Interval = new TimeSpan(0, 0, RedTime);
                    break;
                case LEDTrafficLightState.Green:
                    // SEMÁFORO EN AMBAR
                    State = LEDTrafficLightState.Yellow;
                    timer.Interval = new TimeSpan(0, 0, YellowTime);
                    break;
                default:
                    break;
            }
        }

y este el resultado instanciando varios semáforos en una ventana

            <controls:LEDTrafficLight x:Name="LEDTL1" Width="100" Height="300" GreenTime="4" RedTime="4" DelayTime="1" Margin="10"/>
            <controls:LEDTrafficLight x:Name="LEDTL2" Width="100" Height="300" GreenTime="5" RedTime="4" DelayTime="2" Margin="10"/>
            <controls:LEDTrafficLight x:Name="LEDTL3" Width="100" Height="300" GreenTime="5" RedTime="5" DelayTime="3" Margin="10"/>
            <controls:LEDTrafficLight x:Name="LEDTL4" Width="100" Height="300" GreenTime="5" RedTime="5" IsFlashingAmberLight="True" Margin="10"/>  

Video7
La próxima entrega, el sistema de control de semáforos

<UserControl x:Class="Controls.LEDTrafficLight"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:controls="clr-namespace:Controls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="100">
    <Grid x:Name="grid">
        <Grid.Resources>
            <Style x:Key="LightStyle" TargetType="controls:LEDLight">
                <Setter Property="Margin" Value="5"/>
                <Style.Triggers>
                    <Trigger Property="LightIsEnabled" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                  Storyboard.TargetProperty="Opacity"
                  From="0" To="1" Duration="0:0:0.2" />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                  Storyboard.TargetProperty="Opacity"
                  From="0" To="1" Duration="0:0:0.1" />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="RedLightStyle" TargetType="controls:LEDLight" BasedOn="{StaticResource LightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:LEDTrafficLight},Path=State }" Value="{x:Static controls:LEDTrafficLight+LEDTrafficLightState.Red}">
                        <Setter Property="LightIsEnabled" Value="True"/>
                    </DataTrigger>

                </Style.Triggers>
            </Style>
            <Style x:Key="YellowLightStyle" TargetType="controls:LEDLight" BasedOn="{StaticResource LightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:LEDTrafficLight},Path=State }" Value="{x:Static controls:LEDTrafficLight+LEDTrafficLightState.Yellow}">
                        <Setter Property="LightIsEnabled" Value="True"/>
                    </DataTrigger>

                </Style.Triggers>
            </Style>
            <Style x:Key="GreenLightStyle" TargetType="controls:LEDLight" BasedOn="{StaticResource LightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:LEDTrafficLight},Path=State }" Value="{x:Static controls:LEDTrafficLight+LEDTrafficLightState.Green}">
                        <Setter Property="LightIsEnabled" Value="True"/>
                    </DataTrigger>

                </Style.Triggers>
            </Style>
            <Style x:Key="rectangleTraficLight" TargetType="Border">
                <Setter Property="Width" Value="{Binding ElementName=redEllipse, Path=ActualWidth}"/>
                <Setter Property="Height" Value="5"/>
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Margin" Value="1"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
                <Setter Property="CornerRadius" Value="3"/>
            </Style>
            <Style x:Key="borderColor" TargetType="Border">
                <Setter Property="BorderBrush" Value="Gray"/>
                <Setter Property="BorderThickness" Value="2"/>
                <Setter Property="Margin" Value="2,0,2,2"/>
                <Setter Property="CornerRadius" Value="3"/>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
        </Grid.RowDefinitions>
        <Border Grid.RowSpan="3" BorderBrush="DarkGreen" BorderThickness="5" Background="DarkGreen" Opacity=".5" CornerRadius="5"/>
        <Border Style="{StaticResource borderColor}" Grid.Row="0">
            <controls:LEDLight x:Name="RedLight" LEDLightBackgroundON="Red" Style="{StaticResource RedLightStyle}"/>
        </Border>
        <Border Style="{StaticResource borderColor}" Grid.Row="1">
            <controls:LEDLight x:Name="YellowLight"  LEDLightBackgroundON="Gold" Style="{StaticResource YellowLightStyle}"/>
        </Border>
        <Border Style="{StaticResource borderColor}" Grid.Row="2">
            <controls:LEDLight x:Name="GreenLight" Style="{StaticResource GreenLightStyle}"/>
        </Border>
    </Grid>
</UserControl>
namespace Controls
{
    /// <summary>
    /// Lógica de interacción para LEDTrafficLight.xaml
    /// </summary>
    public partial class LEDTrafficLight : UserControl
    {
        #region Constructor

        public LEDTrafficLight()
        {
            InitializeComponent();
            this.DataContext = this;
            timer.Tick += Timer_Tick;
            timer.IsEnabled = StartAuto;
        }

        #endregion

        #region Enum

        public enum LEDTrafficLightState
        {
            Red,
            Yellow,
            Green,
            None
        }

        #endregion

        #region DependencyProperties

        public int GreenTime
        {
            get { return (int)GetValue(GreenTimeProperty); }
            set
            {
                value = value > YellowTime ? value - YellowTime : YellowTime + 1;
                SetValue(GreenTimeProperty, value);
            }
        }

        public int RedTime
        {
            get { return (int)GetValue(RedTimeProperty); }
            set
            {
                if (value <= 0) value = 1;
                SetValue(RedTimeProperty, value);
            }
        }

        public int YellowTime
        {
            get { return (int)GetValue(YellowTimeProperty); }
            set { SetValue(YellowTimeProperty, value); }
        }

        public int DelayTime
        {
            get { return (int)GetValue(TimeProperty); }
            set { SetValue(TimeProperty, value); }
        }

        public bool IsFlashingAmberLight
        {
            get { return (bool)GetValue(IsFlickingProperty); }
            set
            {
                SetValue(IsFlickingProperty, value);
                State = LEDTrafficLightState.Yellow;
                // en 100 ms cambia a Parpadeo
                timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
            }
        }

        public bool IsManual
        {
            get { return (bool)GetValue(IsManualProperty); }
            set
            {
                SetValue(IsManualProperty, value);
                timer.IsEnabled = !value;
            }
        }

        public bool StartAuto
        {
            get { return (bool)GetValue(StarAutoProperty); }
            set
            {
                SetValue(StarAutoProperty, value);
                timer.IsEnabled = value;
            }
        }

        public LEDTrafficLightState State
        {
            get { return (LEDTrafficLightState)GetValue(StateProperty); }
            set { SetValue(StateProperty, value); }
        }

        #region DependecyProperties Register

        // Using a DependencyProperty as the backing store for StarAuto.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StarAutoProperty =
            DependencyProperty.Register("StartAuto", typeof(bool), typeof(LEDTrafficLight), new PropertyMetadata(true));

        // Using a DependencyProperty as the backing store for IsManual.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsManualProperty =
            DependencyProperty.Register("IsManual", typeof(bool), typeof(LEDTrafficLight), new PropertyMetadata(false));

        // Using a DependencyProperty as the backing store for IsFlicking.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsFlickingProperty =
            DependencyProperty.Register("IsFlashingAmberLight", typeof(bool), typeof(LEDTrafficLight), new PropertyMetadata(false));

        // Using a DependencyProperty as the backing store for State.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StateProperty =
            DependencyProperty.Register("State", typeof(LEDTrafficLightState), typeof(LEDTrafficLight), new PropertyMetadata(LEDTrafficLightState.Red));

        // Using a DependencyProperty as the backing store for Time.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TimeProperty =
            DependencyProperty.Register("DelayTime", typeof(int), typeof(LEDTrafficLight), new PropertyMetadata(0));

        // Using a DependencyProperty as the backing store for TimeYellow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YellowTimeProperty =
            DependencyProperty.Register("YellowTime", typeof(int), typeof(LEDTrafficLight), new PropertyMetadata(2));

        // Using a DependencyProperty as the backing store for TimeRed.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RedTimeProperty =
            DependencyProperty.Register("RedTime", typeof(int), typeof(LEDTrafficLight), new PropertyMetadata(7));

        // Using a DependencyProperty as the backing store for TimeGreen.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GreenTimeProperty =
            DependencyProperty.Register("GreenTime", typeof(int), typeof(LEDTrafficLight), new PropertyMetadata(7));

        #endregion

        #endregion

        #region Fields & Const & Event

        DispatcherTimer timer = new DispatcherTimer();

        #endregion


        #region Publics Method

        /// <summary>
        /// Inicia el semáforo cuando se encuentra en modo automático
        /// </summary>
        public void Start()
        {
            if (IsManual) return;
            timer.Start();
        }

        /// <summary>
        /// Detiene el semáforo
        /// </summary>
        public void Stop()
        {
            timer.Stop();
        }

        /// <summary>
        /// Cambia el semáforo a rojo
        /// </summary>
        public void OnRed()
        {
            State = LEDTrafficLightState.Red;
        }

        /// <summary>
        /// Cambia el semáforo a verde
        /// </summary>
        public void OnGreen()
        {
            State = LEDTrafficLightState.Green;
        }

        /// <summary>
        /// Cambia el semáforo a amarillo
        /// </summary>
        public void OnYellow()
        {
            State = LEDTrafficLightState.Yellow;
        }

        public void Test()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Privates methods

        /// <summary>
        /// Cambia el estado del semáforo según el estado anterior
        /// </summary>
        void changingState()
        {
            // Retardo inicial
            if (DelayTime > 0)
            {
                timer.Interval = new TimeSpan(0, 0, (int)DelayTime);
                DelayTime = 0;
                return;
            }

            // Parpadeando
            if (IsFlashingAmberLight)
            {
                if (State.Equals(LEDTrafficLightState.Yellow))
                {
                    State = LEDTrafficLightState.None;
                    timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
                }
                else
                {
                    State = LEDTrafficLightState.Yellow;
                    timer.Interval = new TimeSpan(0, 0, 0, 1);
                }

                return;
            }

            // Cambio de color
            switch (State)
            {
                case LEDTrafficLightState.Red:
                    // SEMÁFORO EN VERDE
                    State = LEDTrafficLightState.Green;
                    
                    timer.Interval = new TimeSpan(0, 0, GreenTime);
                    break;
                case LEDTrafficLightState.Yellow:
                    // SEMÁFORO EN VERDE
                    State = LEDTrafficLightState.Red;
                    timer.Interval = new TimeSpan(0, 0, RedTime);
                    break;
                case LEDTrafficLightState.Green:
                    // SEMÁFORO EN AMBAR
                    State = LEDTrafficLightState.Yellow;
                    timer.Interval = new TimeSpan(0, 0, YellowTime);
                    break;
                default:
                    break;
            }

        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            changingState();
        }

        #endregion
    }
}

Hilando

Hilando

Desde .NET 4, los hilos en C# se convirtieron en una tarea de lo más fácil. En este post vamos a realizar una par de muestras, una prueba sencilla donde vamos a ejecutar una tarea que usa mucho tiempo en terminarse como es la obtención de π(x) o la cantidad de números primos menores que un número.Vamos a usar una función lambda para obtener el codiciado π(x) y para ello vamos a usar la clase Enumerable del espacio System.Linq y un método llamado Range para obtener un conjunto de números enteros entre dos rangos numerable.Range(2, max), contamos los elementos con el predicado con el que obtengamos todos los números entre el rango de 2 y la raiz del número Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1) que cumplan la condición de tener un módulo mayor que 0 All(i => n % i > 0))o lo que es lo mismo todos los números que no son múltiplos.

Enumerable.Range(2, max).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0))

Linq es bestial, ¿no?
Si le damos un valor alto a la variable max com por ejemplo 10.000.000, la tarea dejará la interfaz bloqueada y por tanto tendremos que crear un hilo para evitar este problema y aquí viene lo bueno de la clase Task.

Esta clase tiene un método Factory.StartNew al que se le pasa un método como delegado, el cual se ejecutará de forma asincrónica devolviendo la tarea iniciada, es decir no devuelve un valor sino la tarea Task en si con sus propiedades y métodos.

Task.Factory.StartNew(() => TareaMuyCostosa());
En nuestro código vamos a ver solo dos aspectos de los muchos de los que podemos extraerle a Task, uno es la propiedad IsCompleted y otra sería el método Wait.
Nuestra aplicación como he dicho, generará números primos en una tarea y mientras que no esté finalizada, mostrará un mensaje indicando el tiempo empleado y una vez que finalice, mostrará el resultado que lo mostraremos de dos modos, uno esperando a que finalice y otro con el método ContinueWith.

La primera

static void primeNumbersCount(int max)
        {
            Stopwatch stw = new Stopwatch();
            stw.Start();
            int sec = 0;
            var piXTask = Task.Factory.StartNew(() => Enumerable.Range(2, max).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));

            var calculando = "Calculando ";
            while (!piXTask.IsCompleted || piXTask.IsFaulted || piXTask.IsCanceled)
            {
                Thread.Sleep(1000);
                Console.Clear();
                Console.WriteLine(calculando.PadRight(sec % 5 + 11,'.'));
                Console.WriteLine(string.Format("Tiempo empleado: {0} sengundos", sec++));
            }

            piXTask.Wait();

            string text = string.Format("Calculo de {0} números primos menores de {1}", piXTask.Result, max);
            Console.WriteLine(text);
            Console.WriteLine(string.Format("Tiempo empleado: {0}", stw.Elapsed));
            Console.Read();
        }

En este código, vemos que se lanza la tarea, luego pasamos a un bucle del que debemos asegurarnos que saldremos algún día (esta opción no la aconsejo, pero para mostrar que la app se queda en sus cosas mientras la tarea se está realizando, está bien), mediante la propiedad IsCompleted, IsFaulted o IsCanceled, es decir cuando pase alguna de estas cosas, sale del bucle.
Luego pasamos al método Wait, que lo que hace es lo mismo que el bucle, hasta que la tarea no haya finalizado, espera y no sobrepasa a la siguiente línea de código. Una vez acabado, muestra el resultado con la propiedad Result del tipo int, porque es el resultado que entrega el delegado que lanzó. Y el resultadotask03task01

Pero para mi, en este caso usaría lo mismo pero con el método ContinueWith.

static void primeNumbersCount(int max)
        {
            Stopwatch stw = new Stopwatch();
            stw.Start();
            int sec = 0;
            var piXTask = Task.Factory.StartNew(() => Enumerable.Range(2, max).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
            var calculando = "calculando ";
            piXTask.ContinueWith((p) =>
            {
                string text = string.Format("Calculo de {0} números primos menores de {1}", piXTask.Result, max);
                Console.WriteLine(text); Console.WriteLine(string.Format("Tiempo empleado: {0}", stw.Elapsed));
            });
            Console.WriteLine("Esto no ha terminado...");
            Thread.Sleep(1000); sec++;
            while (!piXTask.IsCompleted)
            {
                Thread.Sleep(1000); Console.Clear();
                Console.WriteLine(calculando.PadRight(sec % 5 + 11, '.'));
                Console.WriteLine(string.Format("Tiempo empleado: {0} segundos", sec++));
            }
          }

Aquí podemos apreciar que se lanza la tarea, vemos el método ContinueWith que contiene código en su interior mediante otro delegado y posteriormente el código ese que hemos creado para mostrar cosas mientras la tarea se realiza. Al ejecutarlo, se lanza la tarea y se obvia el código del método ContinueWith en cuestión, continua y pasa al bucle, una vez que ha terminado la tarea, continua con lo que le queda dentro del bloque ContinueWith y se acabó, ¿fácil? facilísimo!!

Video4
Ya veremos en otra ocasión el uso de Arrays de Task, esperas, sincronías entre ellos y alguna otra cosa más.

Un poco de Linq

Un poco de Linq

LINQ en inglés es Language Integrated Query o lenguaje de consultas integrado. Lleva en la brecha desde 2007 con la versión 3.5 de .NET, por tanto no estoy descubriendo nada y para el que no lo conozca, con este post podrá introducirse e implementar sus posibilidades.

LINQ es un lenguaje parecido a SQL, es decir mediante una gramática concreta aplicada sobre un conjunto de datos, obtenemos un resultado que puede ser valores o un conjunto de resultados. Uno de los aspectos fundamentales de este lenguaje es que puede ser usado con cualquier colección de datos, ya sea un array, una lista de objetos, una cadena de texto (es un array), una colección, una clase enumerable, una base de datos, un documento XML, etc.

Primer ejemplo, vamos a enumerar los objetos tipo char de de una cadena de texto ya que un tipo string es lo mismo que array de objetos char; si la cadena de texto es «Wakicode» podríamos obtener los char del siguiente modo:

string cadena = "Wakicode";
var query = from u in cadena
select u;
// el resultado de query es un array de objetos char
// query = {'W', 'a', 'k', 'i', 'c', 'o', 'd', 'e'}

Vamos a repasar la gramática de esta consulta de LINQ. Comienza por from, asignamos la variable usada en la consulta, en este caso u, le decimos mediante in, donde vamos a efectuar la consulta y con select, la salida de la consulta que en este caso es la variable o lo que es lo mismo la variable u que es cada uno de los objetos de la cadena. Si le aplicamos una sentencia condicional, por ejemplo queremos obtener todas las vocales de nuestra cadena y para ello he creado una función que determine si un caracter es vocal y ahora agregamos el predicado where en la sentencia LINQ.

string cadena = "Wakicode";
var query = from u in cadena
where esVocal(u)
            select u;
bool esVocal(char c)
{
return "aeiouAEIOU".Contains(c);
}
// el resultado de query es un array de objetos char
// query = {'a','i','o','e'}

Vamos a crear una lista de enteros desde el valor 0 hasta el 100 y luego ejecutaremos consultas básicas sobre la colección. De momento vamos a obtener los múltiplos de 7.

List list = new List();
for (int i = 0; i < 100; i++) {
list.Add(i);
}
var query = from u in list
where u % 7 == 0
select u;
// query = {0,7,14,21,28,35,...91,98}

Por último, vamos a complicar la cosa efectuando consultas sobre objetos complejos y para ello creamos una clase persona con alguna propiedad, creamos una colección de esta clase y le agregamos algún objeto.

public class Persona
{
public string Name { get; set; }
public string City { get; set; }
public int Age { get; set; }
}

public class Main
{
public Main()
{
List people = new List();
// añadimos unos objetos

people.Add(new Persona() { Name = "Donald Trump", City = "Washington", Age = 56 });
people.Add(new Persona() { Name = "Tiriti Trump", City = "New York", Age = 45 });
people.Add(new Persona() { Name = "Michael Knight", City = "Washington", Age = 35 });
people.Add(new Persona() { Name = "Paul Churches", City = "Teheran", Age = 34 });
people.Add(new Persona() { Name = "John Charles Purse", City = "Valencia", Age = 25 });

var query = from u in people
where u.Name.Contains("Trump")
select u.Name;
// query = Donald Trump, Tiriti Trump

var query1 = from u in people
where u.City.Contains("Washington")
select u.Name;
// query1 = Donald Trump, Michael Knight

var query2 = from u in people
where u.Age < 40
select u.Name;
// query2 = Michael Knight, Paul Churches, John Charles Purse
}
}

Podemos apreciar que a la variable u le corresponde el valor de cada uno de los objetos de la lista en cada iteración, les aplica el filtro y se agregan a la variable si cumplen con la condición, pero se agregan según la clausula select. En el caso del ejemplo, seleccionamos la propiedad del tipo string Name, pero si hubieramos dejado select u, estariamos creando una consulta con objetos del tipo Persona pudiendo posteriormente usar alguna de las propiedades del objeto.

var query2 = from u in people
                         where u.Age < 40
                         select u;
            foreach (var item in query2)
            {
                Console.WriteLine(string.Format("Nombre: {0}, Edad: {1}", item.Name, item.Age));
            }
//Nombre: Michael Knight, Edad: 35
//Nombre: Paul Churches, Edad: 34
//Nombre: John Charles Purse, Edad: 25

Como ya comentamos al inicio, podemos usar Linq con cualquier colección y su uso con bases de datos es fantástico, de hecho existe una herramienta LinqToSql que genera las clases y propiedades (tablas y campos) de una base de datos automáticamente, de modo que podemos acceder a los datos de las tablas y sus relaciones de un modo rápido y eficaz.
Pd: Para el que quiera avanzar, puede hacerlo con el siguiente libro.

Controles de Usuario en WPF 2

Controles de Usuario en WPF 2
Continuando con los controles de usuario en WPF, voy a mostrarles un control un poco más complejo y en este caso se trata de un reloj un poco especial, se trata de un reloj binario.
Se trata de un reloj, pero los dígitos se muestran uno a uno en modo binario mediante una bola de indicador. Por ejemplo para indicar la hora 15, se muestra un 1 en binario 001 y un 5 en binario 101.He creado un control básico que hará las veces de indicador con un tono grisáceo cuando el indicador está apagado o es un cero y un tono verdoso para indicar un 1 o cuando está encendido.

indicadores

Y ahora muestro el código de la bolita

<UserControl x:Class="Controls.EllipseUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:Controls="clr-namespace:Controls"
             mc:Ignorable="d"
             d:DesignHeight="48" d:DesignWidth="48" x:Name="ellipseUserControl">
    <Grid x:Name="gridEllipse" Height="{Binding ElementName=ellipseUserControl,Path=Height}"
          Width="{Binding ElementName=ellipseUserControl,Path=Width}">
        <Grid.Resources>
            <Style x:Key="ellipseStyle" TargetType="Ellipse">
                <Setter Property="VerticalAlignment" Value="Stretch"/>
                <Setter Property="HorizontalAlignment" Value="Stretch"/>
                <Setter Property="Margin" Value="2"/>
                <Setter Property="Fill">
                    <Setter.Value>
                        <RadialGradientBrush GradientOrigin="0.6,0.2"
                    Center="0.6,0.2"
                    RadiusX="0.4" RadiusY="0.4">
                            <RadialGradientBrush.GradientStops>
                                <GradientStop Color="White" Offset="0" />
                                <GradientStop Color="{Binding ElementName=gridEllipse, Path=Parent.ActiveColor}" Offset="1.5" />
                            </RadialGradientBrush.GradientStops>
                        </RadialGradientBrush>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <Ellipse x:Name="ellipse" Style="{StaticResource ellipseStyle}"/>
    </Grid>
</UserControl>

Podemos apreciar que el control básico solo tiene un Grid y dentro de este una ellipse, la ellipse tiene un estilo declarado en Grid.Resources y el cual tiene un degradado radial y desde una de sus propiedades GradientStop enlazamos con una propiedad DependecyProperty ActiveColor, de modo que podamos convertir valores booleanos en colores y se la asignemos a esta propiedad y por tanto esta propiedad cambiará el color de GradientStop. Esta propiedad la declaramos en la clase del control de usuario del siguiente modo:


public Color ActiveColor
{
get { return (Color)GetValue(ActiveColorProperty); }
set { SetValue(ActiveColorProperty, value); }
}

// Using a DependencyProperty as the backing store for IsActiveColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ActiveColorProperty =
DependencyProperty.Register("ActiveColor", typeof(Color), typeof(EllipseUserControl), new PropertyMetadata(Brushes.Red.Color));

Ahora vamos al trabajo duro, que es crear un control de usuario más complejo, basado en unos cuantos controles básicos. Para las horas usaremos para:

  • Horas. Primer dígito 2, o vale 0, 1 o 2 (00, 01 o 11). Segundo dígito 4 indicadores, desde 0 a 9 y el 9 es 1001 en binario.
  • Minutos. Primer dígito. Valor máximo es 5, por tanto 3 indicadores (101), segundo dígito valor máximo 9, cuatro indicadores (1001)
  • Segundos. Igual que los minutos.

Ahora que tenemos el diseño del reloj, lo generamos en XAML

<UserControl x:Class="Controls.BinaryClock"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:Controls="clr-namespace:Controls"
             mc:Ignorable="d"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             d:DesignHeight="155" d:DesignWidth="180" >
    <UserControl.Resources>
        <Controls:BooleanToBrushes x:Key="btb"/>
    </UserControl.Resources>
    <Grid x:Name="grid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="30"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
        </Grid.RowDefinitions>
        <!-- HORAS -->
        <TextBlock Text="H" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="20"/>
        <Border BorderThickness="1" BorderBrush="LightCoral" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="4" Margin="1"/>

        <Controls:EllipseUserControl x:Name="hour11" Grid.Column="0" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.H10, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="hour12" Grid.Column="0" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.H11, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="hour21" Grid.Column="1" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.H20, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="hour22" Grid.Column="1" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.H21, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="hour24" Grid.Column="1" Grid.Row="2" ActiveColor="{Binding ElementName=grid, Path=Parent.H22, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="hour28" Grid.Column="1" Grid.Row="1" ActiveColor="{Binding ElementName=grid, Path=Parent.H23, Converter={StaticResource btb}}"/>

        <!-- MINUTOS -->
        <TextBlock Text="M" Grid.Column="2" Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="20"/>
        <Border BorderThickness="1" BorderBrush="LightBlue" Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="4" Margin="1"/>

        <Controls:EllipseUserControl x:Name="minute11" Grid.Column="2" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.M10, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute12" Grid.Column="2" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.M11, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute14" Grid.Column="2" Grid.Row="2" ActiveColor="{Binding ElementName=grid, Path=Parent.M12, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute21" Grid.Column="3" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.M20, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute22" Grid.Column="3" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.M21, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute24" Grid.Column="3" Grid.Row="2" ActiveColor="{Binding ElementName=grid, Path=Parent.M22, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="minute28" Grid.Column="3" Grid.Row="1" ActiveColor="{Binding ElementName=grid, Path=Parent.M23, Converter={StaticResource btb}}"/>

        <!-- SEGUNDOS -->
        <TextBlock Text="S" Grid.Column="4" Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="20"/>
        <Border BorderThickness="1" BorderBrush="LightGreen" Grid.Column="4" Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="4" Margin="1"/>

        <Controls:EllipseUserControl x:Name="second11" Grid.Column="4" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.S10, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second12" Grid.Column="4" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.S11, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second14" Grid.Column="4" Grid.Row="2" ActiveColor="{Binding ElementName=grid, Path=Parent.S12, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second21" Grid.Column="5" Grid.Row="4" ActiveColor="{Binding ElementName=grid, Path=Parent.S20, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second22" Grid.Column="5" Grid.Row="3" ActiveColor="{Binding ElementName=grid, Path=Parent.S21, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second24" Grid.Column="5" Grid.Row="2" ActiveColor="{Binding ElementName=grid, Path=Parent.S22, Converter={StaticResource btb}}"/>
        <Controls:EllipseUserControl x:Name="second28" Grid.Column="5" Grid.Row="1" ActiveColor="{Binding ElementName=grid, Path=Parent.S23, Converter={StaticResource btb}}"/>

        <TextBlock Text="{Binding ElementName=grid, Path=Parent.Hour}" Grid.Column="0" Grid.Row="5" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="22"/>
        <TextBlock Text="{Binding ElementName=grid, Path=Parent.Minutes}" Grid.Column="2" Grid.Row="5" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="22"/>
        <TextBlock Text="{Binding ElementName=grid, Path=Parent.Seconds}" Grid.Column="4" Grid.Row="5" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontSize="22"/>
    </Grid>
</UserControl>

como podéis apreciar, he distribuido los controles para dar forma al reloj quedando su diseño así
bin01
Cada indicador usa una clase converter para convertir el valor booleano en un color y con esto finaliza el código XAML.

public class BooleanToBrushes : IValueConverter
    {
        #region Constructor

        #endregion

        #region Propiedades

        #endregion

        #region IValueConverter

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bValue = (bool)value;
            if (bValue)
            {
                return Brushes.Green.Color;
            }
            else
            {
                return Brushes.Gray.Color;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }

        #endregion
    }

Vamos al código. Hay una propiedad booleana por cada uno de los indicadores. Un DispatcherTime para calcular los valores en cada segundo y un par de métodos para convertir la hora a binario y pasarla a cada uno de los indicadores mediante las propiedades. Paso el código.

    public partial class BinaryClock : UserControl,INotifyPropertyChanged
    {
        public BinaryClock()
        {
            InitializeComponent();

            dispatcher.Tick += Dispatcher_Tick; ;
            dispatcher.Interval = TimeSpan.FromSeconds(1);
            dispatcher.Start();
        }

        #region Privates Method

        List setDecimalToBinary(int value, bool isHour)
        {
            List values = new List();
            string valueToString = value.ToString("00");
            string digit1 = valueToString.Substring(0, 1);
            string digit2 = valueToString.Substring(1, 1);
            string binaryDigit1 = convertToBinary(Convert.ToInt16(digit1)).PadLeft(2, '0');
            if (!isHour)
            {
                binaryDigit1 = binaryDigit1.PadLeft(3, '0');
            }
            string binaryDigit2 = convertToBinary(Convert.ToInt16(digit2)).PadLeft(4, '0');
            foreach (var item in binaryDigit1 + binaryDigit2)
            {
                values.Add(item.Equals('0') ? false : true);
            }
            return values;
        }

        string convertToBinary(int value)
        {
            return Convert.ToString(value, 2);
        }

        List setDecimalToBinary(int value)
        {
            return setDecimalToBinary(value, false);
        }

        private void Dispatcher_Tick(object sender, EventArgs e)
        {
            DateTime horaActual = DateTime.Now;

            Hour = horaActual.Hour.ToString();
            Minutes = horaActual.Minute.ToString();
            Seconds = horaActual.Second.ToString();

            var hora = setDecimalToBinary(horaActual.Hour, true);
            H10 = hora[1];
            H11 = hora[0];

            H20 = hora[5];
            H21 = hora[4];
            H22 = hora[3];
            H23 = hora[2];

            var minutos = setDecimalToBinary(horaActual.Minute);
            M10 = minutos[2];
            M11 = minutos[1];
            M12 = minutos[0];

            M20 = minutos[6];
            M21 = minutos[5];
            M22 = minutos[4];
            M23 = minutos[3];

            var segundos = setDecimalToBinary(horaActual.Second);
            S10 = segundos[2];
            S11 = segundos[1];
            S12 = segundos[0];

            S20 = segundos[6];
            S21 = segundos[5];
            S22 = segundos[4];
            S23 = segundos[3];

        }

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;

        #region Public Methods

        ///
<summary>
        /// Inicia el evento de cambio de propiedad
        /// </summary>

        /// Nombre de la propiedad
        public void OnPropertyChanged(string p_PropertyName)
        {

            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(p_PropertyName));
            }
        }

        #endregion

        #region Properties &amp; fields

        private bool h10;
        private bool h11;
        private bool h20;
        private bool h21;
        private bool h22;
        private bool h23;
        private bool m10;
        private bool m11;
        private bool m12;
        private bool m20;
        private bool m21;
        private bool m22;
        private bool m23;
        private bool s10;
        private bool s11;
        private bool s12;
        private bool s20;
        private bool s21;
        private bool s22;
        private bool s23;
        DispatcherTimer dispatcher = new DispatcherTimer();

        private string hour;
        private string minute;
        private string seconds;

        public string Hour
        {
            get { return hour; }
            set
            {
                hour = value;
                OnPropertyChanged("Hour");
            }
        }

        public string Minutes
        {
            get { return minute; }
            set
            {
                minute = value;
                OnPropertyChanged("Minutes");
            }
        }

        public string Seconds
        {
            get { return seconds; }
            set
            {
                seconds = value;
                OnPropertyChanged("Seconds");
            }
        }

        // HORAS. 1ER DIGITO
        public bool H10
        {
            get { return h10; }
            set
            {
                h10 = value;
                OnPropertyChanged("H10");
            }
        }

        public bool H11
        {
            get { return h11; }
            set
            {
                h11 = value;
                OnPropertyChanged("H11");
            }
        }

        // HORAS. 2º DIGITO
        public bool H20
        {
            get { return h20; }
            set
            {
                h20 = value;
                OnPropertyChanged("H20");
            }
        }
        public bool H21
        {
            get { return h21; }
            set
            {
                h21 = value;
                OnPropertyChanged("H21");
            }
        }
        public bool H22
        {
            get { return h22; }
            set
            {
                h22 = value;
                OnPropertyChanged("H22");
            }
        }
        public bool H23
        {
            get { return h23; }
            set
            {
                h23 = value;
                OnPropertyChanged("H23");
            }
        }

        //MINUTOS. 1ER DIGITO
        public bool M10
        {
            get { return m10; }
            set
            {
                m10 = value;
                OnPropertyChanged("M10");
            }
        }
        public bool M11
        {
            get { return m11; }
            set
            {
                m11 = value;
                OnPropertyChanged("M11");
            }
        }
        public bool M12
        {
            get { return m12; }
            set
            {
                m12 = value;
                OnPropertyChanged("M12");
            }
        }
        // MINUTOS. 2º DIGITO
        public bool M20
        {
            get { return m20; }
            set
            {
                m20 = value;
                OnPropertyChanged("M20");
            }
        }
        public bool M21
        {
            get { return m21; }
            set
            {
                m21 = value;
                OnPropertyChanged("M21");
            }
        }
        public bool M22
        {
            get { return m22; }
            set
            {
                m22 = value;
                OnPropertyChanged("M22");
            }
        }
        public bool M23
        {
            get { return m23; }
            set
            {
                m23 = value;
                OnPropertyChanged("M23");
            }
        }

        // SEGUNDOS. 1ER DIGITO
        public bool S10
        {
            get { return s10; }
            set
            {
                s10 = value;
                OnPropertyChanged("S10");
            }
        }
        public bool S11
        {
            get { return s11; }
            set
            {
                s11 = value;
                OnPropertyChanged("S11");
            }
        }
        public bool S12
        {
            get { return s12; }
            set
            {
                s12 = value;
                OnPropertyChanged("S12");
            }
        }
        // SEGUNDOS. 2º DIGITO
        public bool S20
        {
            get { return s20; }
            set
            {
                s20 = value;
                OnPropertyChanged("S20");
            }
        }
        public bool S21
        {
            get { return s21; }
            set
            {
                s21 = value;
                OnPropertyChanged("S21");
            }
        }
        public bool S22
        {
            get { return s22; }
            set
            {
                s22 = value;
                OnPropertyChanged("S22");
            }
        }
        public bool S23
        {
            get { return s23; }
            set
            {
                s23 = value;
                OnPropertyChanged("S23");
            }
        }

        #endregion
    }

Pues con este código, cada segundo, se comprueba la hora y se pasa a cada uno de los indicadores un valor booleano correspondiente a su valor en binario, este se convierte en un color con el converter y et voilá, un reloj binario. Le he añadido la hora con números arábigos para que podáis contrastar. Y el resultado… en la cabecera.Espero que os haya gustado.

Sucesión de Fibonacci

Sucesión de Fibonacci
Publiqué en mi otro blog sobre mates, física y otros temas un post acerca de la sucesión y la espiral de Fibonacci y gustándome como me gustan las funciones recursivas, no podía quedar atrás una implementación en C# de esta sucesión.
Para ellos, en este artículo expondré diversos métodos para calcular la sucesión de Fibonacci a los cuales se les pasará como argumento el valor de n de la función y que a continuación os muestro:
El primero de ellos será mediante la función recursiva. Este es el método natural de cálculo de la sucesión
espiral01.png

        public double GetRecursiveFunction(int n)
        {
            if ((n == 0) || (n == 1)) return 1;
            else return GetRecursiveFunction(n -1) + GetRecursiveFunction(n - 2);
        }

Este método tiene el inconveniente de la complejidad recurrente que se aplica sobre su cálculo, es decir que si solicitamos el valor del elemento 39, haríamos una llamada a GetRecursiveFunction(39) , la cual una vez dentro de esta, llamará a los elementos GetRecursiveFunction(38) y GetRecursiveFunction(37) de la misma función para sumarlos, y estos a su vez a sus dos anteriores hasta llegar a GetRecursiveFunction(0) o GetRecursiveFunction(1) devolviendo el valor de 1 a partir de entonces comenzará a sumar. Esto significa que para cada cálculo se realiza la suma de las iteraciones de los dos elementos anteriores más 1. Si para n igual a 6 se llama a la función 15 veces y para n igual a 7, 25 veces, para n igual a 8 se llamaría a la función 15 más 25 y más 1 de la primera llamada. Esto supone un gasto de recursos enorme ya que para n igual a 40 el número de iteraciones se elevaría a la suma de 78.176.337, 126.491.971 y 1, un total de 204.668.309 iteraciones para obtener el elemento 40 de la sucesión; en tiempo, aproximadamente unos 8 segundos en un dual core con SSD. A todos los efectos, no es eficiente.El siguiente método de cálculo de la sucesión de Fibonacci, será el de la función general extraída mediante la ecuación de recurrencia y sus raíces.espiral14.png

Esta función tiene como inconveniente la precisión y muestro el por qué. En primero lugar creo una propiedad de solo lectura para calcular ϕ (Phi) o el número áureo, el cual es igual a
Espiral04.png
provocando una falta de precisión; por otra parte el uso de la exponenciación a n, lo que a su vez provoca que un número excesivamente grande, sea tratado exponencialmente. Todo esto unido para un n grande, nos hace obtener un número extremadamente aproximado a cualquier elemento de la sucesión, pero sin llegar a serlo, por lo que debemos auxiliarnos de la función de redondeo para obtener unos resultados satisfactorios. A pesar de los complejos cálculos, es muy rápida.

        public double Phi
        {
            get
            {
                return (1 + Math.Sqrt(5)) / 2;
            }
        }

        public double GetGeneralFuncion(int n)
        {
            double result = (double)((Math.Pow(Phi, n) - Math.Pow((1 - Phi), n)) / Math.Sqrt(5));
            return Math.Round(result);
        }

La siguiente función es la iterativa. Esta parte de los dos primeros valores 0 y 1 y va obteniendo el siguiente en cada iteración, sencilla y muy rápida. No tiene problemas de redondeo. El inconveniente que tiene es que no almacena los valores anteriores, sino que simplemente los calcula.

        public double GetIterativeFunction(int n)
        {
            double f0 = 0;
            double f1 = 1;
            for (int i = 1; i < n; i++)
            {
                f1 = f0 + f1;
                f0 = f1 - f0;
            }

            return f1;
        }

Por último, una función parecida a la iterativa pero en la cual quedan almacenados los elementos de la sucesión mediante un objeto List, de este modo se asignan los dos primeros valores y se van generando los siguientes añadiéndolos a la lista según se van calculando.

        public List numbers = new List();
        public void GetArrayListFunction(int n)
        {
            numbers.Clear();
            numbers.Add(0);
            numbers.Add(1);
            for (int i = 2; i < n; i++)
            {
                numbers.Add(numbers[i - 1] + numbers[i - 2]);
            }
        }

Una vez que hemos visto las funciones para obtener los elementos de la sucesión de Fibonacci, vamos a calcular la espiral de Fibonacci mediante dos métodos, XAML y código puro y duro.
Si lo hacemos con XAML, creamos un objeto Path y dentro de Path.Data con el siguiente código:

        <Path Stroke="Red" StrokeThickness="2" >
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                            <PathFigure StartPoint="610,610">
                                <PathFigure.Segments>
                                <PathSegmentCollection>
                                        <ArcSegment Point="600, 600" Size="10 10" />
                                        <ArcSegment Point="590, 610" Size="10 10" />
                                        <ArcSegment Point="610, 630" Size="20 20" />
                                        <ArcSegment Point="640, 600" Size="30 30" />
                                        <ArcSegment Point="590, 550" Size="50 50" />
                                        <ArcSegment Point="510, 630" Size="80 80" />
                                        <ArcSegment Point="640, 760" Size="130 130" />
                                        <ArcSegment Point="850, 550" Size="210 210" />
                                        <ArcSegment Point="510, 210" Size="340 340" />
                                        <ArcSegment Point="-40, 760" Size="550 550" />
                                        <ArcSegment Point="850, 1650" Size="890 890" />
                                        <ArcSegment Point="2290, 210" Size="1440 1440" />
                                    </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
        </Path>

Lo que hacemos es crear objetos ArcSegment como tantos elementos de la sucesión queramos incluir, pero su límite es evidente, por lo que podríamos crear un método genérico que creara una espiral en base al argumento n, de modo que llamamos por ejemplo a la función iterativa basada en List y con los datos almacenados en esta lista, usarlos para crear tanto objetos ArcSegment como elementos tenga la sucesión. El problema es que la sucesión de Fibonacci tiene un crecimiento alto y la espiral desaparecerá rápidamente de nuestra ventana, pero calcular, calcula correctamente la espiral.
He creado dos propiedades para el centro de la espiral, x e y un ángulo como variable angular. (También podríamos haber usado la función polar de la espiral, pero he escogido esta para mostrar cada arco de segmento).
Para seleccionar el centro de cada arco, he ingeniado un método que mediante el seno y coseno del ángulo de la función, sume o reste los valores de la sucesión y asigne correctamente el centro.
Una vez creados los arcos, los añadimos al objeto Figure y como en XAML vamos añadiendo a la colección.

        public double CenterX { get; set; } = 512;
        public double CenterY { get; set; } = 384;
        public double Angle { get; set; } = Math.PI;

        void create(int n)
        {

            Fibonacci fib = new Fibonacci();
            fib.GetArrayListFunction(n);

            PathGeometry pathGeometry = new PathGeometry();

            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point(CenterX, CenterY);

            for (int i =0; i < fib.numbers.Count; i++)
            {
                double sign = (i % 2 == 0 ? 1 : -1);
                double x = sign==1? Math.Round(Math.Cos(Angle)) : Math.Round(Math.Sin(Angle));
                double y = sign == 1 ? Math.Round(Math.Sin(Angle - Math.PI / 2)) : Math.Round(Math.Cos(Angle-Math.PI/2));
                double a = Math.Round(fib.numbers[i] * sign * x);
                double b = Math.Round(fib.numbers[i] * sign * y);

                CenterX = CenterX + a;
                CenterY = CenterY + b;

                ArcSegment arcSegment = new ArcSegment(new Point(CenterX, CenterY),
                    new Size(fib.numbers[i], fib.numbers[i]),
                    0,false,SweepDirection.Counterclockwise,true);

                figure.Segments.Add(arcSegment);
                Angle += Math.PI/2;

            }

            pathGeometry.Figures.Add(figure);
            path.Data = pathGeometry;
            path.Stroke = Brushes.Green;
        }

el resultado en ambos casos

fib02.png
y esto es todo,
saludos!