Librería de códigos C# (Compartan aquí sus códigos)

Iniciado por DarK_FirefoX, 19 Mayo 2015, 18:36 PM

0 Miembros y 2 Visitantes están viendo este tema.

DarK_FirefoX

27 - Calcular el determinante de una matriz cuadrada de orden n

Voy a mostrar un código recursivo para calcular el determinante de una matriz cuadrada de orden n. No voy a explicar tan en detalle que cosa es el determinante pues son conocimientos "básicos" de algebra que deben saber si necesitan utilizar esté código.

Veamos que:

Sea A una matriz cuadrada; asociada a esa matriz hay un número llamado determinante, que se simboliza por |A| o det(A) y que se calcula de la siguiente forma:

- Si el orden de A es 2 el determinante es el producto de los elementos de la diagonal principal menos el producto de los elementos de la diagonal secundaria:

Ej:

A = (a00, a01)
      (a10, a11)

Luego: det(A) = a00*a11 - a10*a01

- Si el orden de A es 3 el determinante se calcula utilizando la llamada Regla de Sarrus, según la cual si A es la matriz de orden 3:

A = (a00, a01, a02)
      (a10, a11, a12)
      (a20, a21, a22)

y: det(A) = a00*a11*a22 + a01*a12*a20 + a02*a10*a21 - a02*a11*a20 - a01*a10*a22 - a00*a12*a21

Ahora, si el orden de la matriz es superior a 3 el determinante se reduce al de una matriz de orden 3 o de orden 2 de la siguiente manera (que es la que vamos a implementar):

A partir de la matriz cuadrada arbitraria A, si removemos la fila i y la columna j obtenemos una nueva matriz de orden (una unidad) menor que la matriz A y que la vamos a denotar como Aij, cuyo determinante det(Aij) recibe el nombre de menor complementario del elemento aij. Si a este det(Aij) le acompañamos de su signo (-1)i+j tenemos el adjunto de aij

Resumiendo:

Menor complementario de aij = det(Aij)
Adjunto de aij = cij = (-1)i+j*det(Aij)

Entonces, si A es una matriz cuadrada de orden mayor que 3 el determinante de A se obtiene eligiendo una fila o columna arbitraria de A y multiplicando a cada elemento de esta por su adjunto. De esta forma, si elegimos la fila i, el determinante de A es:

det(A) = SUMATORIA(desde i, j=1 hasta n)(aij * (-1)i+j * det(Aij))

Espero esto se haya entendido, trate de explicarlo lo más sencillo posible.

Ahora vamos al código:

Vamos a tener varios métodos con las siguientes signaturas:

Código (csharp) [Seleccionar]
public static int Determinant(int[,] matrix)
static int DeterminantOrder2(int[,] matrix)
static int DeterminantRec(int[,] matrix)
static void FillMatrix(int[,] matrix, int[,] toFill, int row, int column)


Como podemos observar el método Determinant() va a ser el método portal, luego tenemos para calcular el determinante de una matriz de orden 2, luego para calcular el determinante de una matriz de orden mayor que 2 y el último es un método auxiliar para rellenar la matriz adjunta de los menores.

Código (csharp) [Seleccionar]
public static int Determinant(int[,] matrix)
        {
            //Comprobamos que sea cuadrada
            if (matrix.GetLength(0) != matrix.GetLength(1))
                throw new ArgumentException("La matriz debe ser cuadrada");
            //Vemos si es de orden 2
            if (matrix.GetLength(0) == 2)
                return DeterminantOrder2(matrix);
            else
                return DeterminantRec(matrix);

        }


En este ^^ método lo primero que hacemos es comprobar que la matriz sea cuadrada, para esto comprobamos el valor del método .GetLength(), el cual devuelve un int que representa la cantidad de elementos en cada dimensión, o sea el orden de la matriz horizontal y vertical. En este caso tenemos dos dimensiones, por lo tanto comprobamos que si se cumple que:

Código (csharp) [Seleccionar]
matrix.GetLength(0) != matrix.GetLength(1)

Entonces lanzamos una excepción pues la matriz no es cuadrada.

Luego, ya que sabemos que la matriz es cuadrada vamos a comprobar si es de orden 2 y llamamos al método correspondiente, sino es de orden mayor y llamamos al método recursivo.

Veamos primero el método DeterminantOrder2():

Código (csharp) [Seleccionar]
static int DeterminantOrder2(int[,] matrix)
        {
            return (matrix[0, 0] * matrix[1, 1]) - (matrix[0, 1] * matrix[1, 0]);
        }


Este método es muy sencillo lo cual no es necesario explicar nada. (Revisen arriba como se calcula el determinante de orden 2)

Ahora, vamos con el método DeterminatRec() que viene a ser "el más complicado", lo pongo entre comilla, porque no es más que una representación en código de la ecuación que les presenté antes para calcular el determinante de orden mayor que 2:

