Friday, August 29, 2014

Reviviendo el pasado


 Internet es el depositario del presente y pasado de muchísimas cosas que los seres humanos hemos hecho y hacemos. Los contenidos, la información que desde hace siglos tenemos podemos encontrarlas ya muchas veces digitalizada. Los videos de años pasados, por ejemplo, la época dorada de Mtv, por ejemplo, se puede hallar en los depósitos de videos, como YouTube, por ejemplo.

Y quizás esto no parezca a las nuevas generaciones algo importante, pero el hecho de tener acceso a materiales que llevan muchos años y que finalmente han sido pasados a algún formato digital, es extraordinario, porque nos permite revisar con precisión cómo eran las anteriores generaciones, qué pasaba hace 30, 40, 50 años quizás, y así viéndolo en perspectiva, ver cómo hemos... ¿avanzado?

Y si hablo de esto es porque hoy me llamaron la atención sobre un hecho que me pasó. Dejé las llaves de mi casa en la mesa donde siempre se dejan y quedaron como se ve en la foto que ilustra este artículo. La llave más larga quedó "de pie". Y entonces recordé una vieja serie que veía de niño: "La Dimensión Desconocida". Me acordé de un capítulo que trataba de un tipo que compraba el periódico, tiraba la moneda con la que pagaba en una cajita que tenía el vendedor y la moneda caía de canto. Este hecho metía al protagonista de la historia en la "dimensión desconocida", en donde podía entonces leer la mente de los que tenía alrededor. Era sorprendente. Realmente podía leer lo que otros pensaban. Sin ahondar en la temática de ese particular programa, el efecto desaparecía cuando el mismo protagonista compra de nuevo el periódico, tira una moneda y ésta hace que la que está de canto caiga.


Hay otros capítulos memorables, como aquel donde sale Burguess Meredith, mucho antes de que fuese el Pingüino en la serie de Batman, en la cual representa a un cajero que le gustaba mucho leer y entonces, en el momento de su comida, se metía a la bóveda del banco a leer y comer un sandwich. Pero ocurre un cataclismo nuclear y cuando el personaje se recupera de lo que pasó, halla que es el único ser sobre la Tierra... Y empieza a deambular por la ciudad... Encuentra un arma pero desecvha la idea de matarse. De pronto encuentra la biblioteca pública y decide que ahora sí, tendrá todo el tiempo del mundo para ponerse a leer. Hace una estantería coon todos los libros que piensa leer de aquí hasta que se muera pero... Bueno, no les cuento el final.

Pero lo más interesante de esto es que de pronto hallé muchos capítulos completos (en español), del viejo programa, La Dimensión Desconocida, que en su momento fue uno de los mejores que hubo en la televisión. Es increíble pues que podamos acceder a estos programas de forma gratuita, porque alguien los puso en formato digital y de alguna manera hizo algo que es parte de la naturaleza humana, el querer conservar el pasado.

Los medios digitales nos están dando esta oportunidad dorada. Es en ese sentido un mundo extraordinario.

Muchos de los capítulos pueden verse aquí.

Wednesday, August 27, 2014

Que todo cambie para que todo siga igual


Hace un par de semanas ya, hubo elecciones de la Federación Internacional de Ajedrez. Competían para hacerse de la presidencia de este organismo, Garry Kasparov y Kirsán Ilyumzhinov, este último presidente ya de la FIDE por 19 años, con resultados bastante opacos, amén de que Ilyumzhinov es un personaje sinisetro en muchos sentidos (se le ha acusado de haber mandado matar a una periodista de la oposición cuando Kirsán era el presidente de Kalmikya), amén de sus declaraciones bizarras de que había sido abducido por extraterrestres y llevado a un viaje interplanetario. Ilyumzhinov dice de esta experiencia que le pidió a los extraterrestres que lo regresaran a su país, porque al día siguiente tenía que tomar un vuelo.

Pues bien, ganó Ilyumzhinov y mantendrá a la FIDE otros cuatro años bajo su control. En la asamblea donde los delegados de los diferentes países votaron, tuvieron la oportunidad de hablar por última vez, antes de la elección. Kasparov indicó que podía poner 10 millones de dólares desde ya para renovar a la FIDE y empezar con el pie derecho y con patrocinios millonarios. Ilyumzhinov en su turno dijo que podía poner 20 millones de dólares.

Y yo no sé si esta danza de millones de uno u otro candidato convenció a alguien, pero el hecho está en que Ilyumzhinov ganó y bueno, si ha prometido esta cantidad inmensa de dinero, deberíamos ver casi de inmediato resultados. Pero no, en lugar de eso nos acercamos a una bonita crisis en lo que se refiere al Campeonato Mundial, que debería disputarse en las tres primeras semanas de noviembre de este año. Magnus Carlsen, en campeón actual, pidió una postergación del match, que supuestamente se llevará a cabo en Sochi, en la sede de las olimpiadas invernales. Ilyumzhinov recvhazó la propuesta y el re-elegido presidente de la FIDE amenazó al Campeón Mundial sobre la obligación de firmar el contrato de la justa a llevarse a cabo en noviembre, so pena de quitarle el título de campeón mundial ppor no aceptar la reglamentación de la FIDE. Pero si esto fuese poco, Ilymzhinov, en una de sus típicas gracejadas, no declararía al retador, Viswanathan Anand como campeón del mundo, sino que pondría a jugar a éste con Sergei Karjakin, segundo lugar del torneo de candidatos en donde Anand obtuvo el derecho de retar al actual campeón, Carlsen.

¿Y los millones de dólares que prometió Ilyumzhinov? ¿Dónde están? ¿No podría poner parte de este dinero para tentar a los jugadores a dirimir el mundial en una sede mejor situada y más popular? Porque miren, hay reportes de que Sochi, después de que se acabaran las olimpiadas de invierno, se convirtió en prácticamente un pueblo fantasma. ¿Quién diablos quiere jugar en ese inhóspito sitio en donde irán un puñado de periodistas especializados y los jugadores con sus equipos de analistas? Si de por sí, el ajedrez es de difícil promoción, llevarlo a Sochi parece una estupidez, característica de un tipo como Ilyumzhinov.

Por otra parte, de nuevo la FIDE se muestra como autoritaria en lugar de ser un conducto para que el ajedrez internacional esté bien organizado. Cabe decir que la propia FIDE de Ilyumzhinov no logró que ningún país, ningún empresario con dinero siquiera, pujara para pedir la sede del campeonato mundial. Vamos, que se declaró desierta a pesar de haber ampliado el plazo. Eso habla del poco interés que las empresas y los patrocinadores parecen tener en el ajedrez. Y como bien diría el periodista español Leontxo García, "tenemos un gran producto, el ajedrez, el cual no sabemos vender o en el mejor de los casos vendemos muy mal".

Yo no entiendo para qué Ilyumzhinov insistió con estar cuatro años más en la FIDE si iba empezar su actuación (más bien continuarla), con semejante tropiezo político ante el evento que debería ser el más importante del ajedrez en el planeta: un campeonato mundial. La figura de campeón mundial debería tener algún peso, pero no, para Ilyumzhinov, acostumbrado a ser un dictador, esto no le parece importante.

En resumen, nos acercamos a una crisis que me parece va a terminar con quitarle el título de Campeón Mundial al joven talento Magnus Carlsen. Tengo la impresión que Ilyjmzhinov no cederá y que Carlsen en el fondo, siendo el mejor jugador del mundo, puede ignorarlos porque finalmente su calidad de juego habla por él. Sin embargo, es triste que regresemos a estas circunstancias en donde todo puede ponerse "patas para arriba" en un santiamén. La culpa de esto es de Ilyumzhinov y de esta FIDE dizque millonaria, que no sabe jamás qué hacer de forma correcta.

Saturday, August 23, 2014

Nuevo reto ¿de la programación lúdica?


Hace un par de sábados, en una de las reuniones de ajedrez que suelo tener ese día, estaba un palindromista famoso, Willy de Winter, Maestro Internacional de Ajedrez (ver foto más abajo), traductor perito y un especialista en idiomas (al menos cuatro y me quedo corto). En esa misma reunión de pronto apareció Merlina Acevedo, que ha sido en twitter todo un fenómeno por sus complejísimos palíndromas, por la longitud de los mismos, que rayan en la locura.


