KAREL Parmetros Recursividad Funciones avanzadas de Karel Parmetros

  • Slides: 20
Download presentation
KAREL Parámetros, Recursividad Funciones avanzadas de Karel.

KAREL Parámetros, Recursividad Funciones avanzadas de Karel.

Parámetros en funciones Hemos visto ya la sentencia repetir/veces que nos ayuda a iterar

Parámetros en funciones Hemos visto ya la sentencia repetir/veces que nos ayuda a iterar un bloque de código un determinado número de veces, pero siempre teníamos que colocar un número fijo en la sentencia, ¿te has puesto a pensar que pasaría si por ejemplo necesitara una instrucción que volteara a Karel 180°? Pues la respuesta natural sería "haz una instrucción que haga que Karel gire dos veces". Pero. . . ¿crees que sería posible usar la instrucción que hicimos anteriormente gira-derecha? Si existiese alguna forma de que en vez de poner 3 en la sentencia repetir/veces pusiesemos un número variable, podríamos usar la instrucción tanto para girar a la derecha como para dar media vuelta. ¡Pues si existe! Primero retomemos el código para girar a la derecha: . . . define-nueva-instruccion gira-derecha como inicio repetir 3 veces inicio gira-izquieda; fin;

Ahora, todas las nuevas instrucciones declaradas pueden además llevar un parámetro, ¿pero que es

Ahora, todas las nuevas instrucciones declaradas pueden además llevar un parámetro, ¿pero que es un parámetro? , pues es un numerito que le podemos mandar a la instrucción cuando la llamamos, y como cuando declaramos la instrucción no sabemos con que número la vamos a llamar, reemplazamos el número por una palabra. ¿Alguna vez has oído la frase "los primeros n números"? , pues precisamente eso son los parámetros. Podemos en vez de n poner 1, 2 ó 3, quedando "los primeros 3 números" por ejemplo. Este parámetro puede tener el nombre que sea, siempre y cuando la primer letra no sea un número y el nombre del parámetro no sea el mismo que una palabra del lenguaje, por ejemplo no se puede llamar si, repetir, avanza, etc. Este parámetro se puede usar en cualquier lugar dentro de la definición de la instrucción, en cualquier sentencia o instrucción que necesite un número (justo como la sentencia repetir/veces). Redefinamos ahora la instrucción gira-derecha como la instruccion gira: . . . define-nueva-instruccion gira (n) como inicio repetir n veces inicio gira-izquieda; fin;

De esta forma si escribimos en nuestro código "gira(3); " Karel girará a la

De esta forma si escribimos en nuestro código "gira(3); " Karel girará a la derecha, si escribimos "gira(2); " dará media vuelta, si escribimos "gira(1); " girará a la izquierda y si escribimos "gira(0); " no hará nada. Aqui puedes ver como se escribe una instrucción con un parámetro en general: . . . define-nueva-instruccion xxx (yyy) como inicio zzz fin; . . . donde xxx es el nombre de la instrucción, yyy es el nombre del parámetro y zzz es cualquier número de instrucciones. Ejercicio 9: Escribe una nueva instrucción que avance a Karel el número de veces que se le mande como parámetro. Debes de evitar que Karel choque con alguna pared. ¿Tienes dudas? Usa como base el código de la instrucción gira.

Las funciones sucede y precede Ahora ya sabemos como mandarle un número a un

Las funciones sucede y precede Ahora ya sabemos como mandarle un número a un procedimiento, y probablemente ya habrás intentado poner operaciones como suma, resta o multiplicación, sin embargo lamento decirte que ninguna de estas operaciones están soportadas en Karel. Por otro lado, existen dos funciones que nos permiten sumarle 1 a un número y restarle 1. Pero. . . ¿qué es una función? Una función es una instrucción que devuelve un valor, es decir, reciben un parámetro (o más) que luego procesa, para al final regresar un valor; por ejemplo, la función booleana junto-a-zumbador devuelve verdadero si Karel está parado junto a un zumbador y falso si no lo está. En Karel no se pueden declarar funciones