Código (csharp) [Seleccionar]
static int DeterminantRec(int[,] matrix)
        {
            //Caso de parada que sea de orden 2 y lo calculamos con el método para
            //el determinante de orden 2
            if (matrix.GetLength(0) == 2)
            {
                return DeterminantOrder2(matrix);
            }
            else
            {
                int det = 0; //Inicializamos una variable para almacenar el valor del determinante

                //En este ciclo recorremos una fila para para obtener el adjunto de cada elemento
                //de esta fila así calcular el determinante de este fijando cada elemento de la fila
                //0
                for (int i = 0; i < matrix.GetLength(1); i++)
                {
                    //Creamos una matriz para rellenarla con la matriz para luego calcular su
                    //determinante llamando recursivo. Esta matriz tiene un orden menor (en una
                    //unidad) que la matriz original
                    int[,] minor = new int[matrix.GetLength(0) - 1, matrix.GetLength(1) - 1];

                    //Aquí llamamos al método auxiliar que se encarga de rellenar la matriz auxiliar
                    FillMatrix(matrix, minor, 0, i);

                    //Aquí lo que vamos a definir si lo que se hace es sumar o restar. Esto es una
                    //manera de representar el cambio de signo que trae consigo el (-1) elevado a
                    //i+j. En este caso como utilizamos la fila 0 siempre, ese número va a ser
                    //positivo solo cuando estemos en una columna (j) que sea par, negativo en
                    //caso contrario
                    if (i % 2 == 0)
                        //Aquí lo que hacemos es multiplicar el valor del elemento en cuestión
                        //por el  adjunto teniendo en cuenta el signo correspondiente y se lo
                        //sumamos a la variable det (en el else es lo mismo lo que con el signo
                        //negativo). Aquí es donde está la llamada recursiva pues hay que calcular el
                        //determinante de la matriz "minor"
                        det+= (matrix[0, i]) * (DeterminantRec(minor));
                    else
                        det+= (-matrix[0, i]) * (DeterminantRec(minor));
                }
               
                //Una vez que ya recorrimos toda la fila, devolvemos el determinante
                return det;
            }
        }


Ya explique todo en los comentarios del código.

Ahora veamos el método FillMatrix():

Este método recibe la matriz desde la cual se van a sacar los valores, la matriz donde se van a copiar (de un orden menor en una unidad), la fila y la columna que se va a eliminar:

Código (csharp) [Seleccionar]
static void FillMatrix(int[,] matrix, int[,] toFill, int row, int column)
        {
            //Ciclo anidado para recorrer la matriz desde la cual se van a sacar los valores
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    //Si estamos en una fila menor a la que se va a eliminar
                    if (i < row)
                    {
                        //Si estamos en una columna menor a la que se va a eliminar
                        if (j < column)
                            toFill[i, j] = matrix[i, j]; //Copiamos el valor normalmente
                        else
                            if (j > column)
                              //En este momento estamos en una fila menor a la que se va a
                              //eliminar pero por encima de la columna a eliminar, por lo tanto
                              //se saca el valor de la matriz y se coloca en una columna con una
                              //unidad menos (j-1)
                              toFill[i, j - 1] = matrix[i, j];
                    }
                    else
                    //Si estamos en una fila mayor a la que se va a eliminar
                    if (i > row)
                    {
                        //Si estamos en una columna mayor a la que se va a eliminar
                        if (j < column)
                            //En este momento estamos por encima de la fila a eliminar pero por debajo
                            //de la columna a eliminar, por lo tanto tenemos que quitarle una unidad a la fila
                            //(i-1)
                            toFill[i - 1, j] = matrix[i, j];
                        else
                            if (j > column)
                              //Aquí estamos por encima tanto de la fila como de la columna a eliminar por lo
                              //tanto le quitamos una unidad tanto a las filas como a la columna (i-1, j-1)
                              toFill[i - 1, j - 1] = matrix[i, j];
                    }
                }
            }
        }


Espero que este código se haya entendido, sino, ya saben que pueden preguntar, opinar y/o criticar.

Quizás no sea la mejor manera (complejidad temporal) de hacerlo, si tienen alguna sugerencia será bienvenida.

Espero seguir subiendo códigos pronto.

Salu2s

DarK_FirefoX

#11
28 - Drag&Drop sobre un TextBox (detectando la codificación de caracteres)

Primer que todo vamos a repasar los conceptos básicos que se van a mostrar.

¿Que es un Drag&Drop?

Drag significa Arrastrar
Drop significa Soltar

Por lo tanto => Drag&Drop => Arrastrar y Soltar. Vamos que es la simple función de arrastrar un documento y soltarlo en algún lado. En este caso vamos a ser capaces de seleccionar un archivo de texto y soltarlo sobre un TextBox dentro del formulario.

Luego tenemos como detectar la codificación de caracteres. La codificación de caracteres es el método que permite convertir un carácter de un lenguaje natural en un símbolo de otro sistema de representación aplicando normas o reglas de codificación

Existen varios tipos de codificación:


  • UTF-8
  • UTF-16 Big Endian
  • UTF-16 Little Endian
  • UTF-7
  • UTF-32

Entre otros.

Ahora, ¿Cómo vamos a detectar que codificación tiene un fichero?