Ya aquí hablamos de Merlina y de los palíndromas en general, pero en esa reunión a la que hago referencia, le pregunté a Merlina si había palíndromas hechos con palabras y no letras. Vamos, que en los palíndromas normales, la unidad es la letra y por ello por ejemplo, "Sé verlas al revés"  (así podría definirse con un palíndroma al palíndroma), se lee igual de principio a fin y viceversa, pero ¿y si la unidad de estos palíndromas es la palabra?, por ejemplo: "Nuevamente comamos, bebamos, comamos nuevamente". Esto no es un palíndroma en donde se lee de derecho al reves en letras pero si la unidad no es la letra, sino la palabra, entonces estaríamos hablando de un "palíndroma de palabras" (no sé cómo  bautizarlo).

 Merlina me dijo que pensaba que si existían, tenían estos "seudo-palíndromas" ser palíndromas por sí mismos, por ejemplo: "somos seres somos", pero le puse un ejemplo: "político pinche, pinche político", y no se cumple esta condición que ella suponía que era obligatoria. Un par de días después, Merlina me mandó uno que halló, en inglés: "Blessed are they that believe that they are blessed" (que más o menos se traduce como esto: "Bendecidos son aquellos que se creen bendecidos" (que en español pierde la propiedad de ser palíndromas por palabras)... Después me mandó un mensaje que decía: "Afortunados no los que somos, ¿somos qué los no afortunados?", pero no convence. Y lo modificó de esta manera: "Afortunados no somos, somos no afortunados" y acto seguido en un nuevo mensaje me puso éste: "Afortunados no somos muchos, muchos somos no afortunados". Da la impresión que estos palíndromas hechos con palabras y no con letras son mucho más difíciles de hacer o peor aún, parece ser muy complejo expresar ideas tan sofisticadas como la propia Merlina ha hecho con los palíndromas originales en donde la unidad es la letra.


Merlina Acevedo, con su libro de palíndromas y aforismos


Así pues, en un intento de entender más este problema, el siguiente reto de la programacióbn lúdica no involucra a los programadores necesariamente, sino a todos aquellos que quizás tengan en ingenio para crear palíndromas con palabras y no con letras. Al mejor palíndroma de palabras que se me mande se ganará una taza con el logo de La Morsa, una gorra y un cuaderno de notas, donativo de Qualcomm más quizás un par de premios más de otros amigos que están colaborando en esta idea. Pueden mandarme sus palíndromas con palabras a morsa@la-morsa.com. El reto durará un par de semanas. Cabe decir que si no hay buenos palíndromas, el concurso quedará desierto, es decir, no se dará premio alguno, cosa que espero no pase.

Si el ganador es de provincia o fuera de este país, le mandaré una memoria USB de al menos 8 GB. Esto es porque el costo de enviar una taza es ridículamente costoso. Así que por quizás única ocasión, este reto de la programación lúdica no tiene que ver con programación de computadoras, sino con algo más sutil, el ingenio para crear palíndromas de palabras. Esperemos que así le entre más gente a los retos propuestos.

Sunday, August 17, 2014

¿Cuál es la mejor jugada, 1.e4 o 1.d4?


¿1. e4 o 1. d4?

Las dos jugadas más usadas en las partidas de ajedrez son las que se refieren al dominio del centro, a sacar las piezas rápidamente. De todas las jugadas de peones, 1.e4 o 1.d4 son las que más libertades otorgan a las otras piezas y de hecho, son las dos más usadas estadísticamente en la historia del ajedrez. pero... ¿cuál es mejor?

Para dar una posible respuesta -no definitiva- apelaré al artículo de Claude Shannon, el cual entre sus múltiples trabajo, en algún momento decidió incursionar sobre cómo debería programarse una computadora para poder jugar un ajedrez sensato, digamos que pudiese competir con los seres humanos, porque el escribir un programa que juegue simplemente al ajedrez, aunque juegue mal, no tiene ningún chiste.

Shannon escribió un artículo por los años cincuenta del siglo pasado, titulado "Programming a Computer for Playing Chess", en donde analiza a detalle lo que hay que hacer. Cabe decir que Shannon sí entendía bastante de ajedrez y tenía claras las ideas que quería plasmar en su eventual programa. Es importante decir que en ese entonces no se tenía acceso fácilmente a una computadora y además, ni siquiera existía el tema de la computadora personal. Pero debe quedar sin embargo algo claro: el artículo de Shannon es tan importante que prácticamente todos los programas actuales tienen muchas de las ideas que planteó el científico en su momento.

Sin ir a detalle sobre la idea de Shannon, propone éste una estrategia que le llamó tipo A, en donde a partir de una posición dada, se exploran todas las líneas de juego hasta una profundidad fija y se les asigna una puntuación al final de cada continuación. La puntuación  asignada a la posición se denomina hoy en día "función de evaluación" y es una medida de qué tan buena es una posición para el lado de quien le toca jugar. Para decidir esa puntuación, Shannon sugirió un número de factores que deben tomarse en cuenta:

  1.  Material: asignando a las piezas los valores tradicionales, Dama (D)=9, Torre (T)=5, Alfil (A)=3.5, Caballo (C)=3, Peón (P)=1 y Rey (R)=200 (no importa el valor del rey, porque si éste es eliminado se acabó la partida, lo que importa es que sea un valor mucho más grande que el de las demás piezas).
  2.  Formación de peones: castigo de 0.5 puntos por cada peón doblado (PD), aislado (PI) o atrasado (PB).
  3.  Movilidad: es deseable tener muchas jugadas disponibles para el jugador que le toca mover y pocas para el oponente. Shannon sugiere 0.1 puntos por cada jugada disponible (JD).

Basado en esto, la función de evaluación bien puede escribirse como:

f(posición) = 200 (R-R') + 9(D-D') + 5(T-T') + 3.5(A-A') + 3(C-C') + (P-P') - 0.5(PD-PD'+PI-PI'+PB-PB') + 0.1(JD-JD')

donde las piezas primales son las del enemigo. Así, un valor positivo significa que las blancas tienen ventaja, una valoración negativa implica que el negro tiene mejor posición.

Cabe decir que esta función elemental es bastante acertada en la mayoría de las posiciones que se dan en ajedrez, pero desde luego, hay tantas excepciones que hay que refinar mucho más dicha función. De hecho, esto es el secreto de los programas más fuertes y no se conoce en la mayoría de los programas comerciales.

Pero si tomamos el criterio establecido por Shannon, podemos decidir si 1.e4 es mejor que 1.d4. Después de 1.e4, las blancas tienen 30 movimientos posibles (contando incluso los del rey). Después de 1.d4 las blancas tienen una valoraciín menor en la función descrita por Shannon.

Thursday, August 14, 2014

Reto de la programación lúdica: protector de pantalla



Todos sabemos que los protectores de pantalla surgieron de la necesidad de evitar que las pantallas de rayos catódicos, como en las televisiones de hace unos años, “quemaran”  el fósforo de las pantallas y las dejara “marcadas”. Por ejemplo, me tocó ver monitores con las marcas típicas de los programas como las hojas de cálculo, en donde se observaba claramente una imagen fantasmal de cómo se veía el programa en cuestión cuando se utilizaba.

Por ello los protectores de pantalla existen, buscando resolver esta dificultad. Esto llevó, como evolución básica quizás, a la creación de protectores de pantalla que ponían imágenes en movimiento, animaciones, gráficas muilticolores que iban cambiando, etcétera, cuando finalmente el mejor protector de pantalla es el que se apague la pantalla hasta que el usuario toque alguna tecla, mueva el ratón o bien, toque el monitor en estas posmodernas interfaces táctiles.

Así entonces, en este reto de la programación lúdica buscamos un protector de pantalla orioginal, moderno, que aparte de cumplir con la tarea de evitar el desgaste innecesario del monitor, nos presente algo artístico, divertido tal vez. Ustedes -programadores- son quien deciden.

El reto implica hacer no solamente un programa que haga algo en la pantalla, sino que se pueda poner en el listado de los protectores de pantalla de Windows. No se trata de que me pasen un enlace a uno de los miles y miles de protectores de pantalla que ya han sido escritos, sino que la idea es que se programe,en el lenguaje que quieran, su propio protector.

En este caso no hay dificultades ni problemas para usar bibliotecas en su propia herramienta de programación. La condición sine qua non (es decir, obligatoria), es que el programa pueda ponerse en la carpeta donde residen los protectores de pantalla de Windows y pueda usarse como tal. Igualmente, el protector de pantallas debe ser para el sistema operativo Windows 7 en adelante.


Los protectores de pantalla son programas que en términos generales funcionan como cualquier ejecutable, aunque tienen un par de especificaciones que hay que tomar en cuenta.Una de ellas es que los archivos no son .exe sino .scr, pero me parece hay un par de cosas que hay que contemplar para hacer un protector de pantalla.  Sugiero le echen un vistazo a este enlace para resolver los detalles técnicos que tiene este tipo de programas.

Este tipo de programas, probablemente puedan encontrarlo en la red. No se trata pues de copiarlo de algún sitio. Si descubro una copia o si tengo dudas, me tomo la libertad de preguntarle al autor directamente cómo hizo, para garantizar así que la solución fue escrita y no copiada por el autor del programa. Juguemos pues limpiamente y aprendamos todos de estos retos.

¿El premio? Una taza con el logotipo de la Morsa a la mejor solución, en donde ganará el que visualmente sea más atractivo. Como esto es una cuestión subjetiva, un jurado calificado por los articulistas de unocero (más otros personajes externos [sus nombres se mencionarán al terminar el concurso]), serán quienes tomen la decisión y ésta es inapelable. Hay también una gorra y una libreta de notas, cortesía de Qualcomm (sólo para quienes residan en el DF). Habrá probablemente más premios, pero estos son los que están asegurados.

El premio de la taza (con el añadido de la gorra y el cuaderno de notas), solamente aplica a los programadores que vivan en el DF (mandar a provincia o a otros países una taza es estúpidamente costoso). En caso de que los concursantes sean de otros países o de la provincia mexicana, el premio será una memoria USB de 8 GBytes al menos y se les enviará por correo certificado.

Así que ¡manos a la obra! Sorpréndanme…

Tuesday, August 12, 2014

Angel Flores, Gabriela Retes, y una visita maravillosa

 Con Gabriela Retes, la hija del "bulto"

"El Bulto" es una película mexicana, del año 1991, dirigida por Gabriel Retes Mello. La trama -resume la Wikipedia- habla de Lauro (Gabriel Retes), un fotógrafo liberal e izquierdista que cubre El Halconaz. Es golpeado y entra en coma. Despierta después de 20 años, cuando su mujer se ha casado con otro y sus hijos entonces pequeños ya son adultos. Lauro tiene que acostumbrarse a la nueva cultura y ver a sus amigos convertidos en profesionistas y no en los jóvenes liberales que conoció.

El realizador aprovecha la apertura de los medios y del gobierno respecto a hechos pasados que antes eran censurados, en este caso El Halconazo, para hablar de ellos, denunciarlos, y ya no negarlos. Por otro lado, la película retrata la hipocresía de la sociedad mexicana y cómo la gente y sus ideales cambian y son absorbidos por «el sistema».


Pues hablo de esta película porque el domingo pasado fui con Pilar a Tepoztlán, en el Edo. de Morelos. La habían contratado para dar una función de teatro infantil. Llegamos a casa de Angel Flores Torres, el cual es cineasta, el cual a todo esto es ex-marido de Gabriela Retes, la hija de "el bulto".

La compañía "Arte para Chamacos y más..."

La verdad es que fue un domingo único. Angel es un tipazo. Sus tres hijas, Luciana, Sabina y Eloisa me parecieron encantadoras, inteligentes y además, muy educadas y cariñosas. Gabriela Retes estaba dando de desayunar junto con Pilar Campesino (una importante dramaturga amén de ser muy amable y agradable), a sus hijas cuando llegamos a su casa. Angel nos invitó a comer a su mezcalería (una hamburguesa de sirloin) y al final de la función -que se dio ahí mismo- nos invitaron a probar el mezcal. Y lo probé, aunque se demostró rápidamente que no sirvo como bebedor. Demasiado fuerte.

Pero más allá de la foto que me tomé con la hija del "bulto", y el día extraordinario que pasamos, me dejó un gran sabor de boca el ver que Angel busca que la gente de su comunidad tenga acceso a cultura más allá de lo que ofrece el gobierno y para ello, pone de sus propios medios. Se necesita mucha gente así en México y me congratulo de haber podido ir. Fue un placer y privilegio conocer a esta familia, a esta visión de gente del cine, en donde la cultura, la inteligencia, los contenidos importantes, están presentes todo el tiempo.

Con Angel Flores

Friday, August 08, 2014

Del pirateo de libros


Hace unos días vi en una página de ajedrez que iba a salir un libro sobre Nimzowitsch, llamado "Nimzowitsch, Move by Move", del MF Steve Giddins. Considerando que tengo un trabajo a medio terminar sobre el gran ajedrecista danés, nacido en Riga, pensé que éste sería un libro por adquirir. Entré entonces a Amazon y hallé que el libro se venderá en esta tienda virtual en un par de meses. En el Reino Unido saldría a principios de agosto. Así que lo puse en mi lista de deseos de Amazon y pensaba hacerme de él.

Pero resulta que en un sitio web al que entro, hallé que la versión electrónica (no PDF ni ePub, sino en formato Chessbase, que parece ser armada por la editorial que edita el libro), para ser descargada gratuitamente. Esto obviamente no es lo más legal del mundo y quiero suponer que alguien que compró la versión electrónica decidió hacerla pública y disponible para todos, pasándose por "el arco del triunfo" los derechos de autor de Everyman Chess y de Giddins.

El libro se ve interesante y cuando salga la versión en papel, la compraré, pero lo que me interesa es ver cómo las editoriales están ya, o empezarán pronto a estarlo, en desventaja ante la facilidad para publicar cualquier contenido en la red. No es el primer libro que se puede conseguir gratuitamente, ni será el último, pero esto habla claramente de que la situación de vender libros ha cambiado radicalmente con la llegada de Internet. De hecho es probablemente la industria editorial la última que ha tenido que empezar a lidiar con el problema de la piratería. Porque ahora no solamente hay quien en un ataque de tiempo libre inesperado, decide escanear un libro, página por página, y subirlo a la red, sino que no falta quien se hace de un libro electrónico, con DRM (derechos digitales de autor), el cual se pueden quitar si se sabe cómo, y entonces el libro queda a disposición de quien quiera descargarlo. Si además, como en el caso que menciono, el libro viene en formato para Chessbase (un manejador de base de datos de partidas), entonces el asunto no tiene vuelta de hoja: libro pirateado, lo que implica menos ganancias a la editorial y al autor.

Yo quisiera pensar que de todas maneras esto podría paliarse buscando de alguna manera un modelo de negocios que pueda satisfacer a todos, tanto editorial (y autor), como consumidores. Hay quienes a pesar de que sus libros están en PDF hacen dinero pues la gente compra sus libros. Un ejemplo es Adrián Paenza y su serie de libros de divulgación: "Matemática... ¿Estás ahí?". Se venden bien y probablemente se descarguen más aún. Es decir, el mecanismo quizás haga que el autor sea más popular y su libro o libros reciban más publicidad y por otra parte, la gente, al ver que el autor pone sus libros legalmente, decida comprárselos.


¿Qué hacer con este problema? No lo sé. Pareciera que muchos autores no tienen grandes preocupaciones al respecto. Sin embargo, es interesante hacer notar que por ejemplo, mi libro de Editorial Selector "Perfeccione su Ajedrez", se había descargado de uno de estos depósito de archivos públicos, unas 1000 veces. Es decir, son regalías que no recibiré y es dinero que la editorial tampoco recibirá.

Opino pues que se necesita un nuevo modelo de negocios. Sin duda Internet ha logrado cambiar el paradigma de cómo hacíamos antes muchas cosas y que hoy simplemente eso ya no funciona.

Tuesday, August 05, 2014

Una idea millonaria


Ahora que en estos pasados meses he tenido que hacer un sinfín de trámites, de papeleos, de conseguir el apostille de mi título, de hacer el TOEFL, de recuperar acta de nacimiento, tomarme fotos, recuperar los certificados de estudios anteriores, de hallar la fotocopia tamaño carta de mi título de licenciatura, etcétera, me di cuenta que este país no puede seguir haciéndonos esto. Me explico: por muchos años he trabajado en diferentes centros de la UNAM y en cada un de ellos he tenido que dar fotografías tamaño infantil con fondo blanco, actas de nacimiento, copias de mis certificados, y así hasta la náusea. Esto es ridículo. Las montañas de papel que se guardan en algo que se denomina eventualmente "archivo muerto", llenan gavetas y espacio en toda la UNAM. El papel tiene que protegerse además, de las inclemencias del tiempo, de las eventuales goteras en algún centro de trabajo, etcétera. Es decir, el papeleo genera muchos problemas de más.

Y he aquí mi idea, que me parece que podría ser un negocio millonario. Lo pondré a manera de pregunta: ¿Por qué la UNAM no tiene un servidor central de documentos digitalizados? Imaginen que ustedes se inscriben en la UNAM, entregan sus papeles. Estos se digitalizan y listo, cada vez que necesitemos en la UNAM algún papel o se nos requiera algún documento, la dependencia que nos lo pida podrá inmediatamente decirnos si ese documento ya se tiene o no.

Un servidor de documentos digitales suena a un buen negocio y si además, quien lo ofrezca da el servicio de escaneo, podría hacer muchísimo dinero. Y que conste, la UNAM es solamente un ejemplo, pero hospitales, instituciones gubernamentales, y cuanto centro de trabajo que se les ocurra, podría acceder a un servidor central de información. Díganme que no es una gran idea.

Monday, August 04, 2014

¡Buenas noticias!


Después de N trámites, exámenes y demás angustias, fui aceptado en el doctorado en ciencias e ingeniería de la computación, en la UNAM. Son 4 años que espero resulten muy fructíferos en términos académicos. El inicio formal del doctorado es precisamente ¡hoy!

Saturday, August 02, 2014

Ya tenemos ganador del reto de la programación lúdica sobre los laberintos


Hace ya un par de semanas pusimos en el reto de la programación lúdica, la creación de un laberinto. Hubo una discreta participación, la cual quiero creer, se debió en parte a que el reto sonaba demasiado complejo y aunque no lo era tanto, requería quizás de más horas de las que muchos podrían haberse ocupado para resolverlo. Se recibieron algunas participaciones que invalidé porque parecían copia de algún programa de Internet y ante mi petición de aclarar el asunto hubo incluso silencio. Y que conste, no estoy acusando a nadie, solamente que la idea de los retos es que los que participan los resuelvan porque ése es el chiste, amén de que en eso reside la diversión. Finalmente, hubo tres finalistas. Uno usó Java (Salvador González), otro Javascript (Gabriel Martínez), con ayuda de JQuery y un tercero, escrito en Delphi. La decisión no fue fácil pero me parece que el ganador hizo la versión más manejable y visualmente más adecuada a la interfaz gráfica. El ganador es pues Guillermo Cañedo y este es su código (en Delphi):
 
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Spin;

type
  TMurosSet = set of (arriba, abajo, derecha, izquierda);

  PCelda = ^TCelda;
  TCelda = record
      i, j, pos: Integer;
      visitado: Boolean;
      etiqueta: String;
      muros: TMurosSet;
      adyacentes: TList;
  end;

  PRef = ^TRef;
  TRef = record
      pos: Integer;
      muroComun: TMurosSet;
  end;

  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    Lienzo: TPaintBox;
    rens: TSpinEdit;
    cols: TSpinEdit;
    Label1: TLabel;
    Label2: TLabel;
    Button2: TButton;
    Label4: TLabel;
    procedure LienzoPaint(Sender: TObject);
    procedure rensChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    dx, dy: Integer;
    Q: TList;
    solucion: TStringList;
    verSol: Boolean;
    procedure calcTamCeldas;
    function ObtieneListaDeNodos: TList;
    function obtieneNodo(i, j: Integer): PCelda;
    function obtieneNodosAdyacentes(i, j: Integer): TList;
    function refCelda(i, j: Integer): Integer;
    procedure DFS(nodo: PCelda);
    procedure DerribarMuro(A, B: PCelda);
    function obtieneNodosPorDondePuedePasar(nodo: PCelda): TStringList;
    function HayHabitacionesF: Boolean;
    function getMuroRandom(nodo: Pcelda): PCelda;
    function obtieneHabitacionF: PCelda;
    procedure etiquetar(nodo: pCelda; etq: String);
    function obtieneMuroQueIntercepta(A, B: PCelda): TMurosSet;
    function Regresa: PCelda;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.LienzoPaint(Sender: TObject);
var
   i, j, rx, ry: integer;
   R: TRect;
   celda: PCelda;
begin
    R.Left := 0;
    R.Top := 0;
    R.Right := Lienzo.Width;
    R.Bottom := Lienzo.Height;
    Lienzo.Canvas.Brush.Color := clWhite;
    Lienzo.Canvas.Brush.Style := bsSolid;
    Lienzo.Canvas.FillRect(R);

    Lienzo.Canvas.Pen.Color := clBlack;
    Lienzo.Canvas.Pen.Width := 1; 
    if Q <> Nil then
      begin
          for i := 0 to (Q.Count - 1) do
               begin
                   celda := Q[i];

                   rx := celda^.j*dx;
                   ry := celda^.i*dy;
                   
                   if arriba in celda^.muros then
                       begin
                           Lienzo.Canvas.MoveTo(rx, ry);
                           Lienzo.Canvas.LineTo(rx + dx, ry);
                       end;
                       
                   if abajo in celda^.muros then
                       begin
                           Lienzo.Canvas.MoveTo(rx, ry + dy);
                           Lienzo.Canvas.LineTo(rx + dx, ry + dy);
                       end;

                   if derecha in celda^.muros then
                       begin
                           Lienzo.Canvas.MoveTo(rx + dx, ry);
                           Lienzo.Canvas.LineTo(rx + dx, ry + dy);
                       end;

                   if izquierda in celda^.muros then
                       begin
                           Lienzo.Canvas.MoveTo(rx, ry);
                           Lienzo.Canvas.LineTo(rx, ry + dy);
                       end;

               end;

           if (verSol) and (solucion.Count > 0) then
               begin
                   Lienzo.Canvas.Pen.Color := clRed;
                   Lienzo.Canvas.Brush.Style := bsClear;
                   Lienzo.Canvas.Pen.Width := round(dy/3); 
                   celda := Q[StrToInt(solucion[0])];
                   rx := celda^.j*dx;
                   ry := celda^.i*dy;
                   Lienzo.Canvas.MoveTo(round(rx), round(ry + dy/2));

                   for i := 0 to (solucion.Count - 1) do
                       begin
                           celda := Q[StrToInt(solucion[i])];
                           rx := celda^.j*dx;
                           ry := celda^.i*dy;
                           Lienzo.Canvas.LineTo(round(rx + dx/2), round(ry + dy/2));
                       end;
                       
                   Lienzo.Canvas.LineTo(round(rx + dx), round(ry + dy/2));

               end;
      end
    else
      begin

           for j := 0 to cols.Value do
               begin
                   Lienzo.Canvas.MoveTo(dx*j, 0);
                   Lienzo.Canvas.LineTo(dx*j, Lienzo.Height);
               end;

           for j := 0 to rens.Value do
               begin
                   Lienzo.Canvas.MoveTo(0, dy*j);
                   Lienzo.Canvas.LineTo(Lienzo.Width, dy*j);
               end;
            
      end;
end;

function TForm1.ObtieneListaDeNodos: TList;
var
   i, j: integer;
   P: PCelda;
begin
   Result := TList.Create;
   for i := 0 to rens.Value - 1 do
       for j := 0 to cols.Value - 1 do
           begin
              New(P);
              P^.i := i;
              P^.j := j;
              P^.visitado := false;
              P^.etiqueta := 'u';
              P^.muros := [arriba, abajo, derecha, izquierda];
              P^.pos := refCelda(i, j);
              P^.adyacentes := obtieneNodosAdyacentes(i, j);
              Result.Add(P);
           end;
end;


function TForm1.obtieneNodo(i, j: Integer): PCelda;
var
   k: integer;
   P: PCelda;
begin
   Result := nil;
   for k := 0 to (Q.Count - 1) do
       begin
           P := Q.Items[k];
           if (P^.i = i) and (P^.j = j) then
               begin
                   Result := P;
                   Exit;
               end;
       end;
end;


function TForm1.refCelda(i, j: Integer): Integer;
begin
  Result := i*cols.Value + j;
end;


function TForm1.obtieneNodosAdyacentes(i, j: Integer): TList;

    procedure Add(k: Integer; muro: TMurosSet);
    var
        P: PRef;
    begin
        New(P);
        P^.pos := k;
        P^.muroComun := muro;
        Result.Add(P);
    end;

begin

    Result := TList.Create;
    if i - 1 >= 0 then Add(refCelda(i - 1, j), [arriba]);
    if i + 1 <= rens.Value - 1 then Add(refCelda(i + 1, j), [abajo]);     if j - 1 >= 0 then Add(refCelda(i, j - 1), [izquierda]);
    if j + 1 <= cols.Value - 1 then Add(refCelda(i, j + 1), [derecha]);
end;

procedure LimpiaLista2(MyList: TList);
var
   i: Integer;
   ARecord: PRef;
begin
   if MyList <> Nil then
      begin
           for i := 0 to (MyList.Count - 1) do
               begin
                   ARecord := MyList.Items[i];
                   Dispose(ARecord);
               end;
           MyList.Free;
       end;
end;


procedure LimpiaLista(MyList: TList);
var
   i: Integer;
   ARecord: PCelda;
begin
   if MyList <> Nil then
      begin
           for i := 0 to (MyList.Count - 1) do
               begin
                   ARecord := MyList.Items[i];
                   LimpiaLista2(ARecord^.adyacentes);
                   Dispose(ARecord);
               end;
           MyList.Free;
       end;
end;

procedure TForm1.rensChange(Sender: TObject);
begin
   Button2.Enabled := false;
   verSol := false;
   LimpiaLista(Q);
   Q := nil;
   solucion.Clear;
   calcTamCeldas;
   FormResize(Sender);
   Lienzo.Refresh;
end;

procedure TForm1.calcTamCeldas;
begin
   // dx := Round(Lienzo.Width/cols.Value);
   // dy := Round(Lienzo.Height/rens.Value);
   dx := 12;
   dy := 12;
   Lienzo.Width := dx*cols.Value + 1;
   Lienzo.Height := dy*rens.Value + 1;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
   solucion := TStringList.Create;
   calcTamCeldas;
end;

function TForm1.HayHabitacionesF: Boolean;
var
   i: Integer;
   P: PCelda;
begin
    Result := False;
    for i := 0 to (Q.Count - 1) do
        begin
            P := Q[i];
            if P^.etiqueta = 'F' then
                begin
                    Result := true;
                    Exit;
                end;
        end;
end;


function TForm1.obtieneHabitacionF: PCelda;
var
   i: Integer;
   P: PCelda;
   L : TStringList;
begin

   L := TStringList.Create;
   for i := 0 to (Q.Count - 1) do
       begin
           P := Q[i];
           if P^.etiqueta = 'F' then L.Add(IntToStr(i));
       end;
       
   if L.Count > 0 then
       Result := Q[StrToInt(L[Random(L.Count)])]
   else
       Result := nil;
   L.Free;
end;

function TForm1.getMuroRandom(nodo: Pcelda): PCelda;
var
   i: Integer;
   Ref: Pref;
   vecino: PCelda;
   L : TStringList;
begin
   L := TStringList.Create;
   for i := 0 to nodo^.adyacentes.Count - 1 do
       begin
           Ref := nodo^.adyacentes[i];
           vecino := Q[Ref^.pos];
           if vecino^.etiqueta = 'I' then L.Add(IntToStr(i));
       end;

   if L.Count > 0 then
       begin
           Ref := nodo^.adyacentes[StrToInt(L[Random(L.Count)])];
           Result := Q[Ref^.pos];
       end
   else
       Result := nil;
   
   L.Free;
end;

procedure TForm1.etiquetar(nodo: pCelda; etq: String);
var
   i: integer;
   Ref: PRef;
   hijo: PCelda;
begin
   for i := 0 to nodo^.adyacentes.Count - 1 do
       begin
           Ref := nodo^.adyacentes[i];
           hijo := Q[Ref^.pos];
           if hijo^.etiqueta <> 'I' then hijo^.etiqueta := etq;
       end;
end;


function TForm1.obtieneMuroQueIntercepta(A, B: PCelda): TMurosSet;
var
    i: Integer;
    Ref: PRef;
begin
    Result := [];
    for i := 0 to A^.adyacentes.Count - 1 do
        begin
            Ref := A^.adyacentes[i];
            if B^.pos = Ref^.pos then
                begin
                    Result := Ref^.muroComun;
                    Exit;
                end;
        end;
end;

procedure TForm1.DerribarMuro(A, B: PCelda);
begin
    A^.muros := A^.muros - obtieneMuroQueIntercepta(A, B);
    B^.muros := B^.muros - obtieneMuroQueIntercepta(B, A);
end;

function TForm1.obtieneNodosPorDondePuedePasar(nodo: PCelda): TStringList;
var
   i: Integer;
   Ref: PRef;
   adyacente: PCelda;
begin
   Result := TStringList.Create;
   for i := 0 to nodo^.adyacentes.Count - 1 do
       begin
           Ref := nodo^.adyacentes[i];
           adyacente := Q[Ref^.pos];
           if (not adyacente^.visitado) and (Ref^.muroComun * nodo^.muros = []) then Result.Add(IntTostr(Ref^.pos));
       end;
end;

function TForm1.Regresa: PCelda;
var
   L: TStringList;
begin
   L := TStringList.Create;
   Result := nil;
   while (solucion.Count > 0) and (L.Count = 0) do
       begin
           Result := Q[StrToInt(solucion[solucion.Count - 1])];
           L.Free;
           L := obtieneNodosPorDondePuedePasar(Result);
           solucion.Delete(solucion.Count - 1);
       end;

   L.Free;
end;


procedure TForm1.DFS(nodo: PCelda);
var
   celda: PCelda;
   Childs: TStringList;
begin
   nodo^.visitado := true;
   solucion.Add(IntToStr(nodo^.pos));
   Childs := obtieneNodosPorDondePuedePasar(nodo);
   if Childs.Count > 0 then
      begin
          celda := Q[StrToInt(Childs[Random(Childs.Count)])];
          DFS(celda);
      end;
   Childs.Free;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  vecino, I, F: PCelda;
  Ref: PRef;
  k: Integer;
  val: Boolean;
begin
    Button1.Enabled := false;
    Button2.Enabled := false;
    verSol := false;
    if verSol then Button2.Caption := 'Ocultar Solución' else Button2.Caption := 'Ver Solución';
    Randomize;
    LimpiaLista(Q);
    Q := ObtieneListaDeNodos;


    I := obtieneNodo(Random(rens.Value), Random(cols.Value));
    I^.etiqueta := 'I';
    for k := 0 to I^.adyacentes.Count - 1 do
        begin
            Ref := I^.adyacentes[k];
            vecino := Q[Ref^.pos];
            vecino^.etiqueta := 'F';
        end;

    repeat
        F := obtieneHabitacionF;
        I := getMuroRandom(F);
        DerribarMuro(I, F);
        F^.etiqueta := 'I';
        etiquetar(F, 'F');
    until not HayHabitacionesF;


    //// BUSCA LA SOLUCION ////
    solucion.Clear;
    I := obtieneNodo(Random(rens.Value), 0);
    I^.muros := I^.muros - [izquierda];

    repeat
        DFS(I);
        F := Q[StrToInt(solucion[solucion.Count - 1])];
        val := (F^.j = cols.Value - 1);
        if not val then I := Regresa;
    until val;
    
    F^.muros := F^.muros - [derecha];


    Lienzo.Refresh;
    Button1.Enabled := true;
    Button2.Enabled := solucion.Count > 0;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
    solucion.Free;
    LimpiaLista(Q);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    verSol := not verSol;
    Lienzo.Refresh;
    if verSol then Button2.Caption := 'Ocultar Solución' else Button2.Caption := 'Ver Solución';
end;

procedure TForm1.FormResize(Sender: TObject);
begin
    Lienzo.Left := Round((Panel2.ClientWidth - Lienzo.Width)/2);
    Lienzo.Top := Round((Panel2.ClientHeight - Lienzo.Height)/2);
end;

end.
 
Cabe indicar que Guillermo mandó versiones mejoradas de tanto en tanto, las cuales optimizaron la solución, lo cual fue lo que finalmente decidió que se le otorgara el primer lugar. Guillermo Cañedo Ramírez, 44 años, estudió Ingeniería Eléctrica y una maestría en Sistemas Eléctricos de Potencia en el Instituto Tecnológico de Morelia. He aquí la descripción de lo que hizo: "La estrategia que seguí", nos dice, "está basada en 2 algoritmos:" Dependiendo del número de renglones y columnas que se quieran del laberinto, se define una matriz de m renglones y n columnas y se almacena toda la información en una lista dinámica con TList (disponible en Delphi) de apuntadores a una estructura de datos TCelda.

TMurosSet = set of (arriba, abajo, derecha, izquierda);

  PCelda = ^TCelda;
  TCelda = record
      i, j, pos: Integer;
      visitado: Boolean;
      etiqueta: String;   
      muros: TMurosSet;
      adyacentes: TList;
  end;
 
y la lista de habitaciones adyacentes apunta a una estructura de datos del tipo TRef.

  PRef = ^TRef;
  TRef = record
      pos: Integer;
      muroComun: TMurosSet;
  end;
 
Primero se etiquetan todas las celdas o habitaciones de la matriz con 'u'

 1) El Algoritmo de Prim's para generar el laberinto, es como sigue:
  • a) Elegir una celda o habitación al azar y etiquetarla como I,
  • b) Etiquetar las habitaciones adyacentes de I con F
  • c) Obtener al azar una habitación etiquetada como F y derribar el muro que colinda con la habitación I,
  • d) Etiquetar F como I y
  • e) Etiquetar las adyacentes del nuevo I pero que no sean I como F
  • f) Repetir del c) al e) hasta que ya no haya mas habitaciones F
