Archive for the 'Programación' Category

Sophie: mapas en wordpress

Sunday, June 1st, 2008

Powered by SophieA falta de unas horas para que concluya el plazo del reto Windows Live organizado por Microsoft y CP Labs, publico este post comentando el plug in de mi candidatura, Sophie.

La plataforma

La plataforma sobre la que desarrollar el plug in se dejaba libre, no teniendo restricción alguna. Así que, opté por WordPress, el sistema de blogging que mueve este blog y que personalmente, me gusta bastante. La programación se basa en PHP y debido a mi experiencia con este lenguaje, estaría cómodo trabajando. No obstante, tuve que documentarme un poco acerca del desarrollo de plug ins para este script, pues hasta ahora nunca me habría planteado programar para él. Pero WP no defraudó y la integración de plug ins no es difícil. Además, hay mucha información en la web oficial.

La idea

En un principio, tenía en mente desarrollar algo más complejo sobre la api de de live maps y spaces, pero por falta de tiempo no fue posible. De hecho deseché la idea. Este semana se me ocurrió algo, recordando un email que envió Microsoft acerca de sus nuevos servicios. Oficialmente, hay un plug in para wordpress que permite insertar en los post mapas, de forma análoga a los videos del youtube. El mapa queda siempre visible y ocupando un espacio. Y ahí es donde entra Sophie.

Como usuario, veo molesto los blogs en los que apenas se puede leer dos líneas sin tener mil imágenes por medio, mil vídeos o mil gadgets afines. Muchas veces, un post puede constar por ejemplo de dos vídeos y ocupar toda una página, siendo necesario ir al scroll para leer el texto del mismo. En el caso de mapas puede ser especialmente caótico… si estamos contando los lugares visitados… y ponemos mapa tras mapa…

Así se me ocurrió la idea de, a través de un sistema de tags, permitir mostrar mapas en una capa emergente, que se pudiera mover y cerrar… cargándo en esa capa cada mapa que se quisiera, no molestando al usuario (sólo se abriría cuando el usuario pinchase en el enlace).

Cómo funciona

En el fichero leeme.txt, se explica con detalle el funcionamiento. De forma resumida, se basa en un sistema de tags [ sophie ] y [ /sophie ] (al estilo del famoso bbcode), en el que se pueden indicar parámetros (como el tipo de mapa, el estilo, la localización si es diferente al texto a mostrar….)

Ejemplos

Collado Villalba

Mi Ciudad

Mi Ciudad desde el aire

powered by Sophie
Cerrar Mapa

Wendy: ¿qué árbol es?

Saturday, January 19th, 2008

Ayer noche y hoy tarde he estado trabajando en un pequeño programa, Wendy, echando una mano a mi chica y a sus compañeros de prácticas. Éste es su post-mortem.

Descripción

El programa desarrollado debía ser capaz de mostrar el nombre de un árbol en función de unos datos (altura, tipo de hoja, fruto que da..) que previamente hubiera introducido el usuario. Es decir, se presentarían en pantalla varias preguntas tipo test y según aquellas respuestas elegidas Wendy hallaría el nombre del árbol que tiene esas características.

Como única condición se tenía el no utilizar código demasiado avanzado, creando una aplicación funcional pero sin demasiado refinamiento técnico, en lenguaje C.

Planteamiento

Por un lado teníamos una serie de árboles… (pino, castaño, madroño…) y por otro lado, una serie de preguntas acerca de esos árboles. Por lo tanto, se deduce que un árbol va a tener ciertas propiedades, sobre las que formular las preguntas. Una forma propicia para albergar un conjunto de datos pertenecientes a una entidad o objeto, es una estructura. (Por las limitaciones de C, quedaba descartada la POO y el uso de objetos o clases). Definiendo…

typedef struct {
nombreArbol nombre; // Nombre del arbol

int familia; // Familia
int altura; // Altura del arbol
int porte; // Porte del arbol
int tipoHoja; // Tipo de hoja (per
int formaHoja; // Forma de la hoja…
int fruto; // Fruto que da
} arbol;

