Ya os contamos en el podcast “Aprender a programar” que la programación se basa en las matemáticas y en la lógica. Al final programar es resolver un problema mediante algoritmos que no son más que un conjunto finito de instrucciones con operaciones matemáticas y lógicas. Tenemos que montar un “engranaje” que al final realice lo que nos proponemos.
Recientemente hemos publicado un artículo donde os hablamos de las matemáticas en la programación. Allí podréis descubrir cómo aplicar a la programación las matemáticas que ya sabemos. En este artículo veremos la lógica en la programación y lo vamos a ver con un juego clásico de lógica. “El acertijo del lobo, la cabra y la col”:
“Hace mucho tiempo un granjero fue al mercado y compró un lobo, una cabra y una col. Para volver a su casa tenía que cruzar un río. El granjero dispone de una barca para cruzar a la otra orilla, pero en la barca solo caben él y una de sus compras.
Si el lobo se queda solo con la cabra se la come, si la cabra se queda sola con la col se la come.
El reto del granjero era cruzar él mismo y dejar sus compras a la otra orilla del río, dejando cada compra intacta. ¿Cómo lo hizo?”
Tenemos un conjunto de reglas que se deben cumplir y una solución final. ¿Cómo podríamos realizar un juego con este acertijo? ¿Cómo programaríamos esto?
Como todo programa informático estaría compuesto de varios trozos (funciones) que resolverían una parte de nuestro problema. Por un lado el resultado final sería que todos los elementos hayan cruzado. Si tenemos la función ha_cruzado(elemento) que nos devuelve verdadero si un elemento ha cruzado y falso en caso contrario, utilizando operadores lógicos en una instrucción condicional (si se cumple una expresión) la función que nos diría si todos los elementos han cruzado sería la siguiente:
1 2 3 4 5 6 7 8 9 10 11 |
function han_cruzado_todos(){ if(ha_cruzado(granjero) and ha_cruzado(lobo) and ha_cruzado(cabra) and ha_cruzado(col)) { // Si han cruzado todos, fin de problema return true; } else{ //Sino, al menos alguno no ha cruzado, problema sin resolver return false; } } |
En la primera línea vemos como utilizamos la lógica, si ha cruzado el granjero y el lobo y la cabra y la col entonces han cruzado todos y hemos resuelto el problema.
Esta parte del problema la hemos metido en la función han_cruzado_todos(). Esta función nos devolverá (return) verdadero en caso de cumplirse la condición final y falso en caso contrario. Como veis dentro de nuestra instrucción condicional IF hemos utilizado el operador and para que todo el predicado de nuestra expresión, todas las funciones ha_cruzado(), sean verdaderas. Podríamos haber utilizado un operador or indicando que nos valdría con que cualquier elemento haya cruzado. Pero este no es el caso de nuestro problema. El código que va detrás de la palabra clave ELSE se ejecutara si no se cumple el predicado del IF.
Aquí podéis ver una imagen las operaciones lógicas (lógica computacional) que suelen haber en los lenguajes de programación:
Otra parte de nuestro programa tiene que ser comprobar que no se queden dos elementos solos incompatibles, si tenemos la siguiente función existe(elemento, margen) que nos devuelven si un elemento está en el margen de un rio. Para saber si un elemento no esta en el margen del rio tan solo deberemos utilizar el operador lógico not que nos devuelve el resultado contrario en la función existe. Por ejemplo, si queremos comprobar el margen izquierdo tendríamos el siguiente pseudocódigo:
1 2 3 4 5 |
if(not existe(granjero, izq)) if((existe(lobo,izq) and existe(cabra,izq)) or (existe(cabra,izq) and existe(col, izq))) { Game_Over = true; } |
Este código lo leemos de la siguiente forma: Si no está el granjero en el margen izquierdo entonces si existe el lobo y existe la cabra o si existe la cabra y existe la col en el margen izquierdo entonces, no se cumplen las condiciones y el juego se acaba sin conseguir resolverlo.
A través de la lógica vamos dando forma a nuestro programa. Solo faltaría ir encajando los engranajes y dándole forma a nuestro programa. En el programa principal podríamos tener un bucle finito que se repetirá hasta que se cumpla dos condiciones: o todos los elementos hayan cruzado el rio o se hayan quedado elementos incompatibles en un margen.
Para realizarlo utilizamos la instrucción DO WHILE que repite las instrucciones hasta que se cumpla la condición:
1 2 3 |
do{ //instrucciones secuenciales y llamadas a funciones }while (han_cruzado_todos() = false or Game_Over = false) |
Las instrucciones secuenciales y las llamadas a funciones se ejecutaran hasta que han_cruzado_todos() o Game_Over sean verdaderas.
Poco a poco nuestro programa va cogiendo forma utilizando operaciones lógicas. Iríamos añadiendo trozos hasta completar nuestro programa como nosotros quisiéramos, podemos dar facilidades o no al jugador o incluso podríamos hacer que con las reglas que tenemos lógicas lo resuelva la propia máquina. Desde programarfacil os animamos a que resolváis este juego por vosotros mismos (aunque dejaremos al final la solución). También a modo de ejercicio podéis realizar este juego con el lenguaje de programación que queráis. Si lo hacéis enviarnos vuestro programa y veremos todos los algoritmos diferentes que salen para un mismo problema.
Solución del acertijo:
1. Deja a la cabra al otro lado
2. Vuelve
3. Deja al lobo en el otro lado
4. Regresa con la cabra
5. Deja la col en el otro lado
6. Vuelve
7. Deja la cabra al otro lado