2) El Algoritmo de Búsqueda Primero en Profundidad con retroceso para hallar la solución:
  • a) Etiquetar todas las habitaciones del laberinto como no visitadas.
  • b) Elegir al azar una habitación de entrada de la primer columna y se establece como entrada del laberinto, eliminando su muro izquierdo
  • c) Establecer la habitación como nodo raíz y marcarla como visitada y guardar la posición del nodo en una lista que sera la solución.
  • d) Obtener las habitaciones adyacentes que no estén visitadas y que no tengan muro colindante para poder pasar.
  • e) Elegir al azar una de ellas y de manera recursiva repetir de c) a e) hasta que ya no haya habitaciones adyacentes sin visitar y sin muro o que la columna del nodo raíz sea igual al total de columnas del laberinto
  • f) si e) no se cumple entonces ir en sentido inverso con nuestra lista de la solución e ir eliminando el ultimo elemento hasta que haya un camino por donde pasar.
  • g) Al finalizar se marca el último nodo de la lista con la solución como salida del laberinto derribando el muro derecho.
Actualmente desarrolla aplicaciones educativas y juegos para tabletas y smartphones en forma independiente en Taos Games. Felicitamos a Guillermo y vienen más retos, con más premios. Hemos estado trabajando con algunas empresas para que nos den apoyo, así que ahora, a redoblar esfuerzos porque los premios empezarán a ponerse más atractivos... Poco a poco, pero verán que empezarán a incrementarse.

