Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

miércoles, 10 de junio de 2026

Usando mi scanner Canon Lide 110 en Linux Mint

Paso 1: Conectar el Scanner

Paso 2: No esperar a que el scanner haga algún ruido

Paso 3: Abrir la aplicación "Escáner de Documentos" que ya viene instalada

Paso 4: esperar a que detecte el scanner


Paso 5: Have fun




Para guardar la imagen se debe presionar el botón con la flechita hacia abajo en la esquina superior derecha. El formato se puede elegir entre pdf, jpg y png. La aplicación tiene en la parte inferior las opciones para rotar y recortar la imagen (no se muestran porque recorté demasiado los pantallazos).

Este es el dibujito después de aumentarle el contraste con el Krita (lo más parecido a Paint.net que he encontrado), el cual puede instalarse usando el Gestor de Software del Linux Mint. (Creo que se nota que me gusta hacer dibujitos).



Y ahora...


Ya van varios días que estoy usando Linux Mint y no he tenido que ni abrir la terminal. Yo trasteé con varias distros allá por los 2010s, en aquella época en que venían sin las librerías para NTFS o para USB 2.0, y había que montar las particiones NTFS con comandos en la terminal y hasta manoseando archivos de sistema. El tema es que lo primero que se debía hacer apenas instalar un linux era buscar los comandos para resolver dependencias, instalar paquetes, ejecutar aplicaciones... casi todo en realidad. Linux era algo que no podías recomendar a usuarios de Windows. La prueba está en estas entradas:  

2026... las cosas son MUY distintas. Es casi un salto cuántico.


Soy sincera... extraño un poco tener que aporrear la terminal como un mandril con epilepsia.

lunes, 8 de junio de 2026

Configurando el Linux Miint

Mi Linux Mint es el siguiente:

System:
  Kernel: 6.17.0-35-generic arch: x86_64 bits: 64 compiler: gcc v: 13.3.0 clocksource: tsc
  Desktop: Cinnamon v: 6.6.7 tk: GTK v: 3.24.41 wm: Muffin v: 6.6.3 vt: 7 dm: LightDM v: 1.30.0
    Distro: Linux Mint 22.3 Zena base: Ubuntu 24.04 noble
Machine:
  Type: Laptop System: LENOVO product: 83A1 v: Lenovo V15 G4 IRU

En esta distro se puede acceder al menú de inicio con la tecla Windows.

A esta información se llega poniendo "About" en la caja de búsqueda del menú inicio (¿se le dice así en Linux?)  y aparecerá la pantalla de Información del Sistema (Este pantallazo es de cuando ya había cambiado mi sistema a español, las instrucciones más abajo). 

Y ahora el tutorial:

Primero: aumentar el tamaño de fuente porque por defecto los Linux muestran todo muy chiquito.  Nos vomos a la opción All Applications -> Accesibility-> Visual y elegimos Large Text:

 

 

Luego vamos a All Applications -> Font Selection (debajo del que está resaltado en la imagen)

 

En esta ventana podemos configurar el tamaño de fuente de todo el sistema, yo le puse 11 a todo:

 

 

Segundo:. El teclado. El layout "Spanish (Latin America no Dead keys)" no coincide con mi teclado. Para corregirlo hay que ir a Inicio y escribir Keyboard en la caja de búsqueda 

En la ventana que aparece, podremos elegir un nuevo layout haciendo click en el botón con el signo +

 

 

Escritorio: Le hacemos click derecho y elegimos Change Desktop Background:

 

 El signo + permite elegir una carpeta conn las imágenes y la pestaña Settings permite configurar el tamaño y el tiempo que se verán en el escritorio

Faltan los íconos, le hacemos click derecho a la barra de tareas y elegimos System Settings->Desktop

 

Luego quise aumentarle el tamaño al panel (barra de tareas). Nos vamos a System Settings -> Panel o también haciéndole click derecho al Panel y eligiendo la primera opción: Panel Settings. En la sección Customize se puede aumentar el alto del Panel, esto hará que el panel (y los ícoonos de los programas) sean más grandes.

 

El resultado no está mal:

 

En el menú de inicio elegimos Language, aparecerá esta ventana:

 

Aquí podemos instalar Lenguajes. Nos va a pedir la contaseña.

 

 Para que se haga efectivo el cambio se debe reiniciar el sistema:

 

 