Para esto vamos a analizar la "Marca de orden de bytes (BOM)". BOM es un carácter Unicode que se utiliza para indicar el orden de los bytes de un fichero de texto. Su código es U+FEFF.

Representaciones de las marcas de orden de bytes para cada codificación








Encoding Representación (Hex)
UTF-7 2B 2F 76
UTF-8 EF BB BF
UTF-16 Little Endian FF FE
UTF-16 Big Endian FE FF
UTF-32 Big Endian 00 00 FE FF

Veamos el método que vamos a utilizar para analizar la BOM:

Código (csharp) [Seleccionar]
/// <summary>
       /// Determina la codificación de un fichero de texto analizando la marca de orden de bytes (BOM)
       /// Devuelve la codificación por defecto de la página ANSI del sistema en caso de que el análisis falle
       /// </summary>
       /// <param name="filename">El fichero de texto a analizar</param>
       /// <returns>La codificación detectada.</returns>
       public static Encoding GetEncoding(string filename)
       {
           // Read the BOM
           byte[] bom = new byte[4]; //Buffer para almacenar los datos leidos del fichero

           //Utilizamos un FileStream para abrir el fichero
           using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
           {
               file.Read(bom, 0, 4); //Leemos los 4 primeros bytes del fichero
           }

           // Analizamos la BOM y devolvemos la codificación correcta
           if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;
           if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;
           if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
           if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
           if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;

           //Devolvemos la codificacion por defecto de la página ANSI del sistema.
           return Encoding.Default;
       }


Nota: Para usar FileStream, debemos añadir a los using:

Código (csharp) [Seleccionar]
System.IO;

Nota: Ese ^^ nombre de espacio contiene tipos que permiten leer y escribir de archivos y flujos de datos, y tipos que brindan soporte básico para el trabajo con directorios.

Un FileStream, nos permite crear un flujo alrededor de un fichero, soportando operaciones de lectura y escritura tanto sincrónicas como asincrónicas.

Veamos que lo utilizamos con la declaración using que nos brinda una sintaxis conveniente para asegurar el uso correcto de objetos que implementen la interfaz IDisposable. Esta interfaz define un método que nos permite cerrar (de-allocate) los recursos de un objeto. Por lo tanto luego que se salga del ámbito de la declaración using los recursos del objeto sobre el cual se esta trabajando serán liberados. En este caso (FileStream) no será necesario hacerle Close()

El FileStream tiene un constructor con varias sobrecargas, en este caso vamos a utilizar la sobrecarga que tiene esta signatura:

Código (csharp) [Seleccionar]
FileStream(String, FileMode, FileAccess)

Donde el primer parámetro viene dado por la ruta del archivo, o sea, fileList[0]. El segundo es un enum que especifica como el sistema operativo debe abrir el archivo, en este caso FileMode.Open, lo cual indica que el sistema operativo debe abrir un fichero existente. La habilidad de abrir un fichero es dependiente del valor especificado por el enum  FileAccess en el próximo parámetro el cual define que permiso se tiene al acceder al archivo (Read, Write o Read/Write). En este caso vamos a utilizar FileAccess.Read, pues solo vamos a leer el archivo.

El método Read() que pertenece a la clase FileStream, nos permite leer un bloque de bytes desde el fichero apuntado por el flujo y guardarlo en un buffer dado. En este caso el método devuelve un int que representan la cantidad de bytes leídos. Pero modifica el primer parámetro, pues al ser un array, este es pasado al método por referencia, y por lo tanto es modificado. En él se guardan los bytes leídos. Este parámetro es un byte[]. El segundo parámetro es un int que representa el offset (digámosle la posición) en el array (primer parámetro) donde los bytes se comenzarán a guardar. Y el tercer parámetro es el máximo número de bytes a leer.

Ahora, como lo que queremos es mostrar el contenido de un fichero de texto en un TextBox vamos a insertar un TextBox en el formulario.

Nota: En este ejemplo>

Propiedad Name del Form -> mainForm
Propiedad Name del TextBox -> textBox


Ahora, para permitirle a textBox recibir información que haya sido arrastrada y soltada sobre él, le vamos a poner la propiedad AllowDrop = true

Ahora nos vamos subscribir a los eventos textBox_DragEnter y textBox_DragDrop. Luego vamos a necesitar un string[] para almacenar las rutas de el/los fichero/s que se soltaron sobre textBox. Para eso declaramos un campo privado dentro de la clase de mainForm:

Código (csharp) [Seleccionar]
string[] fileList;

Veamos que hacemos una vez que se capture el evento textBox_DragEnter

Código (csharp) [Seleccionar]
private void textBox_DragEnter(object sender, DragEventArgs e)
       {
           if (e.Data.GetDataPresent(DataFormats.FileDrop))
           {
               fileList = (string[])e.Data.GetData(DataFormats.FileDrop);
               if (fileList.Length == 1 && Path.GetExtension(fileList[0]) == ".txt")
               {
                   e.Effect = DragDropEffects.Copy;
               }
               else
                   e.Effect = DragDropEffects.None;
           }
       }