Nombre es otra estructura que a su vez define el nombre técnico y el nombre común del arbol.

Y.. ¿por qué todos los miembros de la estructura son enteros? El asunto era buscar una forma de relacionar el número de respuesta del usuario con los datos de cada arbol, sin tener que hacer infinitos if/else comprobando opción por opción y propiedad por propiedad. Así que, en la carga de datos del array de árboles disponibles (un array de la estructura arbol), metería en cada variable el número de opción correspondiente…

Imaginemos que tengo el árbol Pino, que tiene una altura entre 30 y 40 metros. En el programa, cuando se pregunte por la altura que tiene nuestro arbol a buscar, habrá varias opciones, una de ellas, la número 4, rezará “entre 30 y 40 metros“. En la variable altura del elemento del array en donde tengamos el Pino, meteremos en la fase de carga ese 4, que relacionará la respuesta con la propiedad del árbol. A la hora de buscar, sólo tendremos que comparar la opción elegida por el usuario con el valor de esa variable… y si es igual… (lo mismo se haría con todas las propiedades, y cuando un elemento tenga todas sus variables iguales a las que metió el usuario para cada propiedad.. habremos encontrado nuestro árbol).

Cargando Datos

Cuando arranca el programa, debemos cargar los datos de los árboles en un array de tipo arbol, en el que buscar una vez hayamos terminado de recoger datos por pantalla. Lo suyo hubiese sido algo refinado como un fichero xml… o un fichero binario… pero por crear algo simple, he utilizado un fichero de texto, donde sólo hay números. Cada línea del fichero corresponde a los datos de un árbol… y a través del sistema de númeración / relación de valores de las propiedades del árbol / opciones del test… el fichero tendría esta pinta..

0 0 0 4 1 1 1 1
0 0 0 4 2 1 1 1
1 1 1 3 2 1 2 2

En él vemos 3 árboles…. con sus propiedades. El primer número corresponde al nombre técnico, el segundo al nombre común, el tercero a la familia, el cuarto a la altura (numero de opción de la pregunta de test sobre la altura), el quinto al porte (número de opción de la pregunta de test sobre el porte) y así sucesivamente….

Con un bucle while hasta el final de fichero… leo los datos y los voy metiendo a cada elemento del array.

Nombres y Familias