Update un día después: Al cambiar el lenguaje del sistema, Linux me creó nuevas carpetas en mi carpeta home:

 

Los archivos que creé o descargué antes del cambio de idioma se quedaron en las carpetas Documents, Pictures y Downloads. Las nuevas carpetas, y que son las que aparecen en la lista de la izquierda, son respectivamente: Documentos, Imágenes y Descargas. Un detalle es que esto sólo ha sucedido con las carpetas que tenían archivos dentro, las que estaban vacías (Music, Desktop, etc) ya no aparecen.

Instalando Linux Mint de modo que nos de la opción de doble booteo Linux/Windows 11

 Ah, cómo echo de menos el linux. Y antes de que Microsoft me obligue a usar su AI (mi odio a la AI es otra historia: sé lo que hay detrás, sé cómo funciona, y he visto cómo nos está llevando al desastre ecológico y social), y me obligue a cederle más data personal de la que ya le doy, quiero tener la opción de usar un linux y mandarlos a dar por culo.

Y mejor no menciono Windows Recall, eso ya es un círculo más profundo en el infierno.

rant/

Mi lucha contra la AI incluye también a Google y otras empresas por ahi: lo único smart que tengo es mi teléfono del 2018 junto a un martillo por si se le ocurre hacer un ruido raro (mi tablet del 2014 no cuenta). El beneficio que da la AI a una persona común y corriente es cero, no hace nada que no hacíamos ya usando el cerebro y la wikipedia, y la obsesión por la productividad no nos ha dado aire más limpio ni comida más barata. Ojalá la burbuja reviente de una vez.

/rant

Y ahora al tutorial. Mi laptop es una Lenovo del año pasado (yo misma me sorprendo: ¡estoy usando hardware de menos de una década de edad!) así que puedo meterle todo el software patea-hardware que me de la gana, así que le voy a meter la última versión del Linux Mint https://linuxmint-installation-guide.readthedocs.io/en/latest/

Antes tenía que crearme un USB booteable. Elegí el disco duro que tengo tirado de una laptop del 2011 (y que ya murió) al que hice que me lo pusieran en uno de esos adaptadores que permiten usarlo como disco duro externo.

Paso 0: Siempre: backupear todo.

Instrucciones para crear el USB booteable aquí: https://linuxmint-installation-guide.readthedocs.io/en/latest/burn.html Linux Mint recomienda usar la aplicación Etcher.

Para bootear desde USB seguí las instrucciones de esta web:  https://support.lenovo.com/pe/es/solutions/ht500217 

En Windows 11 hay que ir a configuración -> Sistema ->Recuperación


De ahí vamos  a Arranque Avanzado -> Reiniciar


Windows nos mostrará este menú, hay que elegir "Usar un Dispositivo":


Conectamos el USB desde donde bootearemos el Linux y elegimos EFI USB Device:


Aquí el sistema arrancará desde el Live Linux dentro del USB. En la esquina superior izquierda nos aparecerá esta opción:


Entramos a esta opción, una vez que termine de cargar el instalador nos mostrará la opción que necesitamos ya seleccionada:


Ya nos está prometiendo no trastearnos el Windows y que nos dará la opción de elegir el sistema operativo una vez terminada la instalación. Le damos continuar.

Mi laptop tiene un disco duro de 500 gigas particionado en C y D (mitad y mitad aproximadamente). En la imagen se ve la partición C (nvme0n1p3), a la derecha está la D (nvme0np1p5), se las reconoce por el tamaño:

Aquí debo resaltar que MI PARTICIÓN D ESTÁ VACÍA.

Para el "Device for boot loader installation" le dejamos el dispositivo /dev/nvme0n1 que es mi disco duro, le damos continuar:


Yo le dejé el tamaño de partición por defecto, está cogiendo mi partición D (vacía). Va a crear una partición nueva: nvme0n1p6


Hasta aquí podemos retroceder todas las veces que queramos.

Le damos continuar y nos encomendamos a Linus Torvalds.

Primero va a pedir elegir si queremos descargar códecs, ingresar la contraseña del wifi, y el idioma del teclado (yo elegí Spanish LatinAmérica No Dead Keys), y los datos de nuestra cuenta de usuario:


A partir de aquí es darle "Continue". En mi caso la instalación demoró menos de diez minutos.