Las funciones sucede y precede son dos instrucciones que reciben un parámetro, posteriormente, devuelven

Las funciones sucede y precede son dos instrucciones que reciben un parámetro, posteriormente, devuelven un número más y un número menos (respectivamente) que el que le enviamos. La función sucede se escribe así: . . . sucede(xxx); . . . donde xxx es un número o un parámetro, y la función precede se escribe así: . . . precede(xxx); . . . donde xxx es un número o un parámetro.

Debido a que devuelven un número, solo nos pueden servir poniendolas en alguna instrucción

Debido a que devuelven un número, solo nos pueden servir poniendolas en alguna instrucción o sentencia que reciba un número, como repetir/veces, otro sucede o precede o una instrucción personal que reciba un parámetro. Por ejemplo, el siguiente trozo de código pone n + 1 zumbadores en donde Karel se encuentra: . . . repetir sucede(n) veces inicio deja-zumbador; fin; . . . nota que n se "incrementa" (se le suma uno). Si en vez de sucede, pusieramos precede, Karel dejaría n - 1 zumbadores, porque la n se "decrementa" (se le quita uno) cuando se pone dentro de una función precede.

La función si-es-cero La última función en Karel, es la función si-es-cero, que nos

La función si-es-cero La última función en Karel, es la función si-es-cero, que nos ayuda a saber si un número es cero. Devuelve verdadero si el número es cero y falso si no lo es. Es evidente de que si ponemos "si-es-cero(0)" no es muy útil, ya que sabemos perfectamente que cero es cero ( : S ). Sin embargo es muy útil cuando se está manejando parámetros. Por ejemplo, queremos hacer una instrucción que avance "n" lugares, pero si el parámetro es cero, gire a la izquierda. Por razones didácticas, en esta ocasión te daremos la solución: . . . define-nueva-instruccion avanza-si-no-es-cero (n) como inicio si si-es-cero (n) entonces inicio gira-izquierda; fin sino inicio repetir n veces inicio avanza; fin; …

Recursividad Empecemos. ¿Te has preguntado alguna vez qué sucede cuándo llamas a una instrucción

Recursividad Empecemos. ¿Te has preguntado alguna vez qué sucede cuándo llamas a una instrucción que tu creaste? Como te habrás dado cuenta, se ejecuta la instrucción que le pediste y luego continua en el lugar en donde se quedó. Pero en realidad, ¿cómo hace eso la computadora? Pues bien, la computadora tiene una cosa que se llama "pila de llamadas", cuando un programa se ejecuta y encuentra una instrucción, se guarda en la pila en que lugar se quedó, entonces ejecuta la instrucción que le pediste y al terminar la instrucción, revisa en la pila en donde estaba anteriormente, para continuar en ese lugar. ¿Muy enredado? Mira este dibujo: Espero haya quedado claro, ya que esto es el punto crucial de la recursividad. Ahora que sabemos como funciona el llamado a procedimientos o instrucciones. Definamos lo que es recursividad.

Definición Una instrucción recursiva, es aquella que en algún momento, se llama así misma.

Definición Una instrucción recursiva, es aquella que en algún momento, se llama así misma. Por ejemplo, puedes revisar en libros y en muchos otros lados, la definición recursiva del factorial: factorial(1) = 1 factorial(n) = n * factorial(n - 1) Como puedes ver, para saber el factorial de un número, necesitas saber el factorial del número anterior. Allí está la recursividad. Toda instrucción recursiva, consta de dos partes: 1. - Base Es un valor fijo al que eventualmente, la recursión debe de llegar, normalmente, es un valor pequeño y no demostrable. Por ejemplo, factorial de 1, es 1, y no se puede demostrar, además, si quieres calcular el factorial de cualquier número, eventualmente, debes de saber el factorial de 1. 2. - Recursión Consiste en la parte en donde la instrucción se llama así misma, además de efectuar algunas operaciones con el resultado. Por ejemplo, para el factorial de 3, se calcula el factorial de 2 y eso se multiplica por 3. Ahora que sabes que es recursividad, intenta hacer la definición recursiva de la serie de Fibonacci, la cual dice que sus primeros dos elementos (1 y 2) son 1, y para cualquier otro número de Fibonacci, se debe sumar el Fibonacci de los dos números anteriores, Por ejemplo: Fibonacci(3) = 2, Fibonacci(5) = 5. Pasemos de lleno a la recursividad en Karel.