Para crear un listado de los nombres de los árboles y sus familias, me creé tres arrays, que a través de funciones cargo con datos. (El índice de cada elemento hace referencia al valor de los miembros del array tipo arbol. Es decir, Si tenemos familias[0]=”familia1″, y el elemento arboles[4] pertenece a esa familia, en arboles[4].familia, tendremos un 0. (y así lo indicaremos en el fichero anterior).

Buscando

Con los datos cargados y con las respuestas del usuario guardadas en variables, sólo queda recorrer el array de árboles con un while, hasta que nos pasemos de rango o encontremos el árbol que reúne todos los requesitos. (Comparar en un if que cada variable es igual a cada miembro del elemento actual del array de árboles)

Aprendiendo a programar: algoritmos básicos con arrays

Tuesday, February 27th, 2007

Definido el concepto de array, en este post se verán algunos algoritmos de las operaciones comunes sobre tablas, tales como inserción de un elemento, búsqueda, ordenación… El objetivo es generar una idea clara de cómo se trabaja con tablas, independientemente del lenguaje, por ello esta vez codificaré en pseudocódigo, teniendo en cuenta que:

- Llamaré N al número de elementos presentes en la tabla.

- Llamaré T al número máximo de elementos en la tabla, el declarado con la tabla. tabla(T) es tabla de…

- El rango irá de 1 a T, siendo tabla[1] el primer elemento y tabla[T] el último. (Si codificas en C, ten en cuenta que el índice de los arrays comienza en cero y no en uno)


Lectura y escritura

Como se vió en la primera parte, se puede hacer a un elemento de forma directa, indicando su indice, sin necesidad de recorrer toda la tabla. (tabla[indice]=4; ó variable=tabla[indice]).


Actualización del array

Cuando trabajemos con arrays, no siempre lo tendremos “completo”. Es decir, podemos tener un vector de 5 elementos en el que la mayor parte del tiempo sólo los elementos con índice 1, 2 y 3 tienen algo significativo. A lo largo del programa, puede darse el caso que prescindamos del tercer elemento o añadamos un dato al elemento con índice 4. Por ello, de algún modo debemos llevar cuenta del número de elementos que nos valen, almacenandolos en las primeras posiciones. Respecto al N comentado al principio del post, diremos que los elementos con datos significativos estarán en el rango 1-N. (tabla[1] primer elemento con dato significativo, tabla[N] último elemento con dato significativo). A medida que vayamos considerando elementos o despreciandolos, iremos actualizando el valor de N.


Adicción a continuación del último elemento

Insertaremos en el último lugar (N+1) si el array no está lleno.

Si N < T
tabla[n+1]=valor
N=N+1
Sino
Escribir “tabla llena”
Fin Si

Inserción en una posición P

En este caso, además de comprobar que la tabla no esta llena, moveremos todos los elementos desde P a N al elemento con índice siguiente, para dejar hueco en la posición P y así poder meter el nuevo valor sin perder ningún dato.

Si N < T
Para j de N a P con incremento -1
tabla[j+1]=tabla[j]
Fin Para
tabla[p]=valor
N=N+1
Sino
Escribir “tabla llena”
Fin Si.

También podríamos haberlo hecho con un bucle mientras en lugar de un para y de P a N en lugar de N a P, pero la filosofía seguiría siendo la misma. ;) :)


Borrado de un elemento situado en una posición P

En este caso dará lo mismo que el array esté lleno o no, pero no si está vacío. Tras comprobar esto, moveremos hacia la izquierda todos los elementos posteriores a la posición P.

Si N>0
Para j de P a N-1 con incremento 1
tabla[j]=tabla[j]+1
Fin Para
N=N-1
Sino
Escribir “tabla llena”
Fin Si

Búsqueda de un valor x y la posición que ocupa

Aquí debemos tener en cuenta varias cosillas. En primer lugar, consideramos que tenemos una tabla de enteros, ordenada de menor a mayor. La cosa sería

j=1;
Mientras tabla[j]<x y j<N
j=j+1
Fin Mientras
Si tabla[j]=x Escribir “encontrado x en la posicion j”
Sino Escribir “No encontrado”.

Si la tabla no estuviese ordenada, bastaría cambiar el menor por diferente, en la primera condición del mientras. (Mientras tabla[j]<>x y j<N). Otra forma de hacer esto es utilizar un interruptor: lo inicializamos a false, ponemos la condicion en el mientras de mientras interruptor sea igual a false, si en algún momento del bucle lo encuentra hacemos interruptor=true y fuera del bucle preguntamos por qué condición se ha salido. Pero de la forma mostrada queda más eficiente.

Si la tabla contiene valores repetidos, queremos mostrarlos todos y su posición, haremos algo como:

sw=false
Para j de 1 a N con incremento de 1
Si tabla[j]=x
Escribir “encontrado en posicion j”
sw=true;
Fin Si
Fin Para
Si sw=false
Escribir “No encontrado”
Fin Si

Otro método de búsqueda es la búsqueda binaria o dicotomía, válido sólamente para tablas ordenadas. Se comienza comparando el elemento central de la tabla y, si no es el valor buscado, en función de que sea menor o mayor que el elemento buscado, se coge la mitad inferior o superior y se procede de la misma forma. En tablas muy grandes, es una buena opción, debido a su eficiencia respecto a la búsqueda secuencial.

izq=1
der=N
c=(izq+der)/2
Mientras tabla[c]<>x y izq<der
Si tabla[c]> x entonces der=c-1
Sino izq=c+1
Fin Si
c=(izq+der)/2
Fin Mientras