Al terminar la instalación yo le puse "Continue Testing" para poder apagar la laptop y quitar el USB.

Al iniciar nuevamente el sistema aparece este menú:


Todo bien y ya tenemos el el doble booteo Linux/Windows. Y pude confirmar que no tocó mi partición C:


La partición D quedó más pequeña porque ahí está la partición ext4 del Linux, sólo que Windows no puede verla, en cambio Linux sí puede leer y escribir la particiones NTFS ya por defecto.

Algo bonito: el Linux Mint tiene la misma combinación de teclas de Windows: 

Windows+D: mostrar escritorio

Windows+E: Abrir el explorador

Shift + Print Screen: Selecionar un área de la pantalla a copiar o guardar. En mi lenovo es Shiift+Fn+Print Screen

Tengo que probar aún Windows+Shiift+S que es para capturar áreas de la pantalla (update: abre las opciones de volumen)  y ver si me reconoce el scanner, pero eso es para otro día.

Update: Sí me lo reconoce!!

miércoles, 20 de mayo de 2026

Old web: Generador de Laberintos en Visual C# 2008

Basado en los códigos de Mike Gold 

https://www.c-sharpcorner.com/article/generating-maze-using-C-Sharp-and-net/

https://www.c-sharpcorner.com/article/eater-game-ii-the-stone-maze/ 

y el algoritmo de backtracking para generar un laberinto https://professor-l.github.io/mazes/ 

Este algoritmo de Python usa el pseudocódigo de una web que ya no existe pero que es la que usé para aprender la técnica https://gist.github.com/fitzterra/9491696 

Primero debía saber cómo "pintar" el laberinto, por ello busqué el evento "Paint" en el formulario (la ventanita) en el código de Mike:

El truco está en los objetos "g" y "e". El evento "Paint" se dispara al crear la ventana o maximizarla. Este evento recibe un objeto "e" del tipo PaintEventArgs con el cual creamos el objeto "g" del tipo "Graphics". Es con este objeto con el que se va a pintar el laberinto.

El código mostrado llama al método "Draw" ("TheMaze" es un objeto de la clase "Maze", creada por Mike e incluida en su código). 


El método "Draw" llama a otro método "Draw" en otra clase creada por Mike llamada "Cell". Nos vamos para allá:


He aquí el código para pintar o dibujar el laberinto. Todo se reduce a dibujar líneas con el método "DrawLine" del objeto "g". 

Yo empecé por dibujar una grilla, con todas las celdas del laberinto. Haría mi laberinto "tumbando paredes" en la grilla.

Como no entendí nada del código de Mike, y como ya estaba perdiendo mucho tiempo intentando entenderlo, supe que debía crear mi propio código. El método "Draw" de la clase "Cell" de Mike me dio otra pista: él declara cuatro paredes, entonces yo también debía crear cuatro paredes (y deduje que serían cuatro paredes por celda). Lo hice mediante esta estructura:


Luego creo una matriz de estructuras tipo "celda". Las paredes vienen determinadas por sus puntos cardinales. En un principio pensé hacerlos de tipo booleanos (true: hay pared, false: no hay pared) pero al seguir programando vi que era necesario declarar un tercer valor para los bordes. Un borde le dice al programa que no debe buscar celdas más allá porque no las hay, además de no tumbar esa pared.

Hice mi generador de laberintos un poco al estilo de Mike: creé una clase aparte llamada "Maze" con un método llamado "DibujarLab" que se llama desde el evento "Paint" del formulario. Y ahí se acaban las similitudes.

Y mi código se puede bajar de aquí :)

La variable "padd" determina el tamaño de las celdas que conforman el laberinto.

Acerca de la variable "PrimeraVez": Si su valor es falso, evitará crear una nueva matriz "celda" al minimizar y maximizar el formulario (en el evento "Load", "PrimeraVez" debe ser true), pero su valor se puede dejar como verdadero si se desea generar un nuevo laberinto cuando se minimiza y maximiza la ventana.

Para generar números aleatorios: Se tiene que usar la clase Random que viene con el .Net. Yo creé un objeto llamado "currentCelda" y es a partir de este objeto que se escoge la celda inicial y la celda siguiente (de las cuatro inicialmente disponibles) por donde se empezará a "tumbar paredes". Si se crea otro objeto aleatorio Random para escoger la celda siguiente (en el método "cogerCelda"), el laberinto no queda bien.