A quien le interese el código de Guillermo y el de los otros dos concursantes, poueden escribirme a morsa@la-morsa.com y se los mandaré por si les interesa estudiarlo.

Friday, August 01, 2014

La privacidad en las redes sociales


Facebook es probablemente la red social más usada en el mundo y curiosamente, para poder entrar a ella -la mayoría de quienes ya lo hemos hecho- se nos pide que aceptemos una especie de largo contrato -el cual aceptamos- y listo: a navegar en la red social, compartir contenidos, fotos, mensajes, videos, etcétera. Desafortunadamente como no leemos este "contrato" aceptamos lo que Facebook hará con nuestra información sin previa consulta y si leemos lo que hacen con nuestros datos, en términos generales se reduce a "puedo hacer lo que quiera con ellos y sin consultarte". Vean nada más aquí y aquí.

El tema de la privacidad es algo interesante por muchas razones, la primera es que si no cuidamos este aspecto, nos exponemos en Internet a muchísimas dificultades. No falta quien hace uso de tus datos, de tus fotos, de tus datos personales. Hay quien no tiene empacho en poner que sale de vacaciones, a dónde va y cuando regresa. En esta época en donde la información es un bien valioso, hay que andarse con más cuidado.

Cabe decir que la privacidad no solamente es poner controles a quién puede ver nuestros contenidos porque no olvidemos que Facebook, dentro de su propio sistema, es el "gran hermano" al mejor estilo orwelliano, porque lo ve todo y además, lo guarda para sí todo: fotos, videos, mensajes, incluso reportes que se le hacen a la red social.