Si tabla[c]=x entonces Escribir “encontrado en la posicion c”
Sino Escribir “No encontrado”
Fin Si

Observa que izq va estrechando el cerco por la izquierda o principio del array y la variable der, lo mismo, pero por la derecha o fin del array. Si te fijas en la segunda condición del mientras, paramos cuando izq y der se mezclan o superponen, o lo que es lo mismo, el cerco se convierte en cero. Dentro del bucle, indicamos la nueva zona del array en la que buscar y finalmente preguntamos si coincide la variable buscada. La esencia de este algoritmo, como puedes intuir, es recursiva. (Bastaría con ir pasando a la función la porción de la tabla a evaluar, siguiendo la misma filosofía. Cuando llegue a recursividad, lo retomaremos)

Aprendiendo a programar: introducción a los arrays

Tuesday, February 20th, 2007

El siguiente tema en esta serie de artículos serán las tablas, también llamadas arrays ó matrices, estructura fundamental para el programador. Constantemente haremos uso de ellas; cuanto más soltura se tenga con ellas, menos disgustos nos ahorraremos.


¿Qué es un array?

Un array es un conjunto de datos del mismo tipo. Un conjunto de enteros, un conjunto de chars… Llevan asociados un mismo nombre y para diferenciarlos tienen un índice. LLamaremos elemento a cada dato que compone el conjunto de datos, es decir, el array.


Vectores

Un vector es un array de una dimensión, o lo que es lo mismo, un array de una fila y N columnas.

int miTabla[5];

Con eso tendríamos un array, “vacío”, de enteros, de 5 elementos, en lenguaje C. El índice del primer elemento sería el cero, accediendo a él a través de miTabla[0]. El elemento 2, siguiendo la misma pauta, sería accesible mediante miTabla[1] y el último elemento, por miTabla[4].

En pascal, podemos especificar nosotros el rango del índice… de modo que…

Var MiTabla : Array [1..5] of Integer

En este caso el índice iría de 1 a 5, correspondiendo el 1 al primer elemento y el 5 al último.

Cada elemento del array, se comportará como cualquier otra variable. Es decir, podremos hacer un miTabla[3]=5; y asignaremos al elemento 3 del array miTabla el valor 5; también podremos hacer un miTabla[3]=miTabla[3]+2; con lo que tendremos que en ese elemento de miTabla ahora hay un 7.

Por supuesto, cuando accedamos a los elementos del array, debemos asegurarnos que el elemento con el índice que indicamos, existe. Es decir, si en el ejemplo anterior, intentamos acceder a un elemento miTabla[7];, nos daría un error de overflow, pues el índice pasado no coincide con el rango indicado (de 1 a 5). Esto hay que tenerlo en cuenta de forma especial cuando en lugar de una constante, accedamos por una variable, el típico miTabla[i]; metido en un bucle. Si i en algún momento se pasa del rango, el programa cascará. (En tiempo de ejecucción, además, pues el compilador no daría error al compilar).

Otro aspecto que se ha de tener en cuenta, al igual que con las variables, es comprobar qué tiene el elemento en cada momento. Tras crear el array, en el primer ejemplo, en C, puse un vacío entre comillas. Y, es que, al declarar el array no lo estamos inicializando… y sus elementos pueden contener cualquier cosa, y no necesareamente ceros como se podría pensar. Aprovechando esto para ver cómo sería el recorrido completo de un vector y suponiendo que nuestro programa necesita inicializar todos los elementos del vector a cero…

for(i=0;i<5;i++) miTabla[ i ]=0;

En un algoritmo genérico, la 0 del i=0 sería el comienzo del índice del vector y el i<5, el último. Visto desde pascal, con el ejemplo anterior,

for i=1 to i<=5 do miTabla[ i ]:=0;

Si no recuerdo mal, esa sería la sintaxis para pascal. Pero más allá del código en concreto, hay que coger la filosofía. ;)


Matrices