Lo primero que vemos es la propiedad Data del tipo DataEventArgs e que devuelve un objeto que implementa IDataObject, que contiene datos asociado con este evento. Entonces lo que hacemos es llamar al método GetDataPresent() de la interfaz IDataObject el cual nos permite determinar si la información almacenada en esta instancia está asociada a un formato especifico. En este caso le pasamos como parámetro el campo estático (solo-lectura) FileDrop de la clase DataFormats - DataFormats.FileDrop. El cual especifica el formato de Windows para arrastrar y soltar ficheros.

Una vez explicado esto, lo que comprobamos es que si lo que se está soltando encima de textBox es un archivo vamos a hacer una cosa:

Primero que todo:

Código (csharp) [Seleccionar]
fileList = (string[])e.Data.GetData(DataFormats.FileDrop);

Con el método GetData() sobre la propiedad Data del tipo DragEventArgs e obtenemos la información (con el formato establecido [DataFormats.FileDrop]) que estamos arrastrando sobre el textBox. Luego, vemos que le estamos haciendo un cast a string[] y se lo asignamos al campo que habíamos declarado. Aquí tendremos toda la información que viene siendo arrastrada y capturada por el evento. Como el formato es FileDrop lo que nos va a añadir en el array son las rutas a los documentos que están siendo arrastrados.

Ahora vamos a hacer 2 comprobaciones:

1 - Que solo estemos arrastrando 1 solo fichero, para esto solo tenemos que comprobar que la longitud del array sea 1

2 - Que la extensión del archivo sea ".txt".

Para comprobar esta segunda condición vamos a utilizar el método GetExtension() de la clase Path que pertenece al namespace System.IO. La clase estática Path realiza operaciones sobre strings que contienen información de rutas de ficheros o directorio. En este caso utilizamos el método estático GetExternsion(), el cual recibe un string que representa "la ruta" de la cual queremos sacar la extensión. En este caso: fileList[0], el cual es el único archivo que estamos arrastrando y comprobamos si es igual a ".txt". En ese caso vamos a definir la propiedad Effect del tipo DragEventArgs e a DragDropEffects.Copy, en caso contrario (que no se cumplan las dos condiciones) a DragDropEffects.None.

La propiedad Effect aplica el efecto determinado para el cursor cuando se hace una operación de Drag & Drop sobre el control.

Luego, vemos que le asignamos un valor utilizando el enum DragDropEffects, y su valor Copy, que crea el efecto de que lo que se está arrastrando es copiado a donde se va a soltar.

En el otro caso está DragDropEffects.None que implica que donde se va a soltar no acepta datos. Por lo tanto no aceptará los datos cuando se suelten los datos.

Ahora veamos el EventHandler para textbox_DragDrop:

Código (csharp) [Seleccionar]
private void textBox_DragDrop(object sender, DragEventArgs e)
       {
           Encoding fileEncoding = GetEncoding(fileList[0]);
           using (StreamReader file = new StreamReader(fileList[0], fileEncoding))
           {
               textBox.Text = file.ReadToEnd();
           }
       }


Lo primero que hacemos es capturar lo que devuelve el método GetEncoding() (explicado anteriormente), el cual devuelve la codificación de caracteres correspondiente al fichero (fileList[0]) tras analizar la BOM.

Luego, utilizando un StreamReader, que también pertenece al namespace System.IO vamos a leer el fichero.

Un StreamReader nos permite leer caracteres de un flujo de bytes en una codificación específica. En este caso utilizamos la declaración using con el mismo objetivo que explique arriba con el FileStream. Utilizaremos una sobrecarga del constructor del StreamReader que recibe la ruta del fichero al cual le queremos crear el flujo (fileList[0]) y la codificación de caracteres con la cual queremos abrirla. En este caso le pasamos lo que nos devolvió el método GetEncoding().

Entonces dentro del ámbito de la declaración using vamos a asignarle a la propiedad Text de textBox, lo que nos devuelve el método ReadToEnd() perteneciente a la clase StreamReader. Este método lee todos los caracteres desde la posición actual (en el stream) hasta el final del stream. Se dice desde la posición actual, pues se pueden haber hecho lecturas desde el stream anteriormente y se queda guardada hasta que posición se leyó, en este caso no se había leído nada, por lo tanto se lee desde el principio hasta el final.

Bueno, esto es todo para este código, solo les queda probarlo. Espero que entiendan todo, quizás no sea la mejor manera de explicarlo, pero lo hice lo mejor y más sencillo que pude.

Cualquier duda/comentario/crítica será bienvenida.

Espero seguir subiendo códigos pronto.

Salu2s

Eleкtro

#12
Comparar solamente 5 codificaciones y en caso de no coincidir ninguna devolver la codificación que representa a la página de códigos del sistema no es lo mejor que se puede hacer, lo que deberías hacer es iterar las codificaciones con la función System.Text.Encoding.GetEncodings y usar la función Encoding.GetEncoding para obtener la codificación y Encoding.GetPreamble para obtener el preámbulo (BOM) con el que comparar la secuencia de bytes.
De esta manera pasamos de comparar 5 codificaciones, a unas 150.