Pero ¿cómo debemos cuidarnos? La realidad es que no es difícil, y no se trata de poner controles para que otros no vean nuestros contenidos, cosa que desde luego, no es mala idea restringir. En realidad, sin embargo, lo más simple es seguir esta sencilla regla: "no publique en ninguna red social nada que no quiera que otros vean".

Pero más de uno puede preguntarse "¿Qué importa que otros vean mis contenidos? Finalmente el que nada debe nada teme". Pues sí y no. Es cierto que uno podría pensar que publicar una foto de la comida en un restaurante, o bien, fotos de un evento que ocurrió en la ciudad, una marcha por ejemplo, no tiene mayores consecuencias. Podría uno estar simplemente "documentando" lo que está pasando, ¿no? Pues no necesariamente. Considerando que en Estados Unidos la Agencia de Seguridad Nacional - NSA, vigila a mucha gente y que además, debido a los ataques a las Torres Gemelas en Nueva York en el 2001, en donde Bush emitió una ley sobre "homeland security", y gracias a esta ley prácticamente el gobierno norteamericano tiene derecho de entrometerse donde le dé la gana, cualquier actividad de cualquier ciudadano, la que sea, puede ser investigada.

¿Pero esto es sólo en Estados Unidos, verdad? Pues no, es en el mundo entero. Los norteamericanos han vigilado, lo sabemos por Snowden, incluso a presidentes de otros países, incluyendo Enrique Peña Nieto. ¿Y para qué nos vigilarían? Pues porque cada acción de cualquier ciudadano bien podría ser sospechosa.

La privacidad es algo importante. Uno puede pensar que como ciudadano normal promedio no tendría de qué preocuparse, pero seamos francos, ¿para qué darle argumentos a los "guardianes" del orden? Porque como están las cosas, sin duda hay que ser muy cautos con la información aque compartimos, incluso aunque supongamos que la compartimos solamente con quienes conocemos, cosa que en general no es cierto, aunque así parezca.

Sunday, July 27, 2014

¿Cuáles son las palabras diferentes en el Quijote?


Hace unos días se convocó al reto de hallar cuántas palabras diferentes tenía el Quijote, la obra de Cervantes, además de hallar la frecuencia de cada una de estas palabras. El reto, para un programador novicio puede parecer muy complicado, porque además se pide realizarlo en el menor tiempo posible. ¿Cómo se programa pues algo así?

Aquí la problemática se centra en la estructura de datos a usar. Por ejemplo, imaginemos que queremos usar un arreglo de palabras para irlas acomodando en la medida que las voy leyendo. El primero problema con esto es que no sabemos el total de palabras que hay por lo cual ¿De qué tamaño voy a hacer mi arreglo? Bueno, si el Quijote (como esá en el Proyecto Gutenberg) tiene unas 2 millones de letras, es razonable pensar que un 20% máximo serán palabras, más o menos 400 mil palabras.

Podemos crear un arreglo de 400,000 palabras y esperemos que esto sea suficiente, aunque en principio, sino sabemos cuantas palabras hay, estamos "adivinando" considerando que el promedio de letras de las palabras del español es menos de 10 letras por palabra. Pero esto último es una grosera aproximación a la cual estamos obligados si queremos usar la estructura de datos llamada arreglo.