Recursividad simple Intentemos ahora llamar a una instrucción desde sí misma, recordemos que debe

Recursividad simple Intentemos ahora llamar a una instrucción desde sí misma, recordemos que debe de tener una base y una definición recursiva, ¿te parece bien que la base sea si el frente esta bloqueado termina? , ¿y te parece bien que si no avance una casilla y entonces se llame asi misma? , ¡Hagámoslo! . . . define-nueva-instruccion recursiva como inicio si frente-libre entonces inicio avanza; recursiva; fin; . . . Nota que en Karel es imposible decirle "termina-instruccion", así que mejor invertimos la condición y avanzamos si el frente está libre, ¡es otra forma de poner la base!, por que, en otras palabras, la base es lo que hace que la recursión termine y no sea infinita. Nota también que en este caso las operaciones que hacemos son solamente "avanza; ".

¿Qué crees que haga esté código? Ponlo en el Simulador Karel y adivina. .

¿Qué crees que haga esté código? Ponlo en el Simulador Karel y adivina. . . ¡Así es! Karel avanzará mientras el frente este libre. Entonces te preguntarás ¿no sería mejor un ciclo mientras? Y la respuesta es: si solamente quieres hacer eso, sí, sin embargo, ¿que tal si quieres contar con zumbadores cuantos pasos avanzaste? ¡A verdad! Si queremos hacer eso, debemos agregarle una línea a nuestro código: . . . define-nueva-instruccion recursiva como inicio si frente-libre entonces inicio avanza; recursiva; deja-zumbador; fin; . . . Ahora pruébalo. ¡Wow! ¡Sorprendente! ¿Por qué funciona?

 Si recuerdas la sección de fundamentos, cada vez que se llama una instrucción,

Si recuerdas la sección de fundamentos, cada vez que se llama una instrucción, la siguiente instrucción se guarda en la pila de llamadas, como se va a llamar exactamente el número de veces que avanzaste, cuando la recursividad termine al llegar a la base, va a sacar una por una las instrucciones que siguen, y las que siguen siempre serán "deja -zumbador". En este ejemplo, solo hay una instrucción antes y después de las llamadas recursivas, pero puede haber muchísimas más. Si aún no lo entiendes, trata de simular la pila de llamadas de la misma forma que está en la imagen. Ejercicio 12: ¿Recuerdas el problema del periódico del Ejercicio 2? Ahora imagina que el periódico está en la posición 1, 1 y que la casa de Karel, puede estar ubicada en cualquier posición del mundo, eso sí, con la misma orientación y forma. Haz un programa que haga que Karel lleve el periódico a su sala. ¡Usa recursividad! Recuerda, piensa en que momento la recursividad termina (BASE) y si hay que hacer algo en ese momento, luego piensa en la llamada recursiva, y las operaciones que van a ir antes, y las que van a ir después (las que se van a guardar en la pila).

Recursividad con parámetros ¿Recuerdas los parámetros? ¿Recuerdas las funciones precede y sucede? ¿Que pasaría

Recursividad con parámetros ¿Recuerdas los parámetros? ¿Recuerdas las funciones precede y sucede? ¿Que pasaría si a una instrucción con parámtro la llamaramos usando precede o sucede? Todo esto, en Karel es posible, definamos una instrucción con parámetros y volvámosla recursiva usando sucede: . . . define-nueva-instruccion recursiva 2 (n) como inicio si frente-libre entonces inicio avanza; recursiva 2 ( sucede (n) ); fin sino inicio repite n veces inicio deja-zumbador; fin; . . .