El método "cogerCelda" es donde se escoge la celda siguiente, la pared entre la celda actual y la siguiente es la que se tumbará. En realidad este método no sabe si hay 1,2,3 ó 4 celdas siguientes intactas. Sólo sabe que hay al menos una. "cogerCelda" es como el juego del bingo: no se detendré hasta que haya un ganador, es decir: no saldrá del bucle "while" hasta que el número aleatorio coincida con una celda con todas sus paredes intactas. Según su valor devuelto, se sabrá si se debe tumbar una pared Norte, Sur, Este u Oeste y cuál será la siguiente celda por donde se continuará tumbando paredes.

A la hora de dibujar el laberinto consideré el primer índice de la matriz "celda" como las filas, y el segundo como las columnas. Así a la coordenada "x" le corresponde el segundo índice (ubicación horizontal), y a la coordenada "y" el primer índice (ubicación vertical). El método DrawLine necesita estas coordenadas para determinar los puntos inicial y final de las líneas que dibujará. Es fácil confundirse. A mí me pasó.

Ahora un pantallazo de cómo queda el laberinto:



Bastante bonito, y fácil una vez entendido cómo funciona el algoritmo para generarlo. Así, que...

¿Por qué no hacerlo triangular?

Esta vez el número de columnas va aumentado a medida que el laberinto "crece". Por ello, en lugar de crear una matriz cuadrada, declaré lo que en inglés se llama "jagged array". Se trata de una matriz que puede tener distinto número de columnas por cada fila. La cantidad de columnas por fila está dada por esta fórmula, muy fácil de deducir en realidad:

n° de columnas = (2*n° de filas) + 1

El compilador prioriza multiplicaciones y divisiones por encima de sumas y restas, por lo que los paréntesis pueden omitirse. 

A la hora de generar la matriz "celda" sólo se tienen tres paredes por celda, por ello esta vez la estructura "celda" sólo tiene tres "puntos cardinales": L1, L2 y piso (lado derecho, lado izquierdo y piso). Dependiendo de su ubicación, las celdas podían tener el piso arriba o abajo, mientras que L1 y L2 no cambian su ubicación. 

Lo más difícil fue dibujar las celdas en el lugar que les corresponde pues el laberinto es triangular, mientras que el sistema de coordenadas en la ventana es rectangular. Para facilitarme las cosas, primero dibujé las celdas en un sentido, y luego las que están en el otro, así al final sólo se debe juntar todo (por ello hay dos bucles dentro del bucle principal en el método "DibujarLab"):


Tomé como origen de coordenadas el vértice superior del triángulo, ubicado en la coordenada=(ancho aproximado de la ventana /2, 0). Éste se va dibujando desde arriba y desde la izquierda. Ya con las celdas en su lugar y la orientación correcta (todos los índices empiezan desde cero) se puede aplicar el algoritmo para generar el laberinto. La base o "piso" de cada triangulito mide 2*padd (al igual que en el laberinto rectangular, la variable "padd" determina el tamaño de las celdas que conforman el laberinto).

El resultado es éste:


Por alguna razón siempre me sale que la última fila tiene una pared recta. No sé porqué, pero no importa, porque si se hace que el bucle principal (al que le corresponde la variable "i") en el método DibujarLab vaya de 0 hasta menos de "pisos-1" en lugar de "pisos":


Queda así:



"pisos" es la variable que determina el número máximo de filas que tendrá la matriz que genera el laberinto triangular.

lunes, 16 de febrero de 2026

Resucitando mi viejo scanner canon lide 110 en Windows 11

¿Cuándo compré este scanner? ¿2012? ¿cuándo lo usé por última vez? ¿en una laptop con Windows 10 allá por el 2024 que ni siquiera era mía?

Bueno, ahora tengo una laptop con Windows 11 y me pasó que tenía que digitalizar unos documentos. Así que me fui a la web de canon a bajarme el driver de mi viejo scanner

En la web de canon España y la de Europa me sale esto:


En la de estados unidos es lo mismo, no hay drivers para Windows 11.
Ya me ha pasado que los periféricos me han funcionado con drivers viejos en un sistema operativo más nuevo, esto fue en tiempos del Windows xp y 7.