Pero hay otra opción: usar estructuras de datos dinámicas. En este tipo de estructuras, lo que intentamos hacer es ir creando, en la medida de las necesidades, las estructuras necesarias, las cuales pueden crecer en la medida que lo vamos requiriendo. Dicho de otra manera, si necesitamos una nueva variable para alojar un dato, creamos esa variable en tiempo de ejecución, en el momento, de forma dinámica pues.

Una estructura de datos dinámica, muy poderosa, es la de los áerboles binarios. En una estructura de esta naturaleza tenemos un nodo y dos ramas. En el nodo tenemos la información y en las ramas tenemos apuntadores a otros nodos o bien a NIL, el vacío (es una manera en cómputo de no apuntar hacia la nada).

La técnica para ir creando un árbol binario es así: Consideremos que tenemos una lista de números desordenada: 60, 41, 74, 16, 53, 65, 25, 46, 55, 63, 70, etcétera. Tomemos el valor y pongámoslo en el nodo raíz. Ahora tomemos el siguiente valor, en este caso el 41. Si el valor es menor al que está en el nodo raíz, entonces lo colocamos en la rama izquierda, si es mayor, lo colocamos en la rama derecha., Así, ponemos el 41 en la rama izquierda. Acto seguido tenemos el 74. ¿Dónde lo pondremos? En la rama derecha del nodo raíz. Muy bien hasta aquí, pero de pronto tenemos un número más, el 16. ¿Dónde habremos de ponerlo? Tomamos el nodo raíz y vemos que es 60, así que debe ir en la rama izquierda, pero ésta ya tiene el nodo 41. De nuevo entonces vemos que el 16 es menor que el 41 y lo colocamos en la rama izquierda de éste. Con este procedimiento podemos llegar a llenar el árbol binario (porque solamente tiene dos ramas en cada nodo).



Nótese que un árbol de esta naturaleza además nos da una manera intrínseca de ordenar información. Si queremos desplegar los números que están en este árbol de manera que queden ordenados de menor a mayor, lo que hacemos es muy simple: Partimos del nodo raíz y nos movemos hasta la última rama izquierda posible. Esto nos dará, de acuerdo a la imagen que hemos puesto, en el número 16. Entonces vemos si este nodo tiene rama derecha. Sí, la tiene, y es el 25. Entonces ponemos como primer nímero el 16 y después el 25. Nos hacemos un nodo atrás y hallamos el 41. Lo ponemos. vemos si tiene rama derecha. Sí, la tiene, es el 53, pero éste tiene una rama izquierda, que es el 46 y este nodo a su vez tiene la rama izquierda cone l valor 42. Entonces ponemos el 42, 46, 53 y ahora revisamos la rama derecha y hallamos que hay un 55. Por lo tanto la lista va quedando así: 16, 25, 41, 42, 46, 53, 55... Y ahora ya no hay más ramas izquierdas que revisar. Pasamos a la rama derecha del nodo raíz y hallamos que hay un 74. Pero éste tiene un nodo izquierdo, el 65, que a su vez tiene otro, el 63, que a su vez tiene otro más, el 62, por lo que pondremos, 62, 63 y ahora vemos si hay nodo derecho. Y sí, lo hay, el 64. Ponemos ahora el 65 y como tiene rama derecha, ponemos el 70 y finalmente el 74.

Si queremos ordenar el árbol de los números mayores a los menores, lo que tenemos que hacer es recorrer el árbol al revés, primero empezar por la rama derecha. Esto es increíble. La misma estructura nos permite ya dejar ordenados literalmente los datos sin necesidad de otras estructuras.

Pues bien, una vez que tenemos esto aclarado, podemos crear un árbol binario con las palabras del Quijote. Si es una nueva palabra, creamos el primer nodo. Si es una palabra que es menor que la palabra que está en el nodo raíz, la ponemos en un nuevo nodo, que cuelga de la rama de la izquierda, en caso contrario, de la rama derecha.

Pero ¿cómo puedo crear una estuctura de un árbol binario? La manera más simple es crear una estructura dinámica, que crece en la medida que lo necesitamos. Por ejemplo, en Delphi, (Pascal) primero definiremos la estructura arbórea:


 nodoptr = ^nodo;  //el apuntador del nodo apunta a un nodo
       nodo = record  //esta es la definición del nodo
                algúndato: string; //palabra a guardar
                izquierda, derecha: nodoptr;
              end;


 Esta definición siempre parece costar trabajo leerla, y la razón es que es la única vez que Pascal permite usar algo que aún no hemos definido. Así, nodoptr = ^nodo; pero nodo no ha sido aún definido. De hecho, se define inmediatamente después.

Una vez teniendo la estructura dinámica, Delphi (Pascal), nos permite crear una nueva instancia de la misma si la necesitamos.

Por ejemplo, definamos

var
       arbol     : nodoptr;

Esto es precisamente el árbol en donde iremos colocando las palabras que vayamos leyendo del Quijote. Necesitamos para ello, un procedimiento para insertar nuevos nodos y poner los valores en los mismos. Esto lo podemos hacer así:

procedure insertaarbol(astr: string; var tree: nodoptr);
     { este procedimiento crea el árbol binario en memoria, 

        insertando un nodo en la posición correcta }

    begin
      if tree = nil then  //si el árbol esta vacío...
        begin
          new(tree);
          tree^.algundato := astr;
          tree^.left := nil;
          tree^.right := nil;
        end
      else
        begin
          if astr > tree^.algundato then
            insertaarbol(astr, tree^.right);


          if astr < tree^.algundato then
            insertaarbol(astr, tree^.left);
        end;
    end;


Con esto ya tenemos con qué trabajar. Es la rutina imprescindible para ir creando loas nodos (con sus respectivas ramas izquierda y derecha). Ahora hagamos la tarea: leamos el archivo del quijote, que está separado por líneas. Cada línea puede contener un número finito de palabras. He aquí el código (que se echa a andar cuando damos click al botón):

 procedure TForm1.Button1Click(Sender: TObject);
  var
    Linea   : ansistring;
    Palabra : ansistring;
    j       : integer;

   begin
   arbol := nil;
  
    assignfile(afile, Path+'palabras.txt'); 

//donde vamos a guardar las palabras halladas
    rewrite(afile);
    assignfile(infile, Path+'quijote-sin.txt'); 

//que archivo vamos a leer
    reset(infile);
    j := 0;

    repeat
      Readln(infile,Linea); //leo línea del texto
      for i := 1 to WordCnt(Linea) do
      begin
        Palabra := ExtractWords(i,1,Linea);
        Palabra := Lower(Palabra);
        inc(j);
        insertararbol(Palabra, arbol);
      end;
    until eof(infile); //hasta que leamos todo el texto

    writeouttree(tree);  //escribimos a disco el árbol
      //writeln;
      closefile(afile);
      closefile(infile);
      deletetree(tree); //borramos la estructufra binaria
      ShowMessage('Hay' + inttostr(j)+ ' palabras diferentes en el Quijote');
end;



Esto nos indica que el Quijote tiene 384,123 palabras en total (¿diferentes? unas 30 mil). El programa crea un archivo con todas las palabras (una por línea) y las despliega en orden alfabético, de menor a mayor, de la A a la Z, pues.

La rutina que crea este archivo es la siguiente:

procedure writeouttree(tree: nodoptr);
    {Copia a disco el árbol binario ya ordenado }
    begin
      if tree <> nil then
        begin
          writeouttree(tree^.left);
          writeln(afile, tree^.algundato) //escribe en archivo

          writeouttree(tree^.right);
        end;
    end;


Nótese que esta es una rutina recursiva (se llama a sí misma), que permite imprimir todas las palabras diferentes del Quijote en un archivo.

¿Cuánto creen que tarda en esta labor? ¡Alrededor de un segundo!

El reto propuesto es más interesante. No basta con saber cuáles son las palabras diferentes en total que tiene el Quijote, sino también su frencuencia. Aquí necesitamos entonces hacer dos cosas. La primera es que el nodo contenga no sólo la palabra del texto, sino las veces que la vamos encontrando, algo así como una variable que vaya incrementándose cada vez que encontremos dicha palabra. Por ello, requerimos de un procedimiento más: uno que busque un nodo y pueda modificar los valores del mismo.

No lo voy a hacer aquí. Si el amable lector me ha seguido hasta este punto, seguro puede hacer fácilmente esta rutina ¿verdad?

Friday, July 25, 2014

El inevitable pirateo


Hoy en día pareciese que el problema del pirateo de música es tan común que ya nadie dice nada. Si nos subimos al Metro, por ejemplo, nos hará encontrar casi por definición a algún “vagonero” que vende todos los “exitos de José José” (o Luis Miguel), por la irrisoria cantidad de diez pesos. Si uno decide comprar el disco en cuestión, el vendedor incluso lo garantizará. Y yo entiendo que la industria del disco debe estar haciendo berrinches incontables por esto, pero evidentemente no hay nada que hacer. Controlar que la gente no se copie la música parece ser tan complicado como evitar que se copien películas en DVD o incluso Blu-ray.

Pero aparte de esto, otro componente de la piratería es el que se refiere a los libros. Con la llegada de los formatos electrónicos, ePub y PDF, por ejemplo, muchas obras ya han sido pasadas a este tipo de archivos electrónicos. Ahora mandar un libro por correo electrónico o usando los servicios de mensajería que ofrecen sistemas como HighTail, por ejemplo, resulta algo fácil de hacer.

El inicio del pirateo de libros se basa en la capacidad de las cámaras digitales para fotografiar página por página, o bien, a los “scanners”, que son como fotocopiadoras personales. Pero para ello había que hacer dos cosas: una era tener una buena cámara digital o un dispositivo que escaneara los libros hoja por hoja. Esta última labor resultaba bastante fastidiosa, pero si se quería escanear un libro completo, se podía hacer. De hecho, con esta tecnología “casera”, surgieron programas que permitían poner todas las fotos automáticamente en un archivo PDF y listo, teníamos un nuevo libro digitalizado.