Por matriz se entiende un array bidimensional. En este caso, tendremos un array de N filas por M columnas, es decir, de tamaño NxM, por ejemplo, int Matrix[5][5]; ó int Matrix[10][2]. Lo dicho anteriormente se aplica aquí, teniendo en cuenta la segunda dimensión.

Para recorrer la matriz, necesitaremos dos bucles anidados, con dos contadores, i y j, una para las filas (i) y otra para las columnas (j).

// Código en C
for(i=0;i<10;i++)
for(i=0;i<2;i++)
Matrix[ i ][ j ]=0;


Arrays multidimensionales

También podemos crear arrays de más de dos dimensiones, 3, 4.. N dimensiones. Pasando de 3, la cosa se complicaría mucho y no merecería la pena, optando por otra opción de implementación. En el caso de tres, tendríamos algo como int arrayM[5][6][7]; y recorriendolo con tres bucles for y tres variables, i, j y k.

Aprendiendo a programar: programación modular

Sunday, February 18th, 2007

Seguimos con el cursete de programación. Según vaya avanzando, me meteré más en profundidad en algoritmos genéricos, ejemplos y demás… pues el anterior post del curso igual me parecía muy básico para extenderme demasiado…


Programación estructural, modular y orientada a objetos

Estos tres conceptos hacen referencia a una serie de principios o pautas que definen la filosofía a seguir en los programas.

La programación estructural es la que se compone de las 3 estructuras básicas ya vistas: secuencial (las instrucciones se ejecutan una detrás de otra, en orden descendente), alternativa (los if) e iterativa (los bucles), teniendo en cuenta que todo programa comienza en un sitio y termina en otro o, dicho de otro modo, tiene un principio y un final. (Todo principio, tiene un final, que decía Morpheus)

La programación modular consiste en dividir un programa en partes bien diferenciadas, llamadas módulos (o subprogramas), que pueden ser analizadas y programadas por separado. Existe un algoritmo o programa principal, que cede el control al resto de módulos y, una vez éstos se han ejecutado, vuelve a tomar el control, continuando la ejecución del programa por dónde los llamó.

Entre las reglas principales para programar de forma modular (práctica más que conveniente), están:

- Cada módulo tiene que tener un punto de entrada y otro de salida. (Es decir, el módulo una vez haya realizado su tarea, debe devolver el control al programa principal desde donde fue llamado).

- En el programa principal, se debe definir todos los módulos que se van a utilizar y definirlos en consecuencia.

- Los módulos deben tener independencia, en la medida de lo posible, respecto del programa principal. La idea es que los módulos realicen una tarea de forma genérica, para poder reutilizar código si fuese necesario en otro programa, sin tener que tocar el código del módulo.

- Los datos del programa principal que el módulo necesite, serán pasados desde allí. (Evitar las variables globales).

De la POO ó OOP, programación orientada objetos, hablaré más adelante, pues primero conviene tener soltura con las “programaciones” anteriores, para pillar bien ciertos conceptos.


Funciones y procedimientos

Para no cambiar de tema y después retomarlo, seguiré hablando de subprogramación o programación modular. Las funciones y los procedimientos forman parte de ello.

¿Qué es un procedimiento? Teniendo en cuenta lo anterior, se definiría como un módulo. Concretamente, como un módulo que no retorna ningún valor, ejecuta lo que tenga que ejecutar y devuelve el control al programa que lo llamó.

¿Qué es una función Un módulo que retorna un valor.

La llamada de ambas desde un programa, se hace de forma diferente, atendiendo a su definición. Cuando trabajemos con una función, al llamarla no podremos llamarla sin más, si no que deberemos hacerlo en alguna parte en el que el valor devuelto sea evaluable. Imagina que tenemos una función llamada EsNumero, de tipo booleano (devuelve un valor de tipo bool, true o false, según la cadena pasada esté compuesta toda de números o haya otros caracteres). Si la llamamos como

Sentencia 1
Sentencia 2
EsNumero(cadena)
Sentencia 3