Decidí irme a la web de canon Estados Unidos (por ser la más amigable) y bajarme el último driver para Windows 10. El enlace es:

Los datos del driver son:

File NameLiDE 110 Scanner Driver Ver.17.0.5 (Windows)
TypeDrivers
Date04.12.16
File Size9.16 MB



Funcionó y sin reiniciar la laptop, como prueba escaneé este dibujo:


He estado mirando Angel Hare. El dibujo es de Maddy, la protagonista del spin off "Your Angel's Here":


jueves, 16 de octubre de 2025

Ejemplo práctico de las diferencias entre variables recibidas por Referencia y por Valor en Java

Esta prueba la hice en java 11 y 17. Se basa en crear un ArrayList cuyos elementos son arrays, para estos ejemplos estoy usando IntelliJ:

public class Main {
public static void main(String[] args) {
String[] unArray = new String[] {"Tulio", "Bodoque", "Patana", "Juanin"};

List<String[]> unaListaDeArrays = new ArrayList<>();

unaListaDeArrays.add(unArray);

unArray[0] = "Cucky";
unArray[1] = "Joe Pino";
unArray[2] = "Horacio";
unArray[3] = "Pepe Lota";

unaListaDeArrays.add(unArray);

for (int i = 1; i < unaListaDeArrays.size(); i++) {
for (String s : unaListaDeArrays.get(i))
System.out.println(s + ", ");
}

System.exit(0);
}
}

Como los arrays son almacenados en el ArrayList por referencia (es decir que lo que se guarda no es el array, es su dirección de memoria) el resultado es:

He perdido a los presentadores y al productor de 31 Minutos y me he quedado sólo con los cantantes. Esto no puede ser. Si se almacenara por valor, el arrayList recibiría una copia de los arrays de forma automática, pero por diseño de la JVM no es así.

Para resolverlo hay que crear una copia del array unArray en memoria antes de añadirlo al arrayList, esto es muy fácil de hacer, una forma es usando el operador "new":

public class Main {
public static void main(String[] args) {
String[] unArray = new String[] {"Tulio", "Bodoque", "Patana", "Juanin"};

List<String[]> unaListaDeArrays = new ArrayList<>();

unaListaDeArrays.add(unArray);

unArray = new String[] {"Cucky", "Joe Pino", "Horacio", "Pepe Lota"};

unaListaDeArrays.add(unArray);

for (int i = 1; i < unaListaDeArrays.size(); i++) {
for (String s : unaListaDeArrays.get(i))
System.out.println(s + ", ");
}

System.exit(0);
}
}

Ya quedó bien:


Otra forma es usando la función clone() que poseen las variables que heredan de la clase Object como la clase String, esta función devuelve una copia del objeto:

public class Main {
public static void main(String[] args) {
String[] unArray = new String[] {"Tulio", "Bodoque", "Patana", "Juanin"};

List<String[]> unaListaDeArrays = new ArrayList<>();

unaListaDeArrays.add(unArray.clone());

unArray[0] = "Cucky";
unArray[1] = "Joe Pino";
unArray[2] = "Horacio";
unArray[3] = "Pepe Lota";

unaListaDeArrays.add(unArray.clone());

for (int i = 1; i < unaListaDeArrays.size(); i++) {
for (String s : unaListaDeArrays.get(i))
System.out.println(s + ", ");
}

System.exit(0);
}
}

El resultado es:


En mi caso tuve que usar el segundo método porque los valores del array de string eran devueltos por otra función y la longitud podía variar.

Hora de arreglar esos dos bucles anidados del final, para eso se pueden usar los streams de Java:

public class Main {
public static void main(String[] args) {
String[] unArray = new String[] {"Tulio", "Bodoque", "Patana", "Juanin"};

List<String[]> unaListaDeArrays = new ArrayList<>();

unaListaDeArrays.add(unArray.clone());

unArray[0] = "Cucky";
unArray[1] = "Joe Pino";
unArray[2] = "Horacio";
unArray[3] = "Pepe Lota";

unaListaDeArrays.add(unArray.clone());

unaListaDeArrays.stream().forEach(arr ->
Arrays.stream(arr).forEach(s -> System.out.println(s + ", "))
);

System.exit(0);
}
}


Resultado:




31 Minutos en el Tiny Desk de NPR