Es fácil y económico hacerse de un dispositivo para escanear libros. La mejor opción es sin duda el usar una buena cámara digital. Sin embargo, tenemos el caso de Amazon, que con su Kindle, vende versiones electrónicas de muchos libros y estas parecen estar a buen resguardo de los piratas, porque aparentemente, no se pueden copiar a otros dispositivos. Corrijo: bueno, sí se pueden copiar a otros dispositivos, pero sólo funcionarán con el Kindle (o la versión de software para PC), del que los haya comprado. Si se dañan o si el disco duro que los contiene se echa a perder, Amazon los tiene en su nube y de nuevo podría uno descargarlos pero de nuevo, no se pueden compartir estos libros electrónicos con otros dispositivos.

Hay torrents en donde se supone, hay muchos libros a los cuales se les ha quitado los trucos que Amazon ha puesto para que solamente el dueño legal de un libro pueda leerlos. No sé si existan todos esos libros o sea simplemente un anzuelo para caer en algún desagradable virus o en el infame “adware”. Ahí cada quien tomará sus riesgos y sus decisiones. Sin embargo, es evidente que aparte de los libros, las películas, el software y los programas de televisión, ahora los libros se incorporan a la piratería.

¿Qué se puede hacer? Probablemente nada realmente. La piratería siempre existirá y quien no haya pirateado un contenido de otro, que lance el primer CD. Tal vez el único remedio sea cambiar el modelo de negocios. Apple, cuando sacó su tienda de músicas vendió el primer día un millón de dólares (dicen), a un dólar por canción. Este modelo hace que ya la gente no compre un disco por 15 dólares donde al consumidor lo único que le interesa es una o dos canciones de ese disco en particular. Pero es claro que la gente estaría dispuesta a comprar música si se le da una buena opción en costo.  Con este mismo criterio, con los libros podría hacerse algo parecido. Hoy en día en Amazon un libro en papel puede costar -digamos- 15 dólares, pero el mismo libro en formato electrónico cuesta 14.50 o mínimo 13.50 dólares. Esa diferencia entre formatos no es suficiente para pensar en comprarlo en el formato electrónico. Si un libro en papel cuesta 15 dólares, la versión electrónica quizás podría  costar 4 o 5 dólares. Ya aquí las diferencias parecen significativas y quizás sea la solución al problema de la piratería. A la gente, si se le da un precio razonable, comprará los productos.

Amazon se tomó el camino complicado, el de los derechos digitales, el de las codificaciones de cada libro para personalizarlo con el autor. Es una brecha llena de dificultades técnicas, amén de que incluso los lectores que compren libros así pueden hallar problemas. Puedo entender que no será fácil convencer a las editoriales de cambiar el modelo de negocios, pero como con la música, o cambian el modelo de ventas o serán pirateados sin misericordia. y se acabará el negocio.

Wednesday, July 23, 2014

Murió Joaquín Araiza


El Maestro Nacional y parte de una familia de grandes y entusiastas ajedrecistas, murió el 14 de julio. Tenía -me dicen- 75 años y aparentemente en los últimos meses ya padecía de algunos problemas de salud xe cuidado. Su padre, el Coronel José Joaquín Araiza fue, en su momento, uno de los mejores jugadores mexicanos. Participó en torneos como el de San Remo, 1930, en donde quedó en décimo primer lugar. Esta competencia la ganó Alexander Alekhine, ni más ni menos.

Tengo buenos recuerdos de José Joaquín Araiza y creo que solamente jugamos una partida en todos los años que competimos. He aquí el desarrollo de la misma.

López, Manuel - Araiza, José Joaquín
Campeonato del Club Pomona, 1980
(3 de octubre de 1980)

1. e4 c5 2. Nf3 Nc6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 e5 entrando en la polémica variante Svesnikov, la cual genera juegos de gran desequilibrio. 6. Ndb5 d6 7. Bg5 a6 8. Bxf6 (es más flexible 8. Na3) 8... gxf6 9. Na3 f5 (9... b5 es más popular, pero claramente con la jugada de Araiza, se busca iniciar el conflicto central, amén de deshacerse de su peón doblado.) 10. Bd3 fxe4 (no es la mejor elección. De nuevo parece más elástica primero 10... b5) 11. Bxe4 d5?!

  
Juegan las blancas

Extraño sacrificio para abrir líneas, pero no queda claro por qué entregar un peón central. La teoría no consigna esta jugada y probablemente la razón es que sea mala. En el mejor de los casos el sacrificio es dudoso. 12. Qxd5 (Parece preferible 12. Bxd5 o incluso 12. Nxd5) 12... Be6 increíble, Komodo 6 indica igualdad completa (0.00) 13. Qxd8+ Rxd8 14. Rd1 Bxa3 con esta jugada parece ser que la posición llevará a unas tablas poco interesantes. Esto es lo que después me dijo Araiza que tenía en mente cuando jugó 11. ... d5. 15. Bxc6+ bxc6 16. Rxd8+ Kxd8 17. bxa3 Rg8 18. g3 Rg4 19. Kd2 Rc4 20. Re1 Rc5 21. Re4 Bf5 En esta posición ofrecí el empate, aunque ya Komodo 6 da 0.75 de ventaja al blanco. Dicho de otra manera, debí continuar jugando. 0.5 - 0.5

Descanse en paz el Maestro José Joaquín Araiza

Tuesday, July 22, 2014

¿Cuánto sabemos de la Naturaleza?


La física que conocemos parece admirablemente poderosa. Hemos llegado a entender muchísimos fenómenos. Eisntein nos demostró que el espacio-tiempo se curva y nos hizo ver resultados que al principio para todos fueron prácticamente paradojas. El modelo de la mecánica cuántica, por ejemplo, que creo sigue la interpretación de Copenhagen, parece ser bastante adecuado y es capaz de predecir un sinfín de eventos. Quizás es la teoría más elaborada del ser humano.

Y si hablo de esto es que a la luz del artículo sobre la cuantización del tiempo, me surge una nueva reflexión que ahora comparto. Si es cierto que el tiempo de Planck, el cual es 5.39106 x10-44 segundos, y esto es, de acuerdo a la Wikipedia: "representa el tiempo que tarda un fotón viajando a la velocidad de la luz en atravesar una distancia igual a la longitud de Planck". Podemos pues pensar que el tiempo está cuantizado y se mueve en intervalos de 5.39 x 10-44 segundos. Más allá de eso no tiene sentido el tiempo y tampoco hablar de fenómenos físicos.

Pero lo que me interesa es la persistencia de las leyes de la física. Métanse a la regadera y abran la llave... ¿Cuánto tarda el agua en darse cuenta que está en presencia de un campo gravitacional (que hace caer el agua hacia abajo)? Porque debe haber una interacción entre el campo gravitacional y el agua, ¿no? Vamos, que no estamos hablando de una interacción instantánea. Son dos componentes de un sistema que interactúan entre sí y por lo tanto, debe pasar cierto tiempo para que el campo gravitacional ejerza su acción sobre el agua.

Desde luego que para los tiempos de los seres humanos, el agua se da cuenta "instantáneamente" del campo gravitacional terrestre y nos parece natural que caiga el agua, pero ¿qué hay de esa interacción? ¿cómo surge? ¿cómo se da cuenta uno del otro? ¿Ocurre en el tiempo mínimo de Planck o bien, pasan una cantidad n de unidades de tiempo de Planck, cronones, para que el campo tome la acción correspondiente. ¿Cuántos cronones se requieren para que la interacción se dé?

Eso me parece que ni siquiera lo contempla la física que conocemos. Por ejemplo, entendemos los mecanismos y hemos los seres humanos creados leyes que modelan este universo en el que nos ha tocado vivir, que tiene unas reglas inamovibles aparentemente y además, que persisten en su actuar pase lo que pase.

La pregunta, que ya se han hecho muchos otros antes que yo es: ¿Cómo sería el Universo si las leyes fuesen otras? Por ejemplo, sabemos que la Ley de la Gravitación Universal, en el denominador, r2, ese es un dos. No es 1.99999 o 2.00000001, por decir algo, es un 2 seco, certero. ¿Por qué? Y voy más allá, ¿estamos por el camino correcto para hacer un modelo de este universo en el que vivimos? porque... ¿cómo puede ser que la interacción de campos con otros componentes requiera de tanta herramienta matemática para modelarlo? ¿estamos haciendo algo mal? ¿o quizás nuestras matemáticas son muy rudimentarias para explicar las cosas?

Por el momento al menos, creo que la fisica sólo describe el Universo, pero en realidad, estamos lejos de poder explicar por qué es así.

____
(*) La fantástica foto que ilustra este artículo es de 1931. Aparecen: Nernst, Einstein, Planck, Millikan y Laue.

Monday, July 21, 2014

La moda de los vloggers


Hoy en México hay dos temas que parecen acaparar la atención de los Internautas: las redes sociales y los vloggers. De lo primero ya se ha dicho mucho, pero sobre el segundo tópico, los vloggers, parece que se han puesto de moda entre los usuarios de Internet, menores de 30 años, logrando millones de visitas por semana. Esto significa -finalmente- que estos personajes que han nacido gracias a la plataforma que es YouTube, pueden incluso de vivir de hacer videos (pues hay patrocinadores, anunciantes, etcétera), en donde narran sus experiencias, hacen bromas, insultan, o demuestran que casi cualquiera puede volverse una "estrella" en Internet.

La idea de los vloggeros se parece en cierta medida a lo que Adal Ramones hacía en su programa de televisión, en donde tenía una sección llamada "el monólogo", en donde nos recetaba toda clase de supuesta sabiduría contemporánea, reflexionando, supuestamente de forma graciosa, lo que ocurría en la vida cotidiana. Algo así como lo que hacía Seinfeld inteligentemente en su programa de televisión, nada más que en región 4.