Este código hace exactamente lo mismo que el de la sección anterior, con la

Este código hace exactamente lo mismo que el de la sección anterior, con la diferencia de que la complejidad que existía en la pila de llamadas es eliminada, y colocada como una instrucción base. En cada paso de la recursión, se aumenta uno, y cuando llegas a la base, tiene un número que tal vez pudas usar para tu beneficio. No te olvides que también puedes usar la función precede y si-es-cero y que en la llamada recursiva puedes llamarla con el parámetro sin modficar. Como punto importante, hay que destacar que en la pila de llamdas, además de la instrucción que sigue, también se guarda el valor actual del parámetro. Ejercicio 13: Realiza el Ejercicio 12 pero con Recursividad con parámetros. Ejercicio 14: Realiza una instrucción que avance a Karel tantas veces como zumbadores tenga en su mochila utilizando Recursividad con parámetros, NO se vale usar un ciclo mientras.

Recursividad mixta Si ya dominas los dos tipos de recursividad anteriores, esto será muy

Recursividad mixta Si ya dominas los dos tipos de recursividad anteriores, esto será muy fácil para ti, ya que la recursividad mixta no es más que usar los dos tipos de recursividad al mismo tiempo. Veamos el siguiente problema: Teniendo un mundo como el de arriba y con zumbadores infinitos en la mochila, coloca en 1, 1 el resultado de la multiplicación. Este es uno de los problemas más clásicos de recursividad mixta, sin ella la complejidad del problema sería muy elevada. Para este problema usaremos dos instrucciones, uno con recursividad simple y el otro con parámetro.

La mecánica de solución es la siguiente: Se van a tomar todos los zumbadores

La mecánica de solución es la siguiente: Se van a tomar todos los zumbadores de una posición con recursividad con parámetros, para que al llegar a la base, el parámetro tenga el número de zumbadores que hay en dicha posición, posteriormente, ese número se pasa como parámetro a la instrucción recursiva simple (si, aunque la recursividad es simple, también tiene parámetro), y en cada paso, se le va a llamar recursivamente con el mismo parámetro, de esa forma, en la pila de llamadas, el parámetro va a estar tantas veces como zumbadores haya en la segunda posición, y vuala. Tal vez quede más claro si ves las instrucciones y las sigues paso a paso en Karel.

. . . define-nueva-instruccion multiplica (n) como inicio si junto-a-zumbador entonces inicio coge-zumbador; multiplica(n);

. . . define-nueva-instruccion multiplica (n) como inicio si junto-a-zumbador entonces inicio coge-zumbador; multiplica(n); repetir n veces inicio deja-zumbador; fin sino inicio ve. Al. Inicio; fin; define-nueva-instruccion cuenta (n) como inicio si junto-a-zumbador entonces inicio coge-zumbador; cuenta( sucede (n) ); fin sino inicio avanza; multiplica (n); fin; . . .

 Esta casi completa, pero le falta implementar la instrucción ve. Al. Inicio (que

Esta casi completa, pero le falta implementar la instrucción ve. Al. Inicio (que debe ser de lo más trivial) y el posicionamiento inicial, tal vez en un principio no entiendas bien, revisa el código paso a paso hasta que lo comprendas, ¡Suerte! Ejercicio 15: Teniendo un mundo como el de abajo: en donde puede haber cualquier cantidad de calles y cualquier ancho en las avenidas (siempre cerrado el circuito y sin "islas" o bifurcaciones), deje en la esquina izquierda más inferior (2, 1 en el ejemplo), tantos zumbadores como número de calles de ancho 1 que hay, Karel lleva infinitos zumbadores en su mochila. En resultado del ejemplo es 3.