diff --git a/ayuda.html b/ayuda.html new file mode 100644 index 0000000..3bf23e4 --- /dev/null +++ b/ayuda.html @@ -0,0 +1,22 @@ + + +
+ +Karel.js es un port de KarelOMI a JavaScript, y que facilita la exportación del mundo y la salida esperada a omegaUp.
+Para editar el mundo, haz click en él. Click en alguna intersección agrega un zumbador, Ctrl+Click elimina uno. Shift-Click marca la casilla para que sea incluida en la salida. Puedes mover a Karel (asà como cambiarlo de dirección) usando click derecho.
+Una vez que hayas empezado a ejecutar un programa de Karel, tanto el mundo como el editor se volverán de solo-lectura hasta que hagas click en el botón para regresar al mundo a su estado original ().
+Puedes importar un mundo (archivo .mdo) y sus condiciones de ejecución (archivo .kec) usando el comando Mundo > Importar MDO/KEC.
++ + | +
+ ::= |
+
+ "class program {
+ " |
+
+ + | +
+ ::= |
+ + + | +
+ | + | + |
+ + | +
+ ::= |
+ + + | +
+ Parámetro opcional |
+
+ ::= |
+
+ "("
+ [ Identificador ] ")" |
+
+ + | +
+ ::= |
+
+ {
+ "void" | "define" }f |
+
+ + | +
+ ::= |
+
+ "("
+ ")" |
+
+ + | +
+ ::= |
+
+ "("
+ [ Expresion entera ]
+ ")" |
+
+ + | +
+ ::= |
+
+ ( Bloque |
+
+ + | +
+ ::= |
+
+ "{"
+ [ Expresión ] ... "}" |
+
+ + | +
+ ::= |
+
+ ";" |
+
+ + | +
+ ::= |
+ + + | +
+ + | +
+ ::= |
+
+ { Decimal |
+
+ + | +
+ ::= |
+
+ Cláusula Y [ "||" Cláusula
+ Y ] ... |
+
+ + | +
+ ::= |
+
+ Cláusula No [ "&&" Cláusula No ] ... |
+
+ + | +
+ ::= |
+
+ [
+ "!" ] Cláusula Atómica |
+
+ + | +
+ ::= |
+
+ {
+ "iszero" "(" Expresión
+ entera ")" |
+
+ Expresión
+ if
+ |
+
+ ::= |
+ + + | +
+ Expresión
+ while
+ |
+
+ ::= |
+ + + | +
+ Expresión
+ iterate
+ |
+
+ ::= |
+
+ "iterate" "(" Expresión
+ entera ")" Expresión |
+
+ Expresión
+ turnoff
+ |
+
+ ::= |
+
+ "turnoff" Argumento vaciío ";" |
+
+ Expresión
+ turnleft
+ |
+
+ ::= |
+
+ "turnleft" Argumento vacío
+ ";" |
+
+ Expresión
+ move
+ |
+
+ ::= |
+
+ "move" Argumento vacío ";" |
+
+ Expresión
+ pickbeeper
+ |
+
+ ::= |
+
+ "pickbeeper" Argumento vacío
+ ";" |
+
+ Expresión
+ putbeeper
+ |
+
+ ::= |
+
+ "putbeeper" Argumento vacío ";" |
+
+ Expresión
+ return
+ |
+
+ ::= |
+
+ "return" Argumento vacío ";" |
+
+ + | +
+ ::= |
+ + + | +
+ + | +
+ ::= |
+
+ {
+ {"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"}
+ [ Dígito ] ... |
+
+ + | +
+ ::= |
+
+ Cualquier
+ cosa entre comillas en una única línea |
+
+ + | +
+ ::= |
+
+ {"frontIsClear" |
+
+ + | +
+ ::= |
+
+ {"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"} |
+
+ + | +
+ ::= |
+
+ Una
+ letra del alfabeto |
+
+ + | +
+ ::= |
+
+ Marca
+ el final del fichero |
+
+ | + | + |
+ Definición del panel instantáneo
+ |
+ ||
+ + | +
+ ::= |
+
+ [ Declaración de método |
+
+ Están
+ soportados los dos tipos de comentario de JAVA/C++:
|
+
Fin-de-página
+ ++
El Robot Karel
++ + | +
+ ::= |
+
+ "iniciar-programa" |
+
+ + | +
+ ::= |
+
+ "define-nueva-instruccion" Identificador
+ [ "(" Identificador ")" ]
+ "como" |
+
+ | + | + |
+ + | +
+ ::= |
+
+ { Expresion | ExpresionVacia } |
+
+ + | +
+ ::= |
+
+ {"apagate" |
+
+ + | +
+ ::= |
+
+ Identificador [ "(" ExpresionEntera ")" ] |
+
+ + | +
+ ::= |
+
+ "si"
+ Termino "entonces" |
+
+ + | +
+ ::= |
+ + + | +
+ + | +
+ ::= |
+
+ "repetir"
+ ExpresionEntera
+ "veces" |
+
+ + | +
+ ::= |
+ + |
+ + | +
+ ::= |
+ + + | +
+ + | +
+ ::= |
+
+ ClausulaNo [
+ "y" ClausulaNo
+ ]... |
+
+ + | +
+ ::= |
+
+ [
+ "no" ] ClausulaAtomica
+ |
+
+ + | +
+ ::= |
+
+ {
+ "si-es-cero" "(" ExpresionEntera
+ ")" | FuncionBooleana
+ | "(" Termino ")" } |
+
+ + | +
+ ::= |
+
+ { Decimal | Identificador |
+ "precede" "(" ExpresionEntera
+ ")" | "sucede" "(" ExpresionEntera ")" } |
+
+ + | +
+ ::= |
+ + + | +
+ + | +
+ ::= |
+
+ {
+ {"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"}
+ [ Digito ] ... |
+
+ + | +
+ ::= |
+
+ Cualquier
+ cosa entre comillas en una única línea. |
+
+ + | +
+ ::= |
+
+ {"frente-libre" |
+
+ + | +
+ ::= |
+
+ {"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"}
+ |
+
+ + | +
+ ::= |
+
+ Una
+ letra del alfabeto |
+
+ + | +
+ ::= |
+
+ Marca
+ de final de fichero. |
+
+ | + |
+
+
+
+ |
+
+ Definiciones del Panel Instantaneo
+
+ |
+ ||
+ + | +
+ ::= |
+
+ ExpresionInstantanea [ ";" |
+
+ + | +
+ ::= |
+
+ { DeclaracionDeMetodo | DeclaracionDeEnlace | ExpresionGeneral } |
+
+ Están
+ soportados los dos estilos de comentario en Pascal:
Están soportados los dos estilos de comentario en Java/C++: +
|
+
+ +
Final-de-página
+ ++Nosotros programaremos Karel, un Robot simple que vive en un mundo simple. Debido a que Karel y su mundo son simulados, ¡nosotros podemos realmente ver los resultados de un programa en acción ! El lenguaje con el que programaremos Karel es una versión especial de Pascal, por lo tanto, la mayor parte de lo que aprendamos, podrá ser aplicado directamente al lenguaje de programación estándar Pascal.
+Por qué programamos Karel
+ +Desde el principio, siempre se nos ha dicho la esquina exacta de inicio. Nosotros queremos programar Karel para que se adapte mejor a su mundo. La sentencia mientras/hacer nos permite repetir pasos mientras se cumple una condición, y esto nos va a permitir programar a Karel para que ¡no sea un chico tan rígido!. La sentencia mientras/hacer tiene la forma siguiente:
+...
++
mientras xxx hacer inicio ++ yyy
+ fin ;
+...
++ donde xxx debe ser una condición (una de las funciones booleanas listadas anteriormente), y yyy representa cualquier número de sentencias de Karel. El ejercicio 1 podría haberse escrito de la siguiente manera:
+...
+mientras frente-libre hacer inicio ++ avanza ;
+ fin ;
+...
++Esto soluciona el problema de caminar de nuevo a la 1ª Calle, sin importar como de lejos se encuentre de esta Calle.
++Ejercicio 6: La tarea de Karel es dejar zumbadores a lo largo de una pista de carreras. Un ejemplo de dicha pista es la de la siguiente imagen. Karel debe dar una vuelta completa y depositar un zumbador en cada esquina a lo largo del camino. Guarda el programa con el nombre “pistaCarreras.txt”. Tu solución debe usar sentencias mientras/hacer. Construye el mundo inicial de la siguiente imagen con el nombre “pistaCarreras.mdo”. Asegurate de poner dentro de la mochila suficientes zumbadores para todas las esquinas. El ejemplo requiere 22 zumbadores. Karel debe empezar en cualquier intersección de la pista.
++
+Asegúrate de que tu programa funciona en el mundo anterior, y después prueba tu programa modificando el mundo inicial. También, intenta iniciar a Karel desde diferentes intersecciones a lo largo del camino. ¿Realiza Karel su tarea correctamente en todos los casos?
+La sentencia mientras /hacer
+ +...
+while ( xxx) {
++ yyy
++ }
+...
++ donde xxx debe ser una condición (una de las funciones booleanas listadas anteriormente), y yyy representa cualquier número de sentencias de Karel. El ejercicio 1 podría haberse escrito de la siguiente manera:
++ ...
+while (frontIsClear) {
++ move() ;
++ }
+...
++ +Esto soluciona el problema de caminar de nuevo a la 1ª Calle, sin importar como de lejos se encuentre de esta Calle.
++Ejercicio 6: La tarea de Karel es dejar zumbadores a lo largo de una pista de carreras. Un ejemplo de dicha pista es la de la siguiente imagen. Karel debe dar una vuelta completa y depositar un zumbador en cada esquina a lo largo del camino. Guarda el programa con el nombre “pistaCarreras.txt”. Tu solución debe usar sentencias while. Construye el mundo inicial de la siguiente imagen con el nombre “pistaCarreras.mdo”. Asegurate de poner dentro de la mochila suficientes zumbadores para todas las esquinas. El ejemplo requiere 22 zumbadores. Karel debe empezar en cualquier intersección de la pista.
++
+Asegúrate de que tu programa funciona en el mundo anterior, y después prueba tu programa modificando el mundo inicial. También, intenta iniciar a Karel desde diferentes intersecciones a lo largo del camino. ¿Realiza Karel su tarea correctamente en todos los casos?
+La sentencia while
+ ++En otras palabras, diciendo " gira-derecha; " Karel giraría tres veces hacia la izquierda para alcanzar nuestro objetivo. Es posible. ¿Estás suficientemente motivado para aprender una nueva sentencia? +
++Una de las razones de crear nuevas instrucciones, es por evitar escribir tanto. Otra es para documentar mejor cual es nuestro objetivo, cuando nosotros mismos u otra persona lee el programa. Como seguramente te estarás dando cuenta, programar es una tarea extremadamente compleja, y ¡necesitamos toda la ayuda necesaria para hacer las cosas correctamente !
++Las sentencias define-nueva-instrucion están situadas en un sitio especial dentro de un programa de Karel, justo después de la sentencia iniciar-programa. El siguiente es un programa válido para Karel:
++ +
+Puedes definir cualquier número de instrucciones nuevas, y después usarlas en el programa donde las necesites. Las instrucciones nuevas pueden contener sentencias de control, si es necesario. Date cuenta de que la nueva instrucción puede también usar una instrucción definida previamente. El ejercicio 5 podría haberse escrito:
++
+Date cuenta de como la instrucción repetir acaba moviendo a Karel una esquina hacia adelante, sin tener en cuenta en nº de zumbadores. Si haces esto 14 veces, ¡estarás en casa !
++ +Ejercicio 7: Re-escribe el programa para el ejercicio 4, pero esta vez puede no haber un zumbador en cada esquina. Guarda tu programa con el nombre “diagonal2.txt”. La nueva instrucción debería coger un zumbador en la posición actual, si es que lo hay. Deberías usar esta instrucción para coger todos los zumbadores mientras Karel va a su casa en diagonal. Asegúrate de que tienes el mundo “diagonal.mdo” cargado y probar vuestro programa. Karel debería finalizar el la esquina de la 1ª Calle con la 1ª Avenida, con todos los zumbadores que ha ido cogiendo por el camino, y apagarse.
+Ejercicio 8: Escribe un programa que ayude a Karel a escapar de un laberinto que no contiene islas (cuadrados aislados). La salida del laberinto está marcada ubicando un zumbador en la primera esquina que está fuera del laberinto, al lado del muro de la derecha. Una forma de resolver este problema es hacer que Karel avance a lo largo del laberinto siguiendo el muro de su derecha ( imagina que está tocando el muro y que nunca puede despegar su mano de él). En la siguiente imagen hay un ejemplo de un laberinto del cual debería ser capaz de salir (no olvides que tu programa debería funcionar en todos los laberintos, no solo en el de la imagen). Guarda tu programa con el nombre “laberinto.txt”. Esto parece muy, muy complicado. ¿Puedes darnos un mundo de ejemplo?
+Aquí tenéis un mundo inicial de ejemplo. La línea roja muestra el camino que debería seguir Karel para este mundo. Recuerda que no sabes de antemano donde estarán los muros.
++
Podría hacerse más fácil si definieras unas pocas nuevas instrucciones que hicieran parte del trabajo. Aquí tienes un ejemplo:
+...
+define-nueva-instruccion sigue-muro-derecha como inicio
+{pon tu código aquí}
+fin ;
+...
+Esta instrucción hace que Karel avance correctamente hacia el siguiente segmento de muro. Los diagramas de abajo muestran las 4 situaciones, Karel podría estar en cualquier punto del laberinto. Si sigue-muro-derecha resuelve correctamente los 4 casos, entonces has solucionado la parte principal del problema. También deberías definir gira-derecha.
+Para probar tu programa crea un mundo como el del ejemplo y guárdalo con el nombre “laberinto.mdo”. Una vez te funcione el programa para este mundo, prueba a modificarlo anñadiéndo o quitando muros. ¿Realiza Karel la tarea bien en todos los casos?
++
+ | + |
+En otras palabras, diciendo "turnright(); " Karel giraría tres veces hacia la izquierda para alcanzar nuestro objetivo. Es posible. ¿Estás suficientemente motivado para aprender una nueva sentencia?
++Una de las razones de crear nuevas instrucciones, es por evitar escribir tanto. Otra es para documentar mejor cual es nuestro objetivo, cuando nosotros mismos u otra persona lee el programa. Como te estarás dando cuenta, programar es una tarea extremadamente compleja, y ¡necesitamos toda la ayuda necesaria para hacer las cosas correctamente !
++Las sentencia void (que también se puede escribir como define) está situada en un sitio especial dentro de un programa de Karel, justo después de la sentencia "class program {". El siguiente es un programa válido para Karel:
++ +
+Puedes definir cualquier número de instrucciones nuevas, y después usarlas en el programa donde las necesites. Las instrucciones nuevas pueden contener sentencias de control, si es necesario. Date cuenta de que la nueva instrucción puede también usar una instrucción definida previamente. El ejercicio 5 podría haberse escrito:
++
+Date cuenta de como la instrucción iterate acaba moviendo a Karel una esquina hacia adelante, sin tener en cuenta en nº de zumbadores. Si haces esto 14 veces, ¡estarás en casa !
++ +Ejercicio 7: Re-escribe el programa para el ejercicio 4, pero esta vez puede no haber un zumbador en cada esquina. Guarda tu programa con el nombre “diagonal2.txt”. La nueva instrucción debería coger un zumbador en la posición actual, si es que lo hay. Deberías usar esta instrucción para coger todos los zumbadores mientras Karel va a su casa en diagonal. Asegurate de que tienes el mundo “diagonal.mdo” cargado para probar tu programa. Karel debería finalizar en la esquina de la 1ª Calle con la 1ª Avenida, con todos los zumbadores que ha ido cogiendo por el camino, y apagarse.
+Ejercicio 8: Escribe un programa que ayude a Karel a escapar de un laberinto que no contiene islas (cuadrados aislados). La salida del laberinto está marcada ubicando un zumbador en la primera esquina que está fuera del laberinto, al lado del muro de la derecha. Una forma de resolver este problema es hacer que Karel avance a lo largo del laberinto siguiendo el muro de su derecha ( imagina que está tocando el muro y que nunca puede despegar su mano de él). En la siguiente imagen hay un ejemplo de un laberinto del cual debería ser capaz de salir (no olvides que tu programa debería funcionar en todos los laberintos, no solo en el de la imagen). Guarda tu programa con el nombre “laberinto.txt”. Esto parece muy, muy complicado. ¿Puedes darnos un mundo de ejemplo?
+Aquí tienes un mundo inicial de ejemplo. La línea roja muestra el camino que debería seguir Karel para este mundo. Recuerda que no sabes de antemano donde estarán los muros.
++
Podría hacerse más fácil si definieras unas pocas nuevas instrucciones que hicieran parte del trabajo. Aquí tenéis un ejemplo:
+...
+void sigueMuroDereha() {
+/*pon tu código aquí*/
+}
+...
+Esta instrucción hace que Karel avance correctamente hacia el siguiente segmento de muro. Los diagramas de abajo muestran las 4 situaciones, Karel podría estar en cualquier punto del laberinto. Si sigueMuroDerecha() resuelve correctamente los 4 casos, entonces has solucionado la parte principal del problema. También deberías definir turnright().
+Para probar tu programa crea un mundo como el del ejemplo y guárdalo con el nombre “laberinto.mdo”. Una vez te funcione el programa para este mundo, prueba a modificarlo añadiéndo o quitando muros. ¿Realiza Karel la tarea bien en todos los casos?
++
+ | + |
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;
+fin;
+...
+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;
+fin;
+...
+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.
+Hemos visto ya la sentencia iterate 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 turnright()? Si existiese alguna forma de que en vez de poner 3 en la sentencia iterate 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:
+...
+void turnright() {
+iterate(3) {
+turnleft();
+}
+}
+...
+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 if, iterate, move, 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 iterate). Redefinamos ahora la instrucción turnright como la instruccion turn:
+...
+void turn(n) {
+iterate(n) {
+turnleft();
+}
+}
+...
+De esta forma si escribimos en nuestro código "turn(3);" Karel girará a la derecha, si escribimos "turn(2);" dará media vuelta, si escribimos "turn(1);" girará a la izquierda y si escribimos "turn(0);" no hará nada.
+Aqui puedes ver como se escribe una instrucción con un parámetro en general:
+...
+void xxx (yyy) {
+zzz
+}
+...
+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.
+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 lamanto 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 nuevas, pero se pueden usar las que ya existen.
+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 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.
+Ejercicio 10: Escribe una nueva instrucción que reciba un número n y mueva a Karel n + 2 veces (validando el choque contra paredes), y posteriormente, coloque n - 2 zumbadores en la posición en donde está. PISTA: Usa un repetir/veces para mover a Karel y otro para colocar los zumbadores. NO se vale colocar instrucciones fuera de los ciclos repetir/veces.
+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 lamanto 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 nuevas, pero se pueden usar las que ya existen.
+Las funciones succ y pred 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 succ se escribe así:
+...
+succ(xxx);
+...
+donde xxx es un número o un parámetro, y la función pred se escribe así:
+...
+pred(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 o sentencia que reciba un número, como iterate, otro succ o pred 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:
+...
+iterate( succ(n) ) {
+putbeeper();
+}
+...
+nota que n se "incrementa" (se le suma uno). Si en vez de succ, pusieramos pred, Karel dejaría n - 1 zumbadores, porque la n se "decrementa" (se le quita uno) cuando se pone dentro de una función pred.
+Ejercicio 10: Escribe una nueva instrucción que reciba un número n y mueva a Karel n + 2 veces (validando el choque contra paredes), y posteriormente, coloque n - 2 zumbadores en la posición en donde está. PISTA: Usa un iterate para mover a Karel y otro para colocar los zumbadores. NO se vale colocar instrucciones fuera de los ciclos iterate.
+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;
+fin;
+fin;
+...
+Ahora si, te toca a ti:
+Ejercicio 11: Define una nueva instrucción que haga que Karel ponga "n" zumbadores en donde se encuentra, pero si "n" es cero, recoja 1 zumbador.
+ +La última función en Karel, es la función iszero, 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 "iszero(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:
+...
+void avanzaSiNoEsCero (n) {
+if ( iszero(n) ) {
+turnleft();
+}
+else {
+iterate (n) {
+move();
+}
+}
+}
+...
+Ahora si, te toca a ti:
+Ejercicio 11: Define una nueva instrucción que haga que Karel ponga "n" zumbadores en donde se encuentra, pero si "n" es cero, recoja 1 zumbador.
+ +Hemos llegado al último tema, y no por eso el menos importante, de hecho, es el tema más complicado que veremos aqui, y es muy útil no solo para Karel, sino para resolver cualquier problema. Debido a la complejidad del tema, se han creado 5 subtemas:
+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 instrcció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.
+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:
+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.
+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;
+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;". Algo diferente al factorial ¿no?
+¿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;
+fin;
+...
+Ahora pruébalo.
+¡Wow! ¡Sorprendente! ¿Por qué funciona?
+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).
+¿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 recursiva2 (n) como inicio
+si frente-libre entonces inicio
+avanza;
+recursiva2 ( sucede (n) );
+fin
+sino inicio
+repite n veces inicio
+deja-zumbador;
+fin;
+fin;
+fin;
+...
+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.
+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 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);
+repetir n veces inicio
+deja-zumbador;
+fin;
+fin
+sino inicio
+veAlInicio;
+fin;
+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;
+fin;
+...
+Esta casi completa, pero le falta implementar la instrucción veAlInicio (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.
+En este problema se usan casi todos los temas vistos en el curso, emplealos y resuélvelo.
++
Hemos llegado al fin del curso, ahora debes ser capaz de participar en la Olimpiada Mexicana de Informatica, no olvides seguir resolviendo problemas para mejorar siempre tus habilidades, puedes encontrar ligas a las páginas en donde hay problemas en la página principal de la OMI.
+¡SUERTE!
+Hemos llegado al último tema, y no por eso el menos importante, de hecho, es el tema más complicado que veremos aqui, y es muy útil no solo para Karel, sino para resolver cualquier problema. Debido a la complejidad del tema, se han creado 5 subtemas:
+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 instrcció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.
+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:
+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.
+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!
+...
+void recursiva () {
+if (frontIsClear) {
+move();
+recursiva();
+}
+}
+...
+Nota que en Karel es imposible decirle que termine la 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 "move();". Algo diferente al factorial ¿no?
+¿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:
+...
+void recursiva () {
+if (frontIsClear) {
+move();
+recursiva();
+putbeeper();
+}
+}
+...
+Ahora pruébalo.
+¡Wow! ¡Sorprendente! ¿Por qué funciona?
+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 "putbeeper();". 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).
+¿Recuerdas los parámetros? ¿Recuerdas las funciones pred() y succ()? ¿Que pasaría si a una instrucción con parámtro la llamaramos usando pred() o succ()?
+Todo esto, en Karel es posible, definamos una instrucción con parámetros y volvámosla recursiva usando succ():
+...
+void recursiva2 (n) {
+if (frontIsClear) {
+move();
+recursiva2 ( succ (n) );
+}
+else {
+iterate(n) {
+putbeeper();
+}
+}
+}
+...
+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 pred() y iszero() 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.
+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 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.
+...
+void multiplica (n) {
+if (nextToABeeper) {
+pickbeeper();
+multiplica(n);
+iterate (n) {
+putbeeper();
+}
+}
+else {
+veAlInicio();
+}
+}
+void cuenta (n) {
+if (nextToABeeper) {
+pickbeeper();
+cuenta( sucede (n) );
+}
+else {
+move();
+multiplica (n);
+}
+}
+...
+Esta casi completa, pero le falta implementar la instrucción veAlInicio (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.
+En este problema se usan casi todos los temas vistos en el curso, emplealos y resuélvelo.
++
Hemos llegado al fin del curso, ahora debes ser capaz de participar en la Olimpiada Mexicana de Informatica, no olvides seguir resolviendo problemas para mejorar siempre tus habilidades, puedes encontrar ligas a las páginas en donde hay problemas en la página principal de la OMI.
+¡SUERTE!
++Nosotros programaremos Karel, un Robot simple que vive en un mundo simple. Debido a que Karel y su mundo son simulados, ¡nosotros podemos realmente ver los resultados de un programa en acción ! El lenguaje con el que programaremos Karel es una versión especial de JAVA, por lo tanto, la mayor parte de lo que aprendamos, podrá ser aplicado directamente al lenguaje de programación estándar JAVA.
+Por qué programamos Karel
+ ++
+Esta ventana muestra las calles y avenidas que usa Karel para desplazarse. Primero debemos inicializar (o crear) el mundo que Karel va a ocupar. La idea es que puedas introducir algunos elementos en el mundo inicial de Karel.
++Puedes colocar y quitar muros en el Norte, Sur, Este u Oeste del cursor dando click con el botón izquierdo del ratón en la intersección de las calles correspondientes. Los muros que limitan las calles y avenidas no se pueden quitar, éstos son los que previenen que Karel se salga del mundo. Prueba a introducir algunos muros para ver que aspecto tienen.
++ Otro elemento de interés en el mundo de Karel son los zumbadores. Un zumbador es una forma de marca que Karel puede escuchar sólo cuando se encuentra en la misma esquina que el zumbador. Karel tiene una mochila que puede utilizar para poner los zumbadores que vaya cogiendo. También puede hacer lo contrario, es decir, sacar los zumbadores de su mochila y depositarlos en las esquinas por las que va pasando. Puedes ajustar el número inicial de zumbadores en cada esquina dando click con el botón derecho del ratón en la calle deseada y seleccionando el número de zumbadores deseados (para colocar entre 10 y 99 zumbadores, selecciona la opción N zumbadores y escribe el número deseado).
++Prueba a poner algunos zumbadores para ver como se visualizan en el mundo. Crea el mundo inicial que se muestra a continuación. +Dado que hemos realizado todo el trabajo necesario para crear un mundo para Karel, ¡vamos a guardarlo ! Pulsa sobre el botón Guardar, ve a tu directorio particular y guarda el mundo como “NuevoMundo.mdo”
++
+ Finalmente, ¡Karel tiene su sitio en el mundo! Mueve el cursor del ratón hacia la esquina de la Avenida 15 y Calle 1 y da click con el botón derecho del mouse, situa el puntero del ratón en la opción "Situar a Karel" y elige "Orientado al Oeste". Ahora deberías visualizar el mundo de abajo. Haz de nuevo click sobre el botón "Guardar" , para almacenar los cambios.
++
El mundo de Karel
+ ++
+Esta ventana muestra las calles y avenidas que usa Karel para desplazarse. Primero debemos inicializar (o crear) el mundo que Karel va a ocupar. La idea es que puedas introducir algunos elementos en el mundo inicial de Karel.
+Puedes colocar y quitar muros en el Norte, Sur, Este u Oeste del cursor dando click con el botón izquierdo del ratón en la intersección de las calles correspondientes. Los muros que limitan las calles y avenidas no se pueden quitar, éstos son los que previenen que Karel se salga del mundo. Prueba a introducir algunos muros para ver que aspecto tienen.
+Otro elemento de interés en el mundo de Karel son los zumbadores. Un zumbador es una forma de marca que Karel puede escuchar sólo cuando se encuentra en la misma esquina que el zumbador. Karel tiene una mochila que puede utilizar para poner los zumbadores que vaya cogiendo. También puede hacer lo contrario, es decir, sacar los zumbadores de su mochila y depositarlos en las esquinas por las que va pasando. Puedes ajustar el número inicial de zumbadores en cada esquina dando click con el botón derecho del ratón en la calle deseada y seleccionando el número de zumbadores deseados (para colocar entre 10 y 99 zumbadores, selecciona la opción N zumbadores y escribe el número deseado).
+Prueba a poner algunos zumbadores para ver como se visualizan en el mundo. Crea el mundo inicial que se muestra a continuación. Dado que hemos realizado todo el trabajo necesario para crear un mundo para Karel, ¡vamos a guardarlo ! Pulsa sobre el botón Guardar, ve a tu directorio particular y guarda el mundo como “NuevoMundo.mdo”
++
+ Finalmente, ¡Karel tiene su sitio en el mundo! Mueve el cursor del ratón hacia la esquina de la Avenida 15 y Calle 1 y da click con el botón derecho del mouse, situa el puntero del ratón en la opción "Situar a Karel" y elige "Orientado al Oeste". Ahora deberías visualizar el mundo de abajo. Haz de nuevo click sobre el botón "Guardar" , para almacenar los cambios.
++
El mundo de Karel
+ ++
+ Pulsa en el botón "Nuevo ". Un esqueleto del programa será creado automáticamente. Se creará un programa inicial. Este programa inicial contiene los comandos básicos que son necesarios en cada programa. Ahora deberías ver una ventana como la siguiente.
++
+ Date cuenta de que el programa anterior sólo le dice a Karel que se apague. Antes de apagarlo, vamos a mandarle algunas tareas. La orden "avanza" le dice a Karel que se mueva hacia adelante una esquina. Escribe "avanza;" antes de"apagate;" . Date cuenta de que el punto y coma se usa para separar órdenes (tal como en Pascal). Ahora pulsa el botón "Compilar". Si no has cometido ningún error, tu programa tendrás el aspecto del de la ventana siguiente:
++
+ + Pulsa la pestaña de Ejecutar, y después haz click en el botón Inicializar . (Ejecutar inicia la ejecución (correr) de nuestro programa. Al Inicializar, se muestra el mundo que habíamos creado previamente (NuevoMundo.mdo)). Ahora deberías ver la ventana de abajo (asumiendo que el fichero “NuevoMundo.mdo” que creaste está todavía abierto. Si no, pulsa en la pestaña “Mundo”, y pulsando en el botón “Abrir”, selecciona el fichero “NuevoMundo.mdo” que guardaste en el punto anterior).
++
+ Cuando des click en adelante podrás darte cuenta que la instrucción "avanza;" se colorea de rojo. En este punto haz click en “Adelante” para que Karel realice esa primera orden del programa. ¡Wow, Karel se ha movido solo ! Date cuenta que la instrucción en rojo ahora es "apagate;". Haz click sobre “Adelante”de nuevo. Ahora el programa terminará correctamente. Si quieres probarlo otra vez, antes tendrás que pulsar sobre el botón "Inicializar".
++ + Ejercicio 1 : Escribe un programa de Karel para que se mueva a la esquina de la 1ª Calle con la 1ª Avenida y se desconecte, asumiendo que empieza en la esquina de la Calle 15 y la Avenida 15 con orientación hacia el Oeste. Guarda el programa con el nombre “primerPrograma.txt”. Como mundo utiliza el guardado anteriormente con el nombre “NuevoMundo.mdo”.
++¡¡ Inténtalo !!
++
+ El lenguaje por default es Pascal, para programar en JAVA, selecciona la opción que viene a la izquierda de los botones. Ahora pulsa en el botón "Nuevo ". Un esqueleto del programa será creado automáticamente. Se creará un programa inicial. Este programa inicial contiene los comandos básicos que son necesarios en cada programa. Ahora deberías ver una ventana como la siguiente.
++
+ Date cuenta de que el programa anterior sólo le dice a Karel que se apague. Antes de apagarlo, vamos a mandarle algunas tareas. La orden "move" le dice a Karel que se mueva hacia adelante una esquina. Escribe "move();" antes de"turnoff();" . Date cuenta de que el punto y coma se usa para separar órdenes (tal como en JAVA). Ahora pulsa el botón "Compilar". Si no has cometido ningún error, tu programa tendrás el aspecto del de la ventana siguiente:
++
+ + Pulsa la pestaña de Ejecutar, y después haz click en el botón Inicializar . (Ejecutar inicia la ejecución (correr) de nuestro programa. Al Inicializar, se muestra el mundo que habíamos creado previamente (NuevoMundo.mdo)). Ahora deberías ver la ventana de abajo (asumiendo que el fichero “NuevoMundo.mdo” que creaste está todavía abierto. Si no, pulsa en la pestaña “Mundo”, y pulsando en el botón “Abrir”, selecciona el fichero “NuevoMundo.mdo” que guardaste en el punto anterior).
++
+ Cuando des click en adelante podrás darte cuenta que la instrucción "move();" se colorea de rojo. En este punto haz click en “Adelante” para que Karel realice esa primera orden del programa. ¡Wow, Karel se ha movido solo ! Date cuenta que la instrucción en rojo ahora es "turnoff();". Haz click sobre “Adelante”de nuevo. Ahora el programa terminará correctamente. Si quieres probarlo otra vez, antes tendrás que pulsar sobre el botón "Inicializar".
++ + Ejercicio 1 : Escribe un programa de Karel para que se mueva a la esquina de la 1ª Calle con la 1ª Avenida y se desconecte, asumiendo que empieza en la esquina de la Calle 15 y la Avenida 15 con orientación hacia el Oeste. Guarda el programa con el nombre “primerPrograma.txt”. Como mundo utiliza el guardado anteriormente con el nombre “NuevoMundo.mdo”.
++¡¡ Inténtalo !!
++
+
+
+
+
La salud de Karel
+Andar entre muros no es bueno para un robot, por lo tanto Karel tiene +algunos mecanismos salvavidas dentro de él. Si un programa le dice +a Karel que se mueva aunque haya un muro delante de él, él +dirá que hay un error y no realizará la acción. Lo mismo +ocurrirá si le decimos que coja un zumbador en una esquina y no existe +ninguno. Las únicas órdenes que siempre lleva a cabo sin importar +la situación en la que se encuentre son gira-izquierda y apagate. +Cuando Karel nos dice que hay un error, no tenemos que echarle la culpa, +sino que probablemente habremos escrito mal alguna instrucción.
+Ejercicio 2 : Cada mañana Karel se levanta de la cama y +tiene que recoger el periódico, representado por un zumbador, que +está en el porche de la casa. Escribe un programa que ordene +a Karel que recoja el periódico y lo lleve de vuelta a la cama. La +situación inicial es la de la imagen de abajo, y la situación +final debe tener a Karel de vuelta en la cama (misma esquina, misma dirección +que cuando empezó) con el periódico (zumbador en su mochila). +Crea un mundo como el de la imagen y guárdalo como “periodico.mdo”. +
++
+
+
+
+
+
La salud de Karel
+Andar entre muros no es bueno para un robot, por lo tanto Karel tiene +algunos mecanismos salvavidas dentro de él. Si un programa le dice +a Karel que se mueva aunque haya un muro delante de él, él +dirá que hay un error y no realizará la acción. Lo mismo +ocurrirá si le decimos que coja un zumbador en una esquina y no existe +ninguno. Las únicas órdenes que siempre lleva a cabo sin importar +la situación en la que se encuentre son turnleft() y turnoff(). +Cuando Karel nos dice que hay un error, no tenemos que echarle la culpa, +sino que probablemente habremos escrito mal alguna instrucción.
+Ejercicio 2 : Cada mañana Karel se levanta de la cama y +tiene que recoger el periódico, representado por un zumbador, que +está en el porche de la casa. Escribe un programa que ordene +a Karel que recoja el periódico y lo lleve de vuelta a la cama. La +situación inicial es la de la imagen de abajo, y la situación +final debe tener a Karel de vuelta en la cama (misma esquina, misma dirección +que cuando empezó) con el periódico (zumbador en su mochila). +Crea un mundo como el de la imagen y guárdalo como “periodico.mdo”. +
++
+
++Siempre a continuación de las sentencias de control entonces , veces, sino, y hacer van seguidas de la palabra inicio para iniciar el grupo de sentencias a ser realizado. El grupo de sentencias va seguido de la palabra fin. Utilizamos el par inicio/fin para un sólo parámetro o para varios, no importa el número de ellos. El compilador devolverá una advertencia en caso de que no se siga este estilo.
++Nota: Un punto y coma no debe estar a continuación de un inicio, pero sí es necesario a continuación de un fin (excepto cuando precede una sentencia sino).
+Sentencias de Control de KAREL
+ ++
++Siempre a continuación de las sentencias de control y después de la expresión booleana, se debe colocar una llave que abre "{" para iniciar el grupo de sentencias a ser realizado. El grupo de sentencias va seguido de una llave que cierra "}". Utilizamos el par "{ }" para un sólo parámetro o para varios, no importa el número de ellos. El compilador devolverá una advertencia en caso de que no se siga este estilo.
+Sentencias de Control de KAREL
+ +...
++ si orientado-al-sur entonces inicio
++ gira-izquierda;
++ gira-izquierda;
++ gira-izquierda;
++ fin ;
++...
++Las líneas " ... " significan que pueden haber otras sentencias antes o después de la sentencia si . Nos da igual en esta explicación ya que no hay restricciones en cuanto a lo que hay antes o después de la sentencia si.
++ +La forma más general de la sentencia si es:
+...
++ si xxx entonces inicio
++ yyy
++ fin ;
++ ...
+donde xxx es una condición y yyy es cualquier número de sentencias a ejecutar si la condición si es verdadera. +
+La sentencia Si/Entonces
+Regresar +
+...
++ if (facingSouth) {
++ turnleft();
++ turnleft();
++ turnleft();
++ }
+...
++Las líneas " ... " significan que pueden haber otras sentencias antes o después de la sentencia if. Nos da igual en esta explicación ya que no hay restricciones en cuanto a lo que hay antes o después de la sentencia if.
++ +La forma más general de la sentencia if es:
+...
++ if (xxx) {
++ yyy
++ }
++ ...
++donde xxx es una condición y yyy es cualquier número de sentencias a ejecutar si la condición if es verdadera.
+La sentencia if
+ ++
+...+ si orientado-al-sur entonces inicio
++ gira-izquierda;
++ gira-izquierda;
++ gira-izquierda;
++ fin ;
++ ...
++La condición es una función de la situación actual de Karel, a medida que se ejecuta el programa. Si Karel está actualmente orientado hacia el Sur, el valor de la función orientado-al-sur será verdadero, y el conjunto de sentencias entre el par inicio/fin, se ejecutará. De otra manera, el valor orientado-al-sur será falso y el bloque de sentencias se saltará. Karel comprende cualquier función booleana que comprueba su situación actual. Aquí hay un listado:
++ +
+frente-libre | +junto-a-zumbador | +orientado-al-este | +
frente-bloqueado | +no-junto-a-zumbador | +orientado-al-oeste | +
izquierda-libre | +algun-zumbador-en-la-mochila | +no-orientado-al-norte | +
izquierda-bloqueada | +ningun-zumbador-en-la-mochila | +no-orientado-al-sur | +
derecha-libre | +orientado-al-norte | +no-orientado-al-este | +
derecha-bloqueada | +orientado-al-sur | +no-orientado-al-oeste | +
+ +"libre" significa que no hay ningún muro, mientras que "bloqueado" significa que hay un muro en esa dirección. Karel puede detectar si hay o no algún zumbador en la esquina en la que se encuentra actualmente, así como detectar si tiene algún zumbador en la mochila o no. También tiene una brújula para detectar hacia qué dirección está orientado.
+Por si fuera poco podemos unir dos o más funciones booleanas con los operadores lógicos Y, O, y NO.
+Podemos ver la síntaxis de los operadores y sus valores con las siguientes tablas:
+Síntaxis: función-booleana1 y función-booleana2
+ +Valor de la función 1 | +Valor de la función 2 | +Resultado final | +
falso | +falso | +falso | +
falso | +verdadero | +falso | +
verdadero | +falso | +falso | +
verdadero | +verdadero | +verdadero | +
Síntaxis: función-booleana1 o función-booleana2
+ +Valor de la función 1 | +Valor de la función 2 | +Resultado final | +
falso | +falso | +falso | +
falso | +verdadero | +verdadero | +
verdadero | +falso | +verdadero | +
verdadero | +verdadero | +verdadero | +
Síntaxis: no función-booleana
+ +Valor de la función | +Resultado final | +
falso | +verdadero | +
verdadero | +falso | +
Los operadores "y" y "o" se aplican sobre dos funciones y el operador "no" solo sobre una. Lo mejor de los operadores lógicos es que si ponemos dentro de un par de paréntesis las funciones con el operador lógico, entonces toda la operación se vuelve una función booleana, por lo que podemos aplicar más operadores lógicos sobre ella. ¿No quedó claro? Revisa estos ejemplos:
+(orientado-al-norte o orientado-al-sur) y frente-libre
+(no (frente-bloqueado y junto-a-zumbador)) o orientado-al-este
+no (junto-a-zumbador y frente-libre)
+Ten mucho cuidado de colocar bien los paréntesis, ya que si no lo haces, no te marcará error, pero seguramente hará algo extraño que tu no quieres que haga.
+Por ejemplo, si queremos que Karel avance si está viendo al norte y el frente esté libre, podemos hacer lo siguiente:
+ ...
si orientado-al-norte y frente-libre entonces inicio
+avanza;
+fin;
+...
++Ejercicio 3 : Escribe un programa de Karel que haga que Karel esté orientado al Norte, desde cualquier dirección inicial, y a continuación se apague. Debería terminar en la misma intersección en la que empezó.
++¿Alguna sugerencia?
++En un mundo nuevo inserta el ejemplo visto arriba para el caso en que Karel está orientado hacia el Sur. Pero, ¿qué ocurre cuando no está orientado hacia el Sur?. ¡Podría estar también orientado hacia el Norte o el Este !. Entonces necesitas dos sentencias si adicionales, en las cuales se especifique que es lo que debe hacer Karel en esas situaciones.
++Modifica el mundo inicial de Karel para probar cualquiera de las 4 direcciones de inicio, y para cada una de ellas vuelve a ejecutar el programa.
++En esta sección hemos visto como usar las sentencias de control para adaptar Karel a cada situación.
+Condiciones que puede detectar Karel
+ ++
+...+ if (facingSouth) {
++ turnleft();
++ turnleft();
++ turnleft();
++ }
++ ...
++La condición es una función de la situación actual de Karel, a medida que se ejecuta el programa. Si Karel está actualmente orientado hacia el Sur, el valor de la función facingSouth será verdadero, y el conjunto de sentencias entre las llaves "{ }", se ejecutará. De otra manera, el valor facingSouth será falso y el bloque de sentencias se saltará. Karel comprende cualquier función booleana que comprueba su situación actual. Aquí hay un listado:
++ +
+frontIsClear | +nextToABeeper | +facingEast | +
frontIsBlocked | +notNextToABeeper | +facingWest | +
leftIsClear | +anyBeepersInBeeperBag | +notFacingNorth | +
leftIsBlocked | +noBeepersInBeeperBag | +notFacingSouth | +
rightIsClear | +facingNorth | +notFacingEast | +
rightIsBlocked | +facingSouth | +notFacingWest | +
+ +"clear" significa que no hay ningún muro, mientras que "blocked" significa que hay un muro en esa dirección. Karel puede detectar si hay o no algún zumbador en la esquina en la que se encuentra actualmente, así como detectar si tiene algún zumbador en la mochila o no. También tiene una brújula para detectar hacia qué dirección está orientado.
+Por si fuera poco podemos unir dos o más funciones booleanas con los operadores lógicos Y, O, y NO.
+Podemos ver la síntaxis de los operadores y sus valores con las siguientes tablas:
+ +Síntaxis: funciónBooleana1 && funciónBooleana2
+ +Valor de la función 1 | +Valor de la función 2 | +Resultado final | +
falso | +falso | +falso | +
falso | +verdadero | +falso | +
verdadero | +falso | +falso | +
verdadero | +verdadero | +verdadero | +
Síntaxis: función-booleana1 || función-booleana2
+ +Valor de la función 1 | +Valor de la función 2 | +Resultado final | +
falso | +falso | +falso | +
falso | +verdadero | +verdadero | +
verdadero | +falso | +verdadero | +
verdadero | +verdadero | +verdadero | +
Síntaxis: ! función-booleana
+ +Valor de la función | +Resultado final | +
falso | +verdadero | +
verdadero | +falso | +
Los operadores "&&" y "||" se aplican sobre dos funciones y el operador "!" solo sobre una. Lo mejor de los operadores lógicos es que si ponemos dentro de un par de paréntesis las funciones con el operador lógico, entonces toda la operación se vuelve una función booleana, por lo que podemos aplicar más operadores lógicos sobre ella. ¿No quedó claro? Revisa estos ejemplos:
+(facingNorth || facingSouth) && frontIsClear
+(! (frontIsBlocked && nextToABeeper)) || facingEast
+! (nextToABeeper && frontIsClear)
+Ten mucho cuidado de colocar bien los paréntesis, ya que si no lo haces, no te marcará error, pero seguramente hará algo extraño que tu no quieres que haga.
+Por ejemplo, si queremos que Karel avance si está viendo al norte y el frente esté libre, podemos hacer lo siguiente:
+ ...
if (facingNorth && frontIsClear) {
+move();
+}
+...
++Ejercicio 3 : Escribe un programa de Karel que haga que Karel esté orientado al Norte, desde cualquier dirección inicial, y a continuación se apague. Debería terminar en la misma intersección en la que empezó.
++¿Alguna sugerencia?
++En un mundo nuevo inserta el ejemplo visto arriba para el caso en que Karel está orientado hacia el Sur. Pero, ¿qué ocurre cuando no está orientado hacia el Sur?. ¡Podría estar también orientado hacia el Norte o el Este !. Entonces necesitas dos sentencias if adicionales, en las cuales se especifique que es lo que debe hacer Karel en esas situaciones.
+Modifica el mundo inicial de Karel para probar cualquiera de las 4 direcciones de inicio, y para cada una de ellas vuelve a ejecutar el programa.
+En esta sección hemos visto como usar las sentencias de control para adaptar Karel a cada situación.
+Condiciones que puede detectar Karel
+ +...
++ repetir xxx veces inicio
++ yyy
++ fin ;
++...
++ donde xxx debe ser un número entero positivo, y yyy representa cualquier número de sentencias de Karel. El problema de los 14 avances podría haberse escrito :
+...
++ repetir 14 veces inicio
++ avanza ;
++ fin ;
++...
++Ejercicio 4: Asume que Karel está en la esquina de la 8ª Avenida y la 8ª Calle, con el escenario que se ve en la siguiente imagen. Escribe un programa que haga a Karel recoger todos los zumbadores y acabe en la 1ª esquina orientado al Sur.
++
+¿Crees que es muy difícil?
++Bien… puede ser que un poco de ayuda venga bien. Si puedes imaginar como hacerlo una vez (el primer zumbador de la esquina 7,7), la sentencia repetir lo hará tantas veces como tú quieras.
++Crea un mundo como el de arriba y guárdalo con el nombre “diagonal.mdo”. Escribe el programa y guárdalo con el nombre “diagonal.txt”. Asegurate de utilizar la sentencia repetir/veces. Prueba el programa en este mundo inicial. Karel debería terminar en la esquina de la primera Avenida con la primera Calle, y llevando 7 zumbadores en la mochila.
+ ++
+... ++ iterate (xxx) {
++ yyy
++ }
++...
++ donde xxx debe ser un número entero positivo, y yyy representa cualquier número de sentencias de Karel. El problema de los 14 avances podría haberse escrito :
++
+... ++ iterate (14) {
++ move();
++ }
++...
++Ejercicio 4: Asume que Karel está en la esquina de la 8ª Avenida y la 8ª Calle, con el escenario que se ve en la siguiente imagen. Escribe un programa que haga a Karel recoger todos los zumbadores y acabe en la 1ª esquina orientado al Sur.
++
+¿Crees que es muy difícil?
++Bien… puede ser que un poco de ayuda venga bien. Si puedes imaginar como hacerlo una vez (el primer zumbador de la esquina 7,7), la sentencia repite lo hará tantas veces como tú quieras.
++Crea un mundo como el de arriba y guárdalo con el nombre “diagonal.mdo”. Escribe el programa y guárdalo con el nombre "diagonal.txt”. Asegurate de utilizar la sentencia iterate. Prueba el programa en este mundo inicial. Karel debería terminar en la esquina de la primera Avenida con la primera Calle, y llevando 7 zumbadores en la mochila.
+ +...
++ si xxx entonces inicio
++ yyy
++ fin
++ sino inicio
++ zzz
++ fin ;
++...
++ donde xxx es una condición, yyy son sentencias a realizar si xxx es verdadero, y zzz son las sentencias a ejecutar si xxx es falso.
++Ejercicio 5 : Karel tiene la tarea de alinear una colección de zumbadores en la primera Calle que ha sido distribuida desigualmente. Empieza en la 1ª Calle y la 15ª Avenida y está orientado al Oeste. Se supone que en cada esquina hay exactamente un zumbador. Sin embargo, Karel puede encontrar 0, 1 o 2 zumbadores en cualquier intersección. Su tarea es asegurar que exactamente hay un zumbador antes de continuar hacia la siguiente esquina. Cuando llega a la esquina 1,1 debe apagarse.
++ Diseña el mundo inicial para que Karel comience en la esquina 1,15 orientado hacia el Oeste. Karel debe empezar con 15 zumbadores en la mochila. Aleatoriamente sitúa 1 o 2 zumbadores en esquinas a lo largo de la 1ª Calle, y deja alguna sin zumbadores. Guarda tu mundo inicial con el nombre “lineaDeZumbadores.mdo”.
++ Escribe el programa para hacer que Karel complete la tarea descrita anteriormente. Guarda tu programa con el nombre “lineaDeZumbadores.txt”. + Truco: utiliza repetir/veces, un Si/Entonces/Sino, y un Si/Entonces.
++ Recuerda, ¡no sabemos qué esquinas tienen el número equivocado de zumbadores! Karel debe hacer la tarea correctamente independientemente del nº de zumbadores que haya en cada esquina.
+ +...
++ if (xxx) {
++ yyy
++ }
++ else {
++ zzz
++ }
++...
+donde xxx es una condición, yyy son sentencias a realizar si xxx es verdadero, y zzz son las sentencias a ejecutar si xxx es falso.
++Ejercicio 5 : Karel tiene la tarea de alinear una colección de zumbadores en la primera Calle que ha sido distribuida desigualmente. Empieza en la 1ª Calle y la 15ª Avenida y está orientado al Oeste. Se supone que en cada esquina hay exactamente un zumbador. Sin embargo, Karel puede encontrar 0, 1 o 2 zumbadores en cualquier intersección. Su tarea es asegurar que exactamente hay un zumbador antes de continuar hacia la siguiente esquina. Cuando llega a la esquina 1,1 debe apagarse.
++ Diseña el mundo inicial para que Karel comience en la esquina 1,15 orientado hacia el Oeste. Karel debe empezar con 15 zumbadores en la mochila. Aleatoriamente sitúa 1 o 2 zumbadores en esquinas a lo largo de la 1ª Calle, y deja alguna sin zumbadores. Guarda tu mundo inicial con el nombre “lineaDeZumbadores.mdo”.
++ Escribe el programa para hacer que Karel complete la tarea descrita anteriormente. Guarda tu programa con el nombre “lineaDeZumbadores.txt”. + Truco: utiliza iterate, un if/else, y un if.
++ Recuerda, ¡no sabemos qué esquinas tienen el número equivocado de zumbadores! Karel debe hacer la tarea correctamente independientemente del nº de zumbadores que haya en cada esquina.
+ +