La cosa es que empezaron a salir una serie de jóvenes, mujeres y hombres, los cuales -aprovechando que no hay censura- grabándose en video y platicando de cuanto tema supérfluo se puede hallar en la red. Tenemos por ejemplo al Werevertumorro, Gabriel Montiel, el cual tiene -asómbrense- más de 5 y medio millones de suscritos a su canal de youtube y unas 909 millones de vistas de sus videos en total. Dicen que es el vloguero más famoso y popular de este país.

Están también algunas mujeres: CaeLIKE, que es una chavita que habla de los temas que les interesan a personas como de su edad: la escuela, las novias, la infidelidad del novio en turno, etcétera. Ella tiene más de 2.5 millones de suscriptores y unas 201 millones de vistas de sus video. Otra más es una jovencita, Yuya, que habla de maquillaje, de cómo vestirse para cada ocasión, etcétera. Han aparecido mujeres jóvenes menos tontas y más atractivas, haciendo algo parecido a las mencionadas, como Yosstop (una guapa mujer llamada Yosseline Hoffman) y Daniela Bos, las cuales hacen vlogs a veces muy cortos porque la verdad, hay tantos que quieren vivir de esto que empieza a saturarse el mercado y cada vez es más difícil ser original. Y aunque su belleza seguramente será argumento para tener muchos fans masculinos, me parece claro que tampoco hacen nada maravilloso u original.

Sin duda que la facilidad para grabarse, incluso hacer post-producción con herramientas de edición no lineal de video en casa, han sido parte del posible éxito de todos estos vlogueros. Un tema sin efectos especiales, sin manipulación de la imagen que presentan (poniendo letreros, modificando la voz, etcétera), suele empezar a aburrir a los que lo ven, por lo que si se quiere triunfar en este rubro no basta con salir a cuadro diciendo un sinfín de tonterías. Es importante también la post-producción.

Hay más vlogueros pero la verdad, ver uno solo de sus videos a veces es suficiente para no ver a esos personajes más. Entre ellos están Luisito Rey, Héctor Leal (un chavo de Reynosa, Tamaulipas), Benshortstuff, el cual es prescindible 100%, el Escorpión Dorado, hermano de Gabriel Montiel, que se pone una máscara de luchador y propina todo género de insultos vulgares, pretendiendo ser gracioso. Está otro tipo llamado Yayo Gutiérrez o Misael vlog (hermano de Caeli), Hola, soy Germán,  o Jacobo Wong, que su supuesto exito es contar chistes, en los cuales votan sus fans... Háganme el favor.

Y por supuesto no falta alguien, mayor de 30 años, -el Maicanal- que decide incursionar en esto. Un padre de familia, representante de la clase trabajadora, albañil, que cada semana sale vestido con la camiseta del Cruz Azul y muy a su estilo, comenta la problemática actual. Hay albures, mentadas de madre, etcétera. De nuevo totalmente prescindible.

Y seguro hay más, pero esto es sólo una prueba de que Internet puede ser un gran invento, pero es responsabilidad de cada quien filtrar los contenidos para que la basura no nos llegue, al menos no tan cerca. Hoy se habla de la "caja boba", refiriéndose a la televisión, que mucha gente dice no ver, pero lo más probable es que ahora su tiempo lo pierda con toda este catálogo de chavos dizque "cool" y graciosos,  en donde su gracia está en hablar con groserías y dizque hacernos reír de sus monólogos.

Saturday, July 19, 2014

De la ética médica


Yo siempre he pensado que el dinero gastado en la salud es dinero bien gastado, pero claramente en este país de tantas diferencias sociales, hay una línea divisoria entre la medicina de calidad y de no calidad. Es conocido que el gobierno tiene una infraestructura que deja mucho que desear en lo que se refiere al sistema de salud de México y que muchas veces los ciudadanos tenemos que irnos al sistema de medicina privado, con los subsecuentes costos, que muchas veces no son pocos.

Porque miren, un día tengo inflamado el colon y voy con un especialista en Médica Sur. Sin duda un estupendo médico al cual le tengo confianza sobre los diagnósticos que me da (que lo ha hecho en un número de ocasiones), y en lo que me receta. Sin embargo, en la práctica privada ocurren cosas interesantes de mencionar. Por ejemplo, cualquiera de nosotros podemos ir a un hospital privado, hacer una cita en la torre de consultorios de las diversas especialidades que ahí se manejan y un doctor con las calificaciones adecuadas nos atenderá. En muchas ocasiones ocurre que después de explicarle el problema por el cual acudimos con él, el médico nos pide que nos hagamos, por ejemplo, un estudio de laboratorio. Puede ser análisis de sangre, de orina, una tomografía quizás, una colonoscopía o un ultrasonido de vesícula, entre tantos estudios que hay. Y así termina la primera consulta. Sale uno y paga un promedio de 1200 pesos, aunque en ocasiones son 1500 por ser primera vez que nos atiende este galeno). El doctor espera entonces que cuando tengamos los resultados de los estudios, vayamos a una nueva consulta para entonces diagnosticar y recetarnos.

Primera pregunta: ¿Por qué me cobra esta primera consulta? O bien, ¿me cobrará la consulta que haré con él cuando tenga mis estudios? Lo más probable sino es que lo más seguro, es que la segunda consulta se cobre igual que la primera. Y yo me pregunto, ¿por qué? ¿Porque me dijo qué estudios tenía que hacerme? Vamos, que me pide unos estudios específicos para poder guiar su propio diagnóstico. ¿No debería cobrar simplemente la consulta en donde me diagnostica y me receta? ¿Por qué me puede cobrar la segunda vez, si en la primera ya me cobró y no me dijo nada, ni me diagnosticó, ni me recetó nada?

Y si a esto le añadimos que muchos doctores nos piden ir a una tercera consulta "para ver cómo vamos", es claro que la tendremos que pagar también. ¿Y por qué? Si lo que va a hacer el doctor es ver si el tratamiento que nos dio es funcional o no. Si no lo es, nos dará otro probablemente y nos cobrará (aunque nos haya dado un mal tratamiento). Si es el indicado nos dirá con satisfacción: "va muy bien" y nos cobrará esta tercera consulta.

Me pregunto entonces: ¿Se vale?

Porque miren, haré una comparación un poco burda: imaginen que alguien me contrata para hacerle un programa de computadora que haga algo específico. Digamos que es una base de datos en donde hay que hacer consultas, reportes, mandar por correo fragmentos de dicha base de información, etcétera. Puedo quizás yo quedar en un precio y trabajar en el sistema sobre al cual ya quedamos en las características que debe tener -muchas veces solamente de palabra. Al final, se lo entrego, el cliente lo prueba y si hacen falta cambios o añadir nuevas cosas, normalmente la mayoría de los programadores haremos un mohín y corregiremos el código para satisfacer las necesidades del cliente. No nos pagará más por ello. Digamos que es parte del trabajo pactado. ¿No debería un médico ver a un paciente que tiene X mal como un trabajo que debe hacer desde un inicio y hasta llegar a un final por un precio determinado? Porque eso de cobrar cada consulta me parece que raya un poco en el abuso.

Y hay desde luego más al respecto de la práctica privada de la medicina. Un galeno puso en su consultorio el siguiente letrero: "A partir de enero del 2014 el costo de la consulta es de 1200 pesos". Entiendo y valoro que los médicos saben muchas cosas y que hay algunos que son extraordinarios en su trabajo, pero ¿la cuota de 1000 pesos que cobraban antes les parece ya poco? Miren, sé de médicos en la práctica privada de su ciencia/arte que trabajan de lunes a viernes y digamos, sin exagerar, que ven a cinco pacientes por día. Eso equivale a 6 mil pesos en un día laboral. Multipliquen por 20 días (cuatro semanas), llegarán a 120,000 pesos por mes. ¿A poco no es suficiente dinero? Y sí, entiendo que hay que pagar consultorio, secretaria/recepcionista, luz, mantenimiento, etcétera. Y que conste que no estoy considerando que estos médicos operan un par de veces a la semana y que sacan entre 25 mil y 50 mil pesos por operación.  Supongamos que operan una vez por semana a unos 35 mil pesos por operación., Solamente de eso se obtienen 140,000 pesos en un mes, más lo de las consultas, nos lleva a nos 260,000 pesos, más de un cuarto de millón de pesos. ¿Es poco?

No conozco a muchos médicos (de hecho conozco sólo a uno), que en su práctica privada se le paga la primera cita y el galeno da seguimiento sobre el tratamiento que se nos da como pacientes. Este mismo médico da una tarde, un día a la semana, consultas gratuitas para quien no puede pagar. Al menos hay un soplo de actitud en pro de la sociedad es estos actos.

Ya más de uno me dirá que en lugar de quejarme por pagar, pues que me vaya a la medicina gubernamental, la pública. Ya sabemos que ésta adolece de muchísimas dificultades para poder dar la calidad que se da en la medicina privada y que se paga. Bastaría decirles que cuando mi padre enfermó del corazón, decidieron (en un hospital privado en donde mi papá estaba asegurado desde hacía muchos años), ponerle un marcapasos muy sofisticado, programable, que valía unos 70 mil pesos. Sí, sólo el marcapasos valía esa cantidad. Con esos costos un enfermo internado en un hospital simplemente desangra el capital de cualquier familia de clase media, o como dice un buen amigo, de "clase pobre alta". Una enfermedad larga deja en quiebra a muchas familias.

Mi solución -que está lejos de ser la ideal- es la de pagarme un seguro de gastos médicos mayores y ni modo. Esto de pagar este tipo de seguros es costoso en general, pero enfermarse de algo más grave puede ser demasiado oneroso para cualquier bolsillo y al menos es una especie de tranquilidad para que las familias no tengan que ver con qué pagar la enfermedad importante de alguno de sus miembros. Pero en el fondo, creo que los médicos, sobre todo aquellos que trabajan en el sector privado, deberían ver más por la sociedad en donde se han desarrollado y no solamente enfocarse a hacerse de miles y miles de pesos por día. En mi opinión, la ética médica se ha desvirtuado en este sentido.