Un ejemplo (convertido de VB.Net a C#):
Código (csharp) [Seleccionar]
/// ----------------------------------------------------------------------------------------------------
/// <remarks>
/// Title : Get Encoding of textfile.
/// Author: Elektro
/// Date  : 17-January-2015
/// </remarks>
/// ----------------------------------------------------------------------------------------------------
/// <example><code>
/// Dim encoding As Encoding = TextfileUtil.GetEncoding("C:\file.txt")
/// Dim encodingName As String = TextfileUtil.GetEncoding("C:\file.txt").WebName
/// </code></example>
/// ----------------------------------------------------------------------------------------------------
/// <summary>
/// Determines the <see cref="Encoding"/> of the source textfile.
/// </summary>
/// ----------------------------------------------------------------------------------------------------
/// <param name="sourceFilepath">
/// The source textfile path.
/// </param>
/// ----------------------------------------------------------------------------------------------------
/// <returns>
/// If the encoding can be detected, the return value is the detected <see cref="Encoding"/>,
/// if the encoding can't be detected, the return value is <see cref="Encoding.Default"/>.
/// </returns>
/// ----------------------------------------------------------------------------------------------------
[DebuggerStepThrough()]
[DebuggerHidden()]
public static Encoding GetEncoding(string sourceFilepath)
{

Encoding encoding = null;
byte[] bytes = File.ReadAllBytes(sourceFilepath);

foreach (EncodingInfo encodingInfo in encoding.GetEncodings()) {
Encoding currentEncoding = encodingInfo.GetEncoding();
byte[] preamble = currentEncoding.GetPreamble();
bool match = true;

if ((preamble.Length > 0) && (preamble.Length <= bytes.Length)) {

for (int i = 0; i <= (preamble.Length - 1); i++) {
if (preamble(i) != bytes(i)) {
match = false;
break; // TODO: might not be correct. Was : Exit For
}

}

} else {
match = false;

}

if (match) {
encoding = currentEncoding;
break; // TODO: might not be correct. Was : Exit For
}

}

if (encoding == null) {
return encoding.Default;

} else {
return encoding;

}

}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Saludos








SnzCeb

#13
Hola chicos, pues voy a hacer mi primera aportación de código a ver si os parece útil. Es una clase que está pensada como almacén de datos de juegos basado en tablero de celdas. Me ha servido para implementar el juego de la vida y seguro que os puede servir para juegos como el tres, el cuatro en raya, damas, que se yo xD.

Código (csharp) [Seleccionar]


    /*************************************************************************************
     * This class implements a bit board                                                 *
     *                                                                                   *
     * Foreach bit we have one cell. If we turn on a bit means occupied cell. By the     *
     * opposite, if we turn off the bit, means empty cell                                *
     * The main gain of a bitBoard is to decrease the amount of memory used.             *
     * this fact is so important in algorithms like Minimax                              *
     * foreach byte we can cover 8 positions                                             *
     * For instance: If we have and 8x8 board, we can save 64 cells in a 8x1 board       *
     * (8 bytes) because 1 byteCell can save 8 cells                                     *
     *************************************************************************************/


   public class Board
    {

        protected readonly byte[,] board;
        protected readonly int height;
        protected readonly int byteWidth;
        protected readonly int width;

        protected Board(int height, int width)
        {
            this.height = height;
            this.byteWidth =(int) Math.Ceiling(width * 0.125); // 0.125 * width = width /8 
            this.width = width;
            board = new byte[height, byteWidth];
        }

       
        private byte IncreaseBitPosn(int n)
        {

            return (byte)(0x1 << n);
        }
        private byte ReverseByte (byte b)
        {
            return  (byte) (b ^ 0xFF);
        }

        private int ToByteColumn(int y)
        {
            return (int) 0.125 * y;
        }

        private int ToBitColumn(int y)
        {
            return (y >= 8) ? y - (ToByteColumn(y) * 8) : y;
        }

        /*
        *  Checks if [x,y] is empty with an and bitwise
        *  For instance:
        *  x = 3
        *  y = 7  -> Matchs to byteCol 0, bitCol 7
        *  board (3,0)        = 1 0 0 1 0 1 0 0
        *  IncreaseBitPosn(7) = 1 0 0 0 0 0 0 0
        *  1 0 0 1 0 1 0 0 &  1 0 0 0 0 0 0 0 = 1 0 0 0 0 0 0 0 != 0 -> returns false               
        */
        protected bool PosIsEmpty(int x, int y)
        {
            return (board[x, ToByteColumn(y)] & IncreaseBitPosn(ToBitColumn(y))) == 0;
    }
        /*
        *  Increases bit at position (x,y)
        *  For instance:
        *  x = 3
        *  y = 7  -> Matchs to byteCol 0, bitCol 7
        *  board (3,0)        = 1 0 0 1 0 1 0 0
        *  IncreaseBitPosn(7) = 1 0 0 0 0 0 0 0
        *  0 0 0 1 0 1 0 0  |  1 0 0 0 0 0 0 0 = 1 0 0 1 0 1 0 0 
        */
        protected void turnOnBit(int x, int y)
        {
            board[x, ToByteColumn(y)] |= IncreaseBitPosn(ToBitColumn(y));
        }
        /*
         *  Decreases bit at position (x,y)
         *  For instance:
         *  x = 3
         *  y = 7  -> Matchs to byteCol 0, bitCol 7
         *  board (3,0)        = 1 0 0 1 0 1 0 0
         *  ReverseByte(IncreaseBitPosn(7)) = 0 1 1 1 1 1 1 1
         *  1 0 0 1 0 1 0 0  &  0 1 1 1 1 1 1 1 = 0 0 0 1 0 1 0 0 
         */

        protected void turnOffBit(int x, int y)
        {
            board[x, ToByteColumn(y)] &=  ReverseByte(IncreaseBitPosn(ToBitColumn(y)));
        }

    }

z3nth10n

OBTENER EL PRIMER NUMERO O TODOS LOS NÚMEROS QUE FALTAN DE UNA SECUENCIA DEFINIDA, si los hay...

Pues trabajando en mi sistema de Sockets he inventado este sistema dinámico para obtener si un numero falta dentro de una secuencia. Digo dinámica porque funciona con tipos dinámicos, el último método podremos especificar más tipos si se requiere, como por ejemplo los que nos aporta System.Data.SqlTypes (gracias Elektro).

Código (csharp) [Seleccionar]

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

namespace MissingNumbersOnSequence
{
   public class Program
   {
       public static void Main(string[] args)
       {
           List<ulong> longs = (new ulong[] { 1, 2, 3, 6, 7, 8, 12, 13, 14, 17 }).ToList();

           //Los dos metodos explicados
           ulong numb = 0;
           bool b = FindFirstMissingNumberFromSequence(longs, out numb); //Se devuelve una bool para saber si realmente había algún número que faltaba, puesto que por defecto se devolverá el 0, y el 0 puede formar parte de una secuencia a la cual no pertenece.

           Console.WriteLine("First missing number: {0}\nMissing numbers: {1}", numb, string.Join(", ", FindMissingNumbersFromSequence(longs).Select(x => x.ToString()))); //Para comprobar si la secuencia estaba incompleta solo habría que comprobar x.Count() > 0...
           Console.Read();
       }

       public static bool FindFirstMissingNumberFromSequence<T>(IEnumerable<T> arr, out T n)
       {
           if (!arr.Any(x => x.IsNumericType()))
           {
               Console.WriteLine("Type '{0}' can't be used as a numeric type!", typeof(T).Name);
               n = default(T);
               return false;
           }

           IOrderedEnumerable<T> list = arr.OrderBy(x => x);
           bool b = false;
           n = default(T);

           foreach (T num in list)
           {
               b = (dynamic)num - n > 1;
               if (b) break;
               else n = (dynamic)num;
           }

           n = (dynamic)n + 1;

           return b;
       }

       public static IEnumerable<T> FindMissingNumbersFromSequence<T>(IEnumerable<T> arr) where T : struct
       {
           if (!arr.Any(x => x.IsNumericType()))
           {
               Console.WriteLine("Type '{0}' can't be used as a numeric type!", typeof(T).Name);
               yield break;
           }

           IOrderedEnumerable<T> list = arr.OrderBy(x => x);
           T n = default(T);

           foreach (T num in list)
           {
               T op = (dynamic)num - n;
               if ((dynamic)op > 1)
               {
                   int max = op.ConvertValue<int>();
                   for (int l = 1; l < max; ++l)
                       yield return (dynamic)n + l.ConvertValue<T>();
               }
               n = (dynamic)num;
           }
       }

   }

   public static class Extensions
   {
       public static T ConvertValue<T>(this object o) where T : struct
       {
           return (T)Convert.ChangeType(o, typeof(T));
       }

       public static bool IsNumericType<T>(this T o)
       {
           return typeof(T).IsNumericType();
       }

       public static bool IsNumericType(this Type type)
       {
           switch (Type.GetTypeCode(type))
           {
               case TypeCode.Byte:
               case TypeCode.SByte:
               case TypeCode.UInt16:
               case TypeCode.UInt32:
               case TypeCode.UInt64:
               case TypeCode.Int16:
               case TypeCode.Int32:
               case TypeCode.Int64:
               case TypeCode.Decimal:
               case TypeCode.Double:
               case TypeCode.Single:
                   return true;
               default:
                   return false;
           }
       }
   }
}


Un saludo.

Interesados hablad por Discord.

Eleкtro

Escanear un archivo o una url en VirusTotal.com

Se me ocurrió implementar la API 2.0 de VirusTotal en VB.NET, pero primero busqué para asegurarme de que nadie lo habia hecho todavía (de lo conrario sería absurdo reinventar la rueda), y descubrí que efectivamente ya alguien lo hizo, en C#. Os dejo el repositorio por aquí:


PD: no lo he probado.

Saludos.








z3nth10n

Thread Safe Bool: Implementación Thread-Safe de bools

El otro día me pasaba que al asignar una variable que estaba declarada en ambito de la clase desde otro thread, al leerla desde otro thread no me devolvía el resultado esperado, por eso os traigo esta utilidad.

Código (csharp) [Seleccionar]
using System.Threading;

namespace GTAMapper.Extensions.Threading
{
    /// <summary>
    /// Thread safe enter once into a code block:
    /// the first call to CheckAndSetFirstCall returns always true,
    /// all subsequent call return false.
    /// </summary>
    public class ThreadSafeBool
    {
        private static int NOTCALLED = 0,
                           CALLED = 1;

        private int _state = NOTCALLED;

        /// <summary>Explicit call to check and set if this is the first call</summary>
        public bool Value
        {
            get
            {
                return Interlocked.Exchange(ref _state, CALLED) == NOTCALLED;
            }
        }

        /// <summary>usually init by false</summary>
        public static implicit operator ThreadSafeBool(bool called)
        {
            return new ThreadSafeBool() { _state = called ? CALLED : NOTCALLED };
        }

        public static implicit operator bool(ThreadSafeBool cast)
        {
            if (cast == null)
                return false;

            return cast.Value;
        }
    }
}


Extraído de: https://www.codeproject.com/Tips/375559/Implement-Thread-Safe-One-shot-Bool-Flag-with-Inte

Interesados hablad por Discord.

z3nth10n

#17
ConcurrentQueuedCoroutines: Implementación Thread-Safe de ConcurrentQueues dentro de Coroutinas

La idea de esta utilidad es que cuando tu almacenas items desde otro thread, puedas acceder desde el thread principal.

Mezclando esta idea, con coroutinas, que básicamente, es un sistema del prehistorico que implementó Unity en su momento, que funciona de la siguiente forma, se crea un IEnumerator (con yields), el cual cada MoveNext se ejecuta en cada frame (yield return null) o cuando el programador especifique (yield return new WaitForSeconds(3) equivalente a Thread.Sleep(3000)) (por tal de no atorar el Main Thread, sí, Unity se ejecuta en un solo hilo).

Entonces, teniendo estas 2 cosas, porque no hacer Dequeue en cada MoveNext?

Código (csharp) [Seleccionar]
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;

namespace GTAMapper.Extensions.Threading
{
   public class ConcurrentQueuedCoroutines<T>
   {
       private List<Coroutine> coroutines;
       private Coroutine coroutine;
       private MonoBehaviour Mono;

       public ConcurrentQueue<object> Queue { get; private set; }

       public Action<T> Action { get; private set; }
       public bool Debugging { get; set; }
       public float SecondsToWait { get; private set; }

       private ConcurrentQueuedCoroutines()
       {
       }

       public ConcurrentQueuedCoroutines(float secondsToWait = -1)
       {
           Queue = new ConcurrentQueue<object>();
           coroutines = new List<Coroutine>();
           SecondsToWait = secondsToWait;
       }

       public Coroutine StartCoroutine(MonoBehaviour monoBehaviour, Action<T> action)
       {
           coroutines.Add(monoBehaviour.StartCoroutine(InternalCoroutine()));
           Mono = monoBehaviour;
           Action = action;

           return coroutine;
       }

       public Coroutine StartCoroutineOnce(MonoBehaviour monoBehaviour, Action<T> action)
       {
           if (Debugging)
               Debug.Log("Starting dequeing!");

           if (coroutine == null)
           {
               coroutine = monoBehaviour.StartCoroutine(InternalCoroutine());
               Mono = monoBehaviour;
               Action = action;
           }

           return coroutine;
       }

       public void StopCoroutine()
       {
           if (coroutine != null && Mono != null)
               Mono.StopCoroutine(coroutine);
       }

       public void StopAllCoroutines()
       {
           if (Mono != null && coroutines != null && coroutines.Count > 0)
               coroutines.ForEach((c) => Mono.StopCoroutine(c));
       }

       public IEnumerator GetCoroutine(MonoBehaviour mono, Action<T> action)
       {
           Mono = mono;
           Action = action;
           return InternalCoroutine();
       }

       private IEnumerator InternalCoroutine()
       {
           if (Debugging)
               Debug.Log($"Starting dequeing {Queue.Count} values!");

           while (Queue.Count > 0)
           {
               object value = null;
               bool dequeued = Queue.TryDequeue(out value);

               if (!dequeued)
               {
                   if (SecondsToWait == -1)
                       yield return new WaitForEndOfFrame();
                   else
                       yield return new WaitForSeconds(SecondsToWait);

                   continue;
               }

               Action?.Invoke((T)value);

               if (SecondsToWait == -1)
                   yield return new WaitForEndOfFrame();
               else
                   yield return new WaitForSeconds(SecondsToWait);
           }
       }
   }
}


Y diréis, y para que sirve esta chorra, pues por ejemplo, lo que se puede conseguir, es visualizar como se recorre una textura.





En el próximo post o enseñaré un caso de uso.

Interesados hablad por Discord.

z3nth10n

#18
BatchedCoroutines: Iterar coroutinas una a una

Queréis que vuestras ConcurrentQueues se ejecuten una por una? No problemo, con esta implementación to hard-codeada lo conseguiréis:

Código (csharp) [Seleccionar]
using GTAMapper.Extensions.Threading;
using System;
using System.Collections;
using UnityEngine;

namespace GTAMapper.Extensions
{
   public static class BatchedCoroutines
   {
       public static IEnumerator BatchCoroutines(
           MonoBehaviour monoBehaviour,
           Action finish,
           Func<int, bool>[] waitUntil = null,
           params Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>[] tuple) // Tuple<Action<T>, ConcurrentQueuedCoroutines<T>> || dynamic
                                                                                     // Fix for: https://stackoverflow.com/questions/15417174/using-the-params-keyword-for-generic-parameters-in-c-sharp
       {
           int i = 0;

           foreach (var val in tuple)
           {
               if (waitUntil != null && waitUntil[i] != null)
                   yield return new WaitUntil(() => waitUntil[i](i));

               yield return val.Item2.GetCoroutine(monoBehaviour, val.Item1);

               ++i;
           }

           finish?.Invoke();
       }
   }
}


Un ejemplo de implementación:

Código (csharp) [Seleccionar]
       protected ConcurrentQueuedCoroutines<object> debuggingCoroutine = new ConcurrentQueuedCoroutines<object>(),
                                                    colorCoroutine = new ConcurrentQueuedCoroutines<object>();

namespace GTAMapper.Core {
   public class Program : MonoBehaviour {
       public void Start() {
       StartCoroutine(BatchedCoroutines.BatchCoroutines(
               this,
               () => areCoroutinesCollected = true,
               F.GetFuncs(null, (_ii) => debuggingCoroutine.Queue.Count > 0),
               new Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>((obj) =>
               {
                   Tuple<int, Color> tuple = (Tuple<int, Color>)obj;

                   int i = tuple.Item1,
                           _x = i % width,
                           _y = i / width;

                   UnityEngine.Color actualColor = debugTexture.GetPixel(_x, _y),
                                         mixedColor = UnityEngine.Color.Lerp(actualColor, tuple.Item2, .5f);

                   if (actualColor != mixedColor)
                   {
                       debugTexture.SetPixel(_x, _y, mixedColor);
                       debugTexture.Apply();
                   }
               }, colorCoroutine),
               new Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>((obj) =>
               {
                   Color[] colors = (Color[])obj;

                   debugTexture.SetPixels32(colors.CastBack().ToArray());
                   debugTexture.Apply();
               }, debuggingCoroutine)));
         }
    }
}


Básicamente, en las dos Queues vamos haciendo Enqueue donde sea necesario (en otro thread).

Cuando todo haya acabado, desde el primer thread, llamamos a que se ejecute lo que acabo de mostrar.

Y en mi caso por ejemplo, esto sirve para mostrar pixel a pixel donde se ha iterado una imagen.

Y lo siguiente que ocurre es que la imagen se rellena con el algoritmo de flood-fill que enseñe el otro día. (Básicamente, para saber si se ha hecho bien)

Nota: Si queréis el código de GetFuncs es este:

Código (csharp) [Seleccionar]
using System;

public static class F {
       public static Func<int, bool>[] GetFuncs(params Func<int, bool>[] waitUntil)
       {
           return waitUntil;
       }
}

Interesados hablad por Discord.

z3nth10n

Named Thread & Thread Marked: Pon nombres a tus threads

Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Threading;

namespace GTAMapper.Extensions.Threading
{
    public class ThreadMarker : IDisposable
    {
        //[ThreadStatic]
        //private static string __Name = $"Unity Thread #{Thread.CurrentThread.ManagedThreadId}";

        private static Dictionary<int, string> ThreadNames = new Dictionary<int, string>();

        public static string Name
        {
            get
            {
                lock (ThreadNames)
                {
                    try
                    {
                        return ThreadNames[Thread.CurrentThread.ManagedThreadId];
                    }
                    catch
                    {
                        return $"Unity Thread #{Thread.CurrentThread.ManagedThreadId}";
                    }
                }
            }
        }

        public ThreadMarker(string name)
        {
            lock (ThreadNames)
            {
                ThreadNames.AddOrSet(Thread.CurrentThread.ManagedThreadId, name);
            }

            // __Name = name;
        }

        public void Dispose()
        {
            ThreadNames.Remove(Thread.CurrentThread.ManagedThreadId);
            // __Name = "Un-Owned";
        }
    }
}


Código (csharp) [Seleccionar]
using System;

namespace GTAMapper.Extensions.Threading
{
    public class NamedHandler<TArg>
    {
        public readonly Func<string, TArg> Handler;

        public NamedHandler(Func<string, TArg> handler)
        {
            Handler = arg =>
            {
                using (new ThreadMarker(arg))
                {
                    return handler(arg);
                }
            };
        }
    }
}


Caso de uso:

Código (csharp) [Seleccionar]
int TaskId = new Random().Next();

ThreadPool.QueueUserWorkItem(new NamedHandler<WaitCallback>(name => new WaitCallback(BackgroundRunner)).Handler($"Ninja #{TaskId}"));

Interesados hablad por Discord.