A dónde iría el valor devuelto por la función? A ninguna parte. Y tampoco sería evaluable de ningún modo. La llamada correcta sería en un if, o igualando a una variable. (if EsNumero(cadena) then writeln(”es numero”); ó miVar=EsNumero(cadena), donde miVar es una variable de tipo boolean).

Observa la diferencia. ;) :) También al margen, observa que en el if no he puesto EsNumero(cadena)=true. En un if, cuando la evaluación de la condición da true, verdadero, es cuando se ejecuta las instrucciones que hay dentro de él. Al retornar nuestra función un valor booleano, si devuelve true, en el if habrá algo como if true then… puesto que true, es true…. entrará. Si retorna false, if false then.. como la evaluación de false no es verdadero, no entrará. Por supuesto puedes ponerlo de forma completa con EsNumero=true, pero estos detalles muestran la soltura de un programador.

Por el contrario, la llamada a un procedimiento se hace en “solitario”, como en el ejemplo primero de EsNumero (el que está en el recuadro).

Dentro de una función, deberemos tener una sentencia que indique el retorno de un valor. En pascal, tomaremos el nombre de la función y le asignaremos el valor. (EsNumero:=true). En C, se hará mediante return valor; Para no olvidar este retorno, una buena práctica es declarar una variable del tipo de la función, en este caso bool. Es decir, al principio de la función, haremos var retorno: bool; En el código de la función, iremos asignando a esa variable el valor que proceda en cada caso y al final de la misma, asignaremos esa variable a la función, EsNumero:=retorno. Así, la lógica de la función podrá fallar, pero siempre devolveremos un valor de forma clara. ;)


Paso de parámetros

Los parámetros son los datos que pasaremos a los subprogramas, cuando necesiten trabajar con datos ajenos a ellos. Hay dos formas de pasar estos parámetros, por valor o por referencia. Tanto las funciones como los procedimientos, aceptan ambas formas.

Paso por valor. Se pasa una copia de la variable. Los cambios que hagamos a esa variable, sólo tendrán efecto en el subprograma, pues al tratarse de una copia, en el programa principal tendremos el valor original.

Paso por refencia. En este caso se pasa la dirección de memoria en dónde está la variable, una referencia a su ubicación. (de ahí el nombre). Por tanto, cualquier cambio que hagamos en ella, quedará modificado en el resto del programa, pues se trata de la misma variable.

Y… ¿qué sistema es mejor? Depende de lo que queramos hacer. Es cuestión de valorar cada caso y decidir. (Cuando se trabaje con TAD´s, tipos abstractos de datos, los pasaremos siempre por referencia, pues por valor carecería de sentido por concepto).

Parámetros formales / parámetros actuales. Cuando hablamos de parámetros formales, nos referimos a los parámetros presentes en la declaración de un subprograma. Por parámetros actuales entendemos los parámetros pasados al subprograma en cada llamada. Los parámetros formales y actuales han de coincidir en número y en tipo. De forma opcional, también pueden coincidir en el nombre.


Vida y visibilidad de variables

De vuelta a las variables, comentar una cosilla en relación a la última frase del apartado anterior. Las variables globales, a evitar, son aquellas que son accesibles en cualquier lugar del programa principal y de los subprogramas. En cambio, las locales sólo son accesibles desde el subprograma donde fueron creadas. (Si se crean en el programa principal, sólo serán visibles en el programa principal, no así en los módulos). Por este motivo, si tenemos dos subprogramas y en cada uno de ellos declaramos una variable con el mismo nombre, el programa no daría error, pues se trataría de dos variables diferentes (no se ven entre sí y por tanto, no influyen entre ellas, y tampoco pasaría nada por tener una variable llamada i en el programa principal y en dos subprogramas). La vida de esas variables, terminará (se liberará el espacio en memoria destinado a esa variable), cuando se finalice el subprograma… por ello hay que tener en cuenta que las variables locales de cada subprograma no son accesibles desde el resto de subprogramas o programa principal… si nos hace falta un dato procesado en el subprograma, lo enviaremos por medio de una función, retornando un valor.