cuaderno teórico de gobstones

44
Cuaderno Teórico de Gobstones Introducción Este cuaderno complementa las actividades diseñadas en Gobstones con información teórica. Si bien las actividades en sí mismas son importantes, también lo son las conclusiones a las que arribamos sobre los conceptos que se van presentando en un curso. El objetivo de este documento es sólo el de aproximar un poco de teoría a las actividades. Si se desean estudiar estos temas en profundidad, deben tomarse cursos acordes o consultar bibliografía adecuada para tal fin. Temario Los contenidos son explicados en el orden en que deseamos sean presentados. Programas, valores y comandos Procedimientos Subtareas Comentarios y precondiciones Parametrización Otro ejemplo de parametrización Repetición Repetición indexada Alternativa condicional Repetición condicional Recorridos Recorridos por todo el tablero Variables Programas, valores y comandos Si bien en Scratch se programa combinando y encajando bloques entre sí, actualmente la mayoría de los programadores no define programas de

Upload: cristianlp

Post on 09-Sep-2015

79 views

Category:

Documents


9 download

DESCRIPTION

Gobstones

TRANSCRIPT

Cuaderno Terico de Gobstones

Introduccin

Este cuaderno complementa las actividades diseadas en Gobstones con informacin terica. Si bien las actividades en s mismas son importantes, tambin lo son las conclusiones a las que arribamos sobre los conceptos que se van presentando en un curso.

El objetivo de este documento es slo el de aproximar un poco de teora a las actividades. Si se desean estudiar estos temas en profundidad, deben tomarse cursos acordes o consultar bibliografa adecuada para tal fin.

Temario

Los contenidos son explicados en el orden en que deseamos sean presentados.Programas, valores y comandosProcedimientosSubtareasComentarios y precondicionesParametrizacinOtro ejemplo de parametrizacinRepeticinRepeticin indexadaAlternativa condicionalRepeticin condicionalRecorridosRecorridos por todo el tableroVariables

Programas, valores y comandosSi bien en Scratch se programa combinando y encajando bloques entre s, actualmente la mayora de los programadores no define programas de esta manera. En cambio, desarrollan programas escribiendo texto en cierto lenguaje de programacin, tarea que se conoce como codificar. Por ende los programas son definidos como descripciones ejecutables. Descripciones porque lo que define un programa es un texto, distinto a los que escribimos en espaol porque conlleva seguir una serie de reglas estrictas que estn incluidas en el lenguaje de programacin, a la que llamamos sintaxis; y ejecutables porque esta descripcin debe poder ser ejecutada por una computadora.En este caso utilizaremos un lenguaje de programacin llamado Gobstones, el cual permite presentar conceptos bsicos de programacin. En Gobstones describen tableros con celdas que contienen bolitas de colores. Adems todo tablero posee un cabezal apuntando a una determinada celda del mismo.

Por otra parte, el lenguaje posee valores y comandos. Los valores son simples datos, y en Gobstones (por ahora) disponemos de colores, direcciones, nmeros y booleanos. Los colores pueden ser Azul, Negro, Rojo y Verde; las direcciones pueden ser Norte, Sur, Este y Oeste; los nmeros ya los conocemos (1, 54145, 23, etc), y los booleanos simplemente son True (verdadero) y False (falso).

Por su parte, los comandos, que son acciones dirigidas al cabezal del tablero, consisten en: Poner, que toma un color y pone una bolita de ese color en la celda a la que apunta el cabezal. Mover, que toma una direccin y mueve el cabezal hacia dicha direccin. Sacar, que toma un color y saca una bolita de ese color en la celda a la que apunta el cabezal. Un programa Gobstones siempre empieza de la siguiente manera: program{ }

Las llaves encierran un bloque de cdigo, y dentro de todo bloque de cdigo podemos ejecutar los comandos antes mencionados.

Para aquellos que anteriormente usaron Scratch, estas llaves son similares a los huecos que poseen algunos bloques:

En Gobstones hay reglas que hay que respetar: Los nombres de comandos empiezan con mayscula Los nombres de valores empiezan con mayscula Los nombres de procedimientos empiezan con mayscula procedure empieza con minscula Los bloques de cdigo quedan definidos por una llave que abre y otra que cierra Para esto programar utilizaremos una herramienta denominada PyGobstones que implementa el lenguaje Gobstones. Esta herramienta consiste de un editor de textos sobre el que codificaremos y que definirn programas que al ejecutarse mostrarn un tablero final como resultado.

El siguiente programa pone una bolita de color rojo en la celda a la que apunta el cabezal actualmente (que puede ser cualquiera en un principio)

program{ Poner(Rojo)} A continuacin vern dos tableros. Uno es el inicial (izquierda) y el otro es el tablero resultante de ejecutar el programa sobre el tablero inicial (derecha)

ProcedimientosEn Gobstones podemos aprovechar un concepto que vimos en Scratch: asignar nombres a secuencias de comandos, que denominamos procedimientos. Esto se realiza con la palabra procedure seguida de un nombre a eleccin, que debe empezar con maysculas.Por ejemplo, podemos dibujar un cuadrado compuesto de lneas. Los procedimientos a utilizar podran ser LneaRoja y CuadradoRojo.program { IrAlOrigen() CuadradoRojo()}procedure CuadradoRojo(){ LineaRoja(); Mover(Norte) LineaRoja(); Mover(Norte) LineaRoja()}procedure LineaRoja(){ Poner(Rojo); Mover(Este) Poner(Rojo); Mover(Este) Poner(Rojo) Mover(Oeste); Mover(Oeste) // retornamos a la posicin inicial de la linea}

El resultado es:

SubtareasEsta idea de separar el problema en distintos procedimientos se conoce como divisin en subtareas. La idea es que CuadradoRojo utilice LneaRoja en su definicin, lo que hace que el cdigo sea ms fcil de escribir y de entender. Si, por ejemplo, luego se pide modificar el largo de la figura, slo debemos aadir una LineaRoja ms dentro del bloque de cdigo de CuadradoRojo. Si, por el contrario, queremos modificar el ancho, modificamos LineaRoja para que dibuje una bolita ms.Por otra parte, es importante definir buenos nombres de procedimientos, lo que permite intuir sin mirar el cdigo qu es lo que hace el programa, slo basndonos en los nombres de los procedimientos y cmo se relacionan entre s. Comentarios y precondicionesAdems podemos agregar comentarios en el cdigo, simplemente agregando dos barras (//) seguidas de texto en idioma cotidiano. Los comentarios son simplemente texto que no ser ejecutado pero que permiten al programador entender qu hace el programa o qu cosas debe tener en cuenta el leerlo o utilizarlo. Los comentarios son tambin tiles para definir las precondiciones de un procedimiento, que son aquello que requiere el procedimiento para ejecutarse correctamente. En este caso la precondicin sera:// Precondicin: el cuadrado necesita un espacio de 3x3 para poder ser dibujado.As como sucede en Scratch, ciertos comandos requieren ciertas condiciones para no fallar, y en este caso, el comando Mover, requiere que haya una celda hacia la direccin en la que se desplaza el cabezal. Si esta celda no existe, el programa terminar de forma abrupta. Otro comando que puede fallar es Sacar, si no hay bolitas del color a sacar en la celda actual.ParametrizacinUna actividad que podemos realizar sobre el cuadrado anterior es cambiar el color con el que se dibuja, de Rojo a Verde. Lo que haremos ser buscar cada comando Poner que haba y lo modificaremos para que ponga una bolita del nuevo color. Tambin modificaremos los nombres de procedimientos para que reflejen este cambio de color:procedure LineaVerde(){ Poner(Verde); Mover(Este) // Antes deca Poner(Rojo) Poner(Verde); Mover(Este) Poner(Verde) Mover(Oeste); Mover(Oeste) // retornamos a la posicin inicial de la linea} procedure CuadradoVerde(){LineaVerde(); Mover(Norte)LineaVerde(); Mover(Norte)LineaVerde()}Si nuevamente pedimos que vuelvan a cambiar el color por otro de los existentes harn lo mismo: buscar dnde figura el color actual para cambiarlo por otro color, siempre modificando el cdigo de los procedimientos.No obstante, no es prctico andar modificando el procedimiento para elegir de qu color deseamos pintar un cuadrado. De esta manera, existe un mecanismo mucho mejor para hacer esto, que permite seleccionar un determinado valor al momento de invocar un procedimiento. Esto posibilita como usuarios del procedimiento elegir el color a dibujar al momento de utilizarlo. De esta manera, podramos escribir los cuatro cuadrados de cada color posible como:program{IrAlOrigen(); Cuadrado(Rojo)IrAlOrigen(); Cuadrado(Azul)IrAlOrigen(); Cuadrado(Verde)IrAlOrigen(); Cuadrado(Negro)}

Esta es una tcnica ya utilizada con los comandos Poner, Mover y Sacar, es decir, indicamos con qu valor deseamos que trabajar al invocar el procedimiento. Al que brindabamos al momento de utilizar al procedimiento lo llamaremos parmetro, y para que el procedimiento pueda utilizarlo debemos modificar lo siguiente:procedure Cuadrado(colorDeCuadrado){ }procedure Linea(colorDeLinea){ }Como puede observarse, aadimos un nombre con mnusculas (a eleccin) entre los parntesis a continuacin de los procedimientos que deben elegir el color a dibujar. Como Cuadrado utiliza Linea, este ltimo tambin necesitar definir este color arbitrario. El nombre que inventamos, al invocar el procedimiento, es reemplazado en todas sus apariciones por un valor concreto (Rojo, Verde, Azul o Negro), pero nos permite mientras tanto, utilizarlo para ocupar el lugar de aquellos valores concretos, aunque no sepamos cul ser elegido todava. A la accin de aadir un parmetro al procedimiento para reemplazar un valor concreto dentro de ste, la denominaremos parametrizar.El ejemplo completo de Cuadrado parametrizando este valor es: program { IrAlOrigen(); Cuadrado(Azul) IrAlOrigen(); Cuadrado(Rojo) IrAlOrigen(); Cuadrado(Negro) IrAlOrigen(); Cuadrado(Verde)}

procedure Cuadrado(colorDeCuadrado){ Linea(colorDeCuadrado); Mover(Norte) Linea(colorDeCuadrado); Mover(Norte) Linea(colorDeCuadrado)}procedure Linea(colorDeLinea){ Poner(colorDeLinea); Mover(Este) Poner(colorDeLinea); Mover(Este) Poner(colorDeLinea) Mover(Oeste); Mover(Oeste) // retornamos a la posicin inicial de la linea}Es stil pero interesante no utilizar exactamente el mismo nombre para los parmetros de ambos procedimientos. Para el procedimiento Cuadrado el parmetro se llama "colorDeCuadrado" y para Linea el parmetro se llama "colorDeLinea". Con esto queda en evidencia que cada uno define el nombre del parmetro para s mismo, y que cada uno utiliza este nombre dentro del bloque de cdigo que lo define (de hecho, no es posible utilizar un nombre de parmetro fuera del bloque de cdigo del procedimiento). Esto se conoce como "scoping" o alcnce del parmetro.Si este tema no queda claro, operacionalmente el pasaje de un parmetro funciona de la siguiente manera. En program indicbamos como usuarios de qu color queremos el cuadradoprogram{ IrAlOrigen() Cuadrado(Rojo)}Con escribir Cuadrado(Rojo), le indicamos al procedimiento Cuadrado que el parmetro con nombre "color" es igual a Rojo, por lo que cada aparicin de esta palabra se reemplaza por el color concreto (en este caso Rojo). Podemos pensar en dos tipos de procedimientos, uno general, antes de saber de qu color vamos a dibujar, y uno particular, cuando ya seleccionamos dicho color. Al escribir Cuadrado(Rojo), transformamos al procedimiento general en uno particular.El procedimiento general sera:procedure Cuadrado(colorDeCuadrado){ Linea(colorDeCuadrado); Mover(Norte) Linea(colorDeCuadrado); Mover(Norte) Linea(colorDeCuadrado)}que no indica (todava) con qu color particular se dibujar el cuadrado, y el procedimiento particular (cuando ya se sabe el color) sera algo como: procedure Cuadrado(Rojo) // esto es slo con fines ilustrativos, no es un programa vlido{Linea(Rojo); Mover(Norte)Linea(Rojo); Mover(Norte)Linea(Rojo)}Es la misma tarea que realizbamos a mano, pero esta vez hecha de manera automtica por el lenguaje.A su vez Linea tambin recibe el valor concreto, por lo que el procedimiento general de Linea sera:procedure Linea(colorDeLinea){ Poner(colorDeLinea); Mover(Este) Poner(colorDeLinea); Mover(Este) Poner(colorDeLinea) Mover(Oeste); Mover(Oeste) // retornamos a la posicin inicial de la linea}Y luego de aplicar el color concreto se transforma en:procedure Linea(Rojo){ Poner(Rojo); Mover(Este) Poner(Rojo); Mover(Este) Poner(Rojo) Mover(Oeste); Mover(Oeste) // retornamos a la posicin inicial de la linea}Lo mismo suceder con cada color que elijamos para dibujar el cuadrado.Otro ejemplo de parametrizacinDefinamos un procedimiento ms, que ser una variacin de dibujar un cuadrado. Dibujaremos en este caso slo el permetro del cuadrado (sin la parte interna pintada). Haremos que sea adems de color Rojo. El resultado sera:

Antes de empezar a codificar sin pensar, debemos razonar las subtareas que utilizaramos:program{ PerimetroCuadrado()}

procedure PerimetroCuadrado(){ }procedure LineaArriba(){ }procedure LineaAbajo(){ }procedure LineaIzquierda(){ }procedure LineaDerecha(){ }

de tal forma que PerimetroCuadrado quedaba definido comoprocedure PerimetroCuadrado(){LineaArriba()LineaDerecha()LineaAbajo()LineaIzquierda()}

A su vez las distintas subtareas para lineas quedan definidas comoprocedure LineaArriba(){Poner(Rojo)Mover(Norte)Poner(Rojo)Mover(Norte)Poner(Rojo)Mover(Norte)}procedure LineaAbajo(){Poner(Rojo)Mover(Sur)Poner(Rojo)Mover(Sur)Poner(Rojo)Mover(Sur)}procedure LineaDerecha(){Poner(Rojo)Mover(Este)Poner(Rojo)Mover(Este)Poner(Rojo)Mover(Este)}procedure LineaIzquierda(){Poner(Rojo)Mover(Oeste)Poner(Rojo)Mover(Oeste)Poner(Rojo)Mover(Oeste)}Como podemos observar, los cuatro procedimientos son equivalentes en todo menos en la direccin concreta hacia la que se mueven para pintar.Para reducir tanto cdigo similar, podemos parametrizar la direccin hacia donde se dibujar cada lnea, de tal manera que pasamos a tener un slo procedimiento:procedure LineaHacia(dir){Poner(Rojo)Mover(dir)Poner(Rojo)Mover(dir)Poner(Rojo)Mover(dir)}

Por lo que PerimetroCuadrado ser tan simple como:procedure PerimetroCuadrado(){LineaHacia(Norte)LineaHacia(Este)LineaHacia(Sur)LineaHacia(Oeste)}Iremos eligiendo valores concretos al momento de utilizar el procedimiento, y en LineaHacia utilizamos un nombre para designar que el valor ser reemplazado luego por algo concreto, el cual llamamos dir (por direccin)Pero si ahora tambin queremos parametrizar el color? Es tan fcil como agregar otro nombre de parmetro ms, junto a "dir", separado por una coma.procedure LineaHacia(dir, color){Poner(color)Mover(dir)Poner(color)Mover(dir)Poner(color)Mover(dir)}

Y tambin modificamos PerimetroCuadrado:procedure PerimetroCuadrado(color){LineaHacia(Norte, color)LineaHacia(Este, color)LineaHacia(Sur, color)LineaHacia(Oeste, color)}En este caso PerimetroCuadrado utiliza LineaHacia primero pasndole una direccin concreta (Norte, Este, Sur y Oeste) pero tambin pasndole el parmetro que recibe, denominado "color". LineaHacia es un procedimiento totalmente general, trabaja con una direccin y un color que todava no sabe cules son y su eleccin queda a gusto del usuario que utilice el procedimiento.Por su parte, program queda definido como:program{ PerimetroCuadrado(Rojo)}

RepeticinVeamos otro caso totalmente distinto. Definamos un procedimiento simple pero tedioso, que consista en colocar 300 bolitas de algn color. Lo llamaremos Poner300(). Para simplificarlo crearemos dos subtareas Poner10 y Poner100. De esta manera Poner300 es Poner100 3 veces y Poner100 es 10 veces Poner10:procedure Poner10(){ Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo); Poner(Rojo);}procedure Poner100(){ Poner10();Poner10();Poner10();Poner10();Poner10(); Poner10();Poner10();Poner10();Poner10();Poner10();}procedure Poner300(){ Poner100();Poner100();Poner100();}Pero qu sucede si ahora quisiramos poner 1000 bolitas, 512 bolitas, 215 bolitas, etc. El programa se torna difcil de modificar, pese a que la tarea de poner una cantidad arbitraria de bolitas debera ser trivial.En programacin solemos utilizar constantemente el concepto de repeticin, para ejecutar una cantidad arbitraria de veces cierta tarea. Gobstones posee una construccin llamada repeat, que permite repetir una tarea dependiendo de un rango de valores. Adems permite utilizar cada elemento del rango para hacer algo.En este caso poner 300 bolitas rojas sera algo tan simple comorepeat(300){ Poner(Rojo) }La parte que indica "300" representa es la cantidad de veces que queremos repetir una tarea.Ahora pensemos un procedimiento que aprovecha el poder de la repeticin colocando una cantidad de bolitas a eleccin del usuario. Nuestros procedimientos concretos que ponan una cantidad fija de bolitas se llamaran Poner300, Poner100, Poner10, etc., y ahora necesitamos algo como PonerLasQueQueramos(cantidad, color) o PonerX(cantidad, color). Con la X queremos significar nmero arbitrario, as como antes ponamos como parte del nombre de los procedimientos un nmero concreto (300, 200, 100, 10, etc.). Ahora indicamos con una X que el nmero puede ser cualquiera que elijamos. Esto es simplemente una convencin.El procedimiento que definamos deber tomar un nmero y un color, y pondr ese nmero de bolitas del color dado. Una posible definicin de program que utiliza este procedimiento puede ser:program{ PonerX(10, Rojo) // pone 10 bolitas rojas PonerX(25, Negro) // pone 25 bolitas negras PonerX(5, Verde) // pone 5 bolitas verdes}

Como podemos ver, el comportamiento del procedimiento vara cuando le pasamos parmetros distintos. El primer parmetro indicar la cantidad de bolitas a poner y el segundo de qu color queremos a estas bolitas. En la definicin de PonerX debemos utilizar estos parmetros para reflejar este comportamiento variable:procedure PonerX(cantidad, color){ // cdigo que utiliza cantidad y color}Lo primero que podemos imaginar es que debemos utilizar el comando Poner junto con el parmetro color para colocar bolitas de ese color que nos pasan por parmetro:procedure PonerX(cantidad, color){ Poner(color) ...}Esto coloca slo slo una bolita del color dado. Lo que queremos es utilizar el nmero cantidad para ejectuar exactamente ese nmero de veces el comando Poner. Aqu es donde entra en juego la repeticin.procedure PonerX(cantidad, color){repeat(cantidad){ Poner(color) }}Como podemos ver, utilizamos el parmetro cantidad junto con el repeat, en lugar de repetir un nmero concreto de veces. Si cantidad fuese 300, entonces Poner(color) se repetir 300 veces, pero en principio, dentro de la definicin de PonerX, la cantidad de veces a repetir puede ser cualquiera, siendo el usuario quien elige cuntas exactamente.De la misma manera nos podemos imaginar la implementacin de SacarX(cantidad, color), que toma un nmero y un color y saca esa cantidad de bolitas del color dado, y MoverX(cantidad, direccion), que se mueve la cantidad dada por parmetro de veces hacia la direccin dada por parmetro:procedure SacarX(cantidad, color){repeat(cantidad){ Sacar(color) }}procedure MoverX(cantidad, dir){repeat(cantidad){ Mover(dir) }}

Repeticin indexadaExiste otro tipo de repeticin, denominada repeticin indexada. En lugar de utilizar un nmero para repetir tareas una cantidad determinada de veces, esta repeticin recorre una lista de valores que sern utilizados en una tarea que hace uso de estos (generalmente se pasan por parmetro).Un ejemplo sencillo es el de poner una bolita de todos los colores posibles. Bien podramos hacer lo siguiente:procedure PonerUnaDeCadaColor(){ Poner(Azul); Poner(Negro); Poner(Rojo); Poner(Verde)}Pero utilizando una repeticin indexada, esto se resuelve tan simple como:procedure PonerUnaDeCadaColor(){ foreach color in [minColor() .. maxColor()] { Poner(color) }}En Gobstones, la repeticin indexada se denomina foreach. Es similar al repeat, dado que utiliza un bloque de cdigo para definir la tarea que va a repetirse, pero posee ms elementos: La parte que dice "color" es un ndice, es decir, es el nombre que representa a cada valor de la lista para poder utilizarlo dentro. Este nombre es totalmente inventado por nosotros, y bien podra ser otro. El ndice del foreach no puede ser utilizado en otro lado que no sea el bloque definido para esta construccin. La parte que encerrada entre corchetes representa la lista con los valores a recorrer. Como queremos arrancar desde el primer color hasta el ltimo, utilizamos las expresiones minColor() (que representa el Azul) y maxColor() (que representa el Verde), situadas entre .. (dos puntos), para que se completen de forma automtica los elementos que hay entre medio de los dos extremos. Los colores estn ordenados alfabticamente, por lo que la lista resultante ser idntica a [Azul, Negro, Rojo, Verde], pero la forma en la que construimos la lista (como un rango del mnimo al mximo valor) nos facilita no tener que escribirlos todos.Operacionalmente, el foreach pasar por cada elemento de la lista, y repetir la tarea por cada cada elemento por los que pasa. En cada momento, el ndice apuntar a un elemento distinto, y pasar por el primer valor de la lista, hasta el ltimo. En el ejemplo anterior, el ndice color, empieza valiendo Azul, luego pasa a valer Negro, prosigue con Rojo y termina siendo Verde.

Otro ejemplo sencillo es uno que utilice todas las direcciones:procedure PonerUnaEnCadaDireccion(color){ foreach dir in [minDir() .. maxDir()] { Mover(dir); Poner(color); Mover(opuesto(dir)) }}Para construir una lista con todas las direcciones utilizamos minDir() y maxDir(). La primera direccin es Norte, y la ltima es Oeste. Las direcciones estn ordenadas en sentido horario, por lo que la lista resultante de [minDir() .. maxDir()] termina siendo [Norte,Este,Sur,Oeste]. El ndice en esta ocasin lo nombramos como dir. Lo que hacemos como tarea es movernos hacia cada direccin de la lista, ponemos una bolita de un color que recibimos por parmetro, y volvemos sobre el opuesto de esa misma direccin. La expresin opuesto toma una direccin y devuelve la direccin contraria a esta. Por ejemplo, opuesto(Norte) es igual a escribir Sur, y opuesto(Oeste) es lo mismo que Este. Utilizamos esta expresin, porque no sabemos de qu direccin estamos hablando en cada momento (sabemos que va a ser alguna de la lista, pero no cul exactamente). Pero s sabemos que es una direccin, y como con toda direccin, podemos averiguar su opuesto. Esto nos permite ir y volver para cualquier direccin de la que estemos hablando.Un program construido con este procedimiento que acabamos de definir podra ser:program { IrAlOrigen(); Mover(Norte); Mover(Este) PonerUnaEnCadaDireccion(Azul)}

Los dos ejemplos mencionados, que utilizan colores y direcciones, al ser cuatro valores de cada tipo, no demoraramos mucho en enumerarlos todos a mano si quisiramos. Pero qu sucede si queremos recorrer una lista de nmeros, del 1 al 10, para realizar una tarea. Aqu el trabajo sera ms pesado.Un ejemplo como el anterior puede ser el siguiente:procedure PonerX(cantidad, color){ repeat(cantidad) { Poner(color) }}procedure ProgresionVerde(longitud){ foreach numero in [1 .. longitud] { PonerX(numero, Verde); Mover(Este) }}program{ IrAlOrigen() ProgresionVerde(10)}

PonerX, es un procedimiento definido en el apartado de Repeticin. El procedimiento a observar es ProgresionVerde, al que le pasamos un nmero y construye una sucesin de distintas cantidades de bolitas verdes, empezando por el 1 hasta el nmero que hayamos indicado. En este programa utilizamos ProgresionVerde(10), por lo que la sucesin se detiene en 10 bolitas verdes.Funciona de la siguiente manera. El parmetro es utilizado para formar la lista que se va a recorrer [1 .. longitud]. Al ndice lo nombramos numero, dado que cada elemento va a ser un nmero de al lista. El ndice es pasado a PonerX, junto con el color Verde, para que cada vez, se coloquen numero bolitas verdes, es decir, que vayan colocando bolitas verdes usando cada nmero que haya en la lista. En cada momento el cabezal es movido al Este, para que las bolitas se coloquen en distintas celdas, pero contiguas. El resultado de todo esto es el observado en la imagen.

FuncionesHasta el momento definimos nuestros propios procedimientos, que representan tareas a ejecutar sobre el tablero. Los procedimientos se componen de comandos, que son ordenados de forma secuencial en un bloque de cdigo. En sntesis, la herramienta llamada procedimiento permite asignarle un nombre a una tarea.Anteriormente vimos algo llamado expresiones, que son elementos que describen valores. Por ejemplo, la expresin 3+1 describe el valor 4 y la expresin opuesto(Norte) describe el valor Sur. Ms an, opuesto(Norte) es equivalente a Sur, y son intercambiables justamente por denotar el mismo valor. En este ejemplo opuesto representa una expresin que, al recibir una direccin, equivale a la direccin opuesta a esta. Si recibe Norte sera equivalente a Sur, si recibe Oeste sera equivalente a Este, y as con cada direccin. Esta operacin ya existe en Gobstones, al igual que existe la suma, la multiplicacin y la resta entre nmeros. Sin embargo, esta expresin opera sobre colores, a diferencia de estas ltimas que trabajan con nmeros.Tambin existen expresiones que no reciben ningn valor y directamente equivalen a uno. Por ejemplo, minColor() equivale a Azul. Con esto queremos decir que es lo mismo poner minColor() que Azul en un programa. Pero lo que sucede es que a veces conviene una forma u otra de describir lo mismo. Si en el futuro el primer color no fuese Azul sino, por ejemplo, amarillo, minColor() pasara a describir amarillo, porque su funcin es describir el primer color de los existentes en Gobstones. Si por el contrario ponemos Azul en un lugar en donde en realidad queremos el primer color existente y en el futuro cambian los colores, nuestro programa quedara desactualizado ante la nueva versin de Gobstones (cosa que pasa en muchos programas donde esto se toma a la ligera).Por lo que podemos observar, las expresiones se relacionan con valores, pueden recibir valores por parmetro y equivalen a otros valores, y se diferencian de los comandos y procedimientos, que representan tareas o acciones, dado que los valores no hacen algo, sino que simplemente son datos. De la misma manera, las expresiones no son comandos, ya que no describen acciones sino que describen valores. La expresin 3+1 no es la accin de sumar 3 a 1 sino que simplemente describe 4 al igual que 2+2 describe 4. Por ejemplo, decir repeatWith i in 1 .. 2+2 es equivalente a decir repeatWith i in 4. Y esto es lo que nos interesar cuando hablemos de expresiones: qu valor describen en ltima instancia.La nueva herramienta que veremos en esta clase sirve para ponerle un nombre a una expresin. As como antes, de manera opuesta, asignbamos nombres a tareas a travs de procedimientos, ahora asignaremos nombres a expresiones con una herramienta llamada funcin. Un ejemplo fcil es el siguiente:function igualA4(){ return(2+2)}Esta funcin simplemente equivale a la expresin 2+2. Es decir, si en un programa encontramos escrito igualA4(), la invocacin a esta funcin equivaldr a encontrar 2+2. Este simple ejemplo nos sirve para distinguir algunas cosas importantes: As como antes escribamos procedure ahora escribimos function . El nombre de una funcin empieza en minscula, contrariamente al de los procedimientos, que empieza en mayscula. Existe una palabra llamada return que significa esta funcin equivale a la siguiente expresin. Viene del ingls devolver o retornar, y esto es as porque tradicionalmente se dice que la funcin devuelve o retorna, en este caso, 2+2. Pero en lugar de decir devolver tambin podemos decir describe o equivale a la siguiente expresin. La expresin junto al return va entre parntesis.La palabra return por ahora ser la nica que encontraremos dentro del bloque de cdigo que define a la funcin.Un ejemplo un tanto ms interesante es la funcin sumarUno:function sumarUno(x){ return(x+1)}Podemos ver en este caso que las funciones tambin pueden definir parmetros. En este caso la invocacin sumarUno(2) describir al nmero 3, y la invocacin sumarUno(5) describir el nmero 6. Esto es as porque el parmetro recibido se utiliza en la expresin x+1, que describir distintos valores conforme vare el valor del parmetro.Por ltimo las funciones tambin pueden llevar una parte de procesamiento, antes de return. La palabra return siempre debe ser la ltima en dentro del bloque de cdigo que define a una funcin. Por procesamiento entendemos que podemos ejecutar comandos (y procedimientos) dentro de este bloque de cdigo.Por ejemplo, la siguiente funcin devuelve el nmero de bolitas rojas de la celda lindante al Norte:function nroDeBolitasRojasAlNorte(){ Mover(Norte) return(nroBolitas(Rojo))}Los comandos y procedimientos ejecutados antes del return, afectarn lo que describa la expresin final que describe la funcin. En este caso la expresin nroBolitas(Rojo), describe el nmero de bolitas de la celda en la que est posicionado el cabezal. Como primero nos movemos al Norte, describir la cantidad de bolitas rojas que hay una celda hacia el Norte desde donde est posicionado el cabezal al momento de ejecutar la funcin. Si no hay una celda al Norte, la funcin fallar al igual que un procedimiento. La mayor diferencia entre procedimientos y funciones con procedimiento, adems de que los procedimientos no devuelven ningn valor, es que luego del return de la funcin todos los efectos generados dentro de la funcin desaparecern. En el caso anterior, el cabezal volver a su posicin original (la posicin que tena antes de ejecutar la funcin). Esto significa que lo procesado dentro de una funcin no genera un efecto final, dado que esa es la tarea de los procedimientos y no el de las funciones. Lo procesado dentro de una funcin slo modifica el contexto dentro de esa funcin, pero luego de retornar la expresin deseada (objetivo de las funciones), los efectos internos generados son descartados (se reintegra el estado inicial antes de ejecutar la funcin).Para ilustrar mejor este efecto, podemos pensar en el siguiente procedimiento:procedure PonerTantasAzulesComoRojasHayaAlNorte(){ PonerX(nroDeBolitasRojasAlNorte(), Azul)}Analicemos qu valores pasamos como argumentos de PonerX. Por un lado (segundo parmetro) indicamos con el valor Azul el color de las bolitas a poner; y por otro lado (primer parmetro) indicamos que queremos poner exactamente la cantidad de bolitas que haya en la celda al Norte de la actual.Con el siguiente estado inicial, deberamos estar poniendo 10 bolitas de color Azul en la celda actual, copiadas de la cantidad de bolitas rojas, al Norte de esta celda: Antes de ejecutar el programa Despus de ejecutar el programaLa cantidad de bolitas rojas al Norte de la celda actual es dada por la invocacin de la funcin nroDeBolitasRojasAlNorte(), que simplemente equivale a dicho nmero. As como podramos haber escrito PonerX(10, Azul) para poner 10 bolitas azules, ahora escribimos PonerX(nroDeBolitasRojasAlNorte(), Azul) para poner exactamente tantas bolitas azules como el nmero de bolitas rojas haya al Norte. Recordamos la definicin de esta funcin:function nroDeBolitasRojasAlNorte(){ Mover(Norte) return(nroBolitas(Rojo))}En ninguna parte de la secuencia volvemos al Sur. Esto no es necesario ya que el movimiento al Norte ser eliminado luego de retornar el nmero de bolitas rojas. Es aqu entonces donde se ve que la funcin nroDeBolitasRojasAlNorte no gener efectos finales sobre el tablero sobre el que trabaja PonerX. Si bien la funcin nroDeBolitasRojasAlNorte debe moverse al Norte para devolver la cantidad de bolitas rojas de esa celda, ese movimiento no cuenta al terminar de devolver el valor deseado. Simplemente el cabezal sigue en la misma posicin sobre la cual se comenz a ejectuar el procedimiento PonerTantasRojasComoHayaAlNorte, por lo que PonerX colocar las bolitas sobre la celda actual.

Alternativa condicionalEn Gobstones tambin disponemos de lo que se conoce como alternativa condicional, una forma de condicionar la ejecucin de una tarea en base al valor de una expresin booleana. Por ejemplo: if(puedeMover(Norte)){ Mover(Norte)}La funcin puedeMover es algo existente en Gobstones. Cuando recibe una direccin indica si hay una celda en esa direccin. En este caso si al Norte no hay ms espacio (el cabezal est en el borde Norte del tablero), entonces devolver False (falso), caso contrario devolver True (verdadero). Combinando esta expresin con la alternativa condicional, si el valor de la expresin que toma entre parntesis es verdadera, entonces ejecuta la tarea que se encuentra entre las llaves (el bloque de cdigo). Si la expresin es falsa, entonces no ejecuta nada. Esto sirve para aquellos casos en donde queremos comprobar el estado de una situacin antes de ejecutar una tarea.Otro caso en donde se utiliza una alternativa, es cuando queremos ejecutar una tarea si una expresin es verdadera, y otra tarea en caso de ser falsa. Por ejemplo, imaginemos una funcin que dada una direccin marca con una bolita roja la celda en caso de estar en el borde perteneciente a esa direccin, y con una bolita azul en caso de no estar en ese borde:procedure MarcarBorde(dir){ if(not puedeMover(dir)) { Poner(Rojo) } else { Poner(Azul }}La forma de decir sino se cumple ejecutar esta otra tarea es else, a continuacin del primer bloque de cdigo de la alternativa condicional.Las alternativas condicionales tambin sirven para chequear que cierta condicin se cumpla antes de ejecutar un comando parcial:procedure MoverSiSePuede(dir){ if(puedeMover(dir)) { Mover(dir) } }Este procedimiento funcionar correctamente en todos los casos, dado que antes de ejecutar el movimiento, verifica si es posible hacerlo. Sin embargo, esto no significa que debamos siempre chequear estas condiciones, dado que podemos estar modificando el significado de lo que queremos hacer en situaciones en las que no lo deseamos. Por ejemplo, si queremos movernos 10 veces al Norte, simplemente podemos hacer:repeatWith i in 1 .. 10 { Mover(Norte) }Esta tarea fallar al no tener suficiente espacio, y no se comportar igual que esta otra:repeatWith i in 1 .. 10 { MoverSiSePuede(Norte) }El problema de esta ltima tarea es que si no hay suficiente espacio, se mover las veces que pueda. Si nuestra intencin es movernos exactamente 10 veces, esto no ser lo mismo que movernos 4, 6 u 8 veces. La tarea igualmente no se estara cumpliendo, verifiquemos o no en cada movimiento si nos vamos a caer del tablero, y probablemente sea preferible que directamente no se realice, a que se realice parcialmente. Si bien depende de lo que queramos modelar, hay que tener estos detalles en cuenta.Otra pregunta til en Gobstones es hayBolitas, que toma un color y responde si hay bolitas de ese color en la celda actual. Para qu sirve? Podemos asociarla al comando Sacar. Para el comando Sacar la precondicin que debe cumplir es que haya bolitas del color a sacar. Si queremos escribir un programa que exprese la idea de sacar de un color slo en el caso que haya bolitas de ese color, entonces necesitamos esta nueva herramienta para preguntar antes si hay o no bolitas, y en caso afirmativo sacar, y sino no hacer nada:procedure SacarSIHay(color){ if(hayBolitas(color)) { Sacar(color) }} Repeticin condicionalOtra herramienta interesante sera aquella que permita repetir una accin MIENTRAS se cumpla una condicin. Observen que hasta el momento slo podamos repetir un nmero fijo de veces una determinada tarea (o utilizar cada elemento de una lista bien definida, que es similar), pero no podamos resolver problemas en los que no se sabe cunto hay que repetir la tarea.Por ejemplo, deseamos definir un procedimiento que mueve el cabezal hacia el Norte mientras no haya una bolita de color Negro. El cabezal puede encontrarse en cualquier parte del tablero, al igual que las bolitas negras. Queremos detenernos ante la presencia de alguna, pero no sabemos cunta distancia debemos recorrer hasta terminar. No podemos resolver este problema con un repeat, por lo que precisamos una nueva construccin existente en Gobstones:while(not hayBolitas(Negro)){ Mover(Norte)}La construccin while al igual que if, recibe una expresin que puede ser verdadera o falsa (una condicin o pregunta) y un bloque de cdigo que ser la tarea a ejecutar. En este caso, cuando la condicin sea falsa, la tarea se dejar de ejecutar, pero MIENTRAS esa condicin sea verdadera se seguir ejecutando. En otras palabras, mientras NO haya bolitas de color negro, el cabezal se mover al Norte, y cuando exista una celda en la que haya una bolita de color negro, la tarea se dejar de ejecutar.Un problema tpico que es posible resolver con un while, pero no con lo que vimos hasta el momento, consta de ir hacia alguno de los bordes del tablero. Si no sabemos dnde se encuentra el cabezal ni el tamao del tablero en donde ejecutamos nuestro programa, no podemos saber cunto deberamos movernos hasta alcanzar cualquiera de los bordes. Pero utilizando un while, podemos movernos MIENTRAS podamos movernos hacia una determinada direccin. Cuando no podamos movernos ms, significar que alcanzamos un borde del tablero.procedure IrAlBorde(dir){ while(puedeMover(dir)) { Mover(dir) }}Un problema que se introduce con el uso de esta construccin es la posibilidad de que un programa no termine. Cmo es posible esto? Si la condicin del while nunca llega a ser falsa, jams terminar de ejecutar una tarea. El siguiente ejemplo puede no terminar:while(hayBolitas(Negro)){ Poner(Verde) }Si existen bolitas negras en la celda actual, se seguirn poniendo bolitas verdes, y no hay nada que se alcance el caso contrario. El programa efectivamente no terminar nunca.Por esta razn, cuando utilizamos un while, debemos pensar si la tarea que definimos har que la condicin en algn momento pase a ser falsa, dado que si esto no sucede, la tarea, como acabamos de ver, no terminar de ejecutarse jams.

RecorridosLa idea de repetir una tarea a travs de una condicin nos permite pensar en la idea de recorrido. Un recorrido es una tarea que consiste en ir pasando por una serie de elementos, desde el primero hasta el ltimo, sin importar CUANTOS sean. La idea de recorrido la hemos utilizado junto con la repeticin indexada para recorrer valores de una lista, pero esta vez lo que recorreremos sern celdas del tablero.Un ejemplo puede ser el de pintar toda una columna de negro:procedure PintarColumnaDeNegro (){ IrAlBorde(Sur) // Voy al borde sur de la columna Poner(Negro) // Pinto la primera columna de negro while(puedeMover(Norte)) // mientras pueda moverme al norte { Mover(Norte) // paso a la siguiente celda Poner(Negro) // pinto la celda }}

Todo recorrido sobre el tablero sigue el siguiente esquema:procedure UnRecorrido(){ EmpezarRecorrido() PrimerPasoDeLaTarea() while(puedoContinuarRecorrido()) {PasarAlSiguienteElemento()RealizarTarea() }}Este procedimiento no est bien definido porque esas subtareas no existen, pero representa un recorrido tpico en Gobstones. Lo nico que tenemos que hacer para implementar recorridos concretos es pensar cmo cambiar esas subtareas por otras que tengan sentido para el problema que se desea resolver. Para el caso de pintar toda la columna con bolitas negras, el recorrido empieza con IrAlOrigen(), sigue con Poner(Negro) para pintar ya la primer celda, y contina pintando (procesando la celda actual) y movindose (pasando a la siguiente celda) mientras haya celdas al norte (mientras sea posible continuar el recorrido).Como podemos observar, recorrido no es una herramienta del lenguaje Gobstones, como lo son repeat, foreach, while o if, sino que es una construccin mental que permite estructurar un procedimiento o funcin para reflejar el pasaje por distintos elementos en los que se procesa alguna tarea.Recorridos por todo el tableroEn el ejemplo anterior hicimos un recorrido slo por una columna. Pero lo interesante en Gobstones es realizar una tarea para todas las celdas del tablero. Siguiendo el esquema abstracto de recorrido, podemos construir lo siguiente:

function haySiguienteCelda() // no estoy en el borde superior derecho{ return(puedeMover(Norte) || puedeMover(Este))}

procedure PasarASiguienteCelda()// mover hacia el Norte y sino pasar a siguiente columna (Este) desde el Sur{ if(puedeMover(Norte)) { Mover(Norte) } else { Mover(Este); IrAlBorde(Sur) }}

procedure UnRecorridoPorTodoElTablero() // recorrido abstracto por todo el tablero{ IrAlOrigen() // procesar primer celda while(haySiguienteCelda()) {PasarASiguienteCelda()// procesar celda actual }}

En este caso, como sabemos de antemano que lo que vamos a recorrer sern todas las celdas del tablero, podemos fijar cierto comportamiento para gran parte del esquema abstracto de recorrido. En particular, podemos definir cmo va a recorrerse el tablero. En este caso decidimos recorrerlo desde el borde inferior izquierdo hasta el borde superior derecho, procesando las columnas desde su extremo sur hacia su extremo norte, y pasando a la siguiente columna (movindo el cabezal al este) cuando alcanzamos este ltimo extremo. En otras palabras, dejamos de procesar cuando ya no nos podemos mover ni al Norte ni al Este. Lo nico que faltara definir es qu hacemos con cada celda en particular.Si quisiramos poner una bolita roja en cada una, completamos lo siguiente:procedure PonerUnaRojaEnTodoElTablero(){ IrAlOrigen() Poner(Rojo) while(haySiguienteCelda()) {PasarASiguienteCelda()Poner(Rojo) }}Si quisiramos en realidad vaciar todas las celdas del tablero, podemos hacer lo siguiente:procedure VaciarCelda(){ foreach c in [minColor() .. maxColor()] { SacarX(nroBolitas(c), c) }}procedure VaciarElTablero(){ IrAlOrigen() VaciarCelda() while(haySiguienteCelda()) {PasarASiguienteCelda()VaciarCelda() }}Como podemos observar, toda la estructura del recorrido se mantiene intacta, y slo cambia lo que haremos en cada celda.VariablesPor ltimo, existe una herramienta que se utililza en aquellos casos en los que queremos guardar informacin que ser utilizada en un futuro, y que si no guardamos ya no podremos consultar.Imaginen el problema de copiar la cantidad de bolitas verdes de una celda a otra. La forma de saber la cantidad de bolitas de la celda ACTUAL es preguntar con la expresin nroBolitas. Es decir, si escribimos nroBolitas(Verde) esto representar el nmero de bolitas verdes de la celda actual. Pero qu pasa si queremos llevarnos ese dato a la celda al Norte, para colocar esa cantidad de verdes pero de rojas en esa celda al Norte. Al mover el cabezal, ya no podemos consultar la informacin de la celda anterior, dado que slo podemos consultar datos de la celda en donde est posicionado el cabezal. Sin embargo, este problema se resuelve fcilmente haciendo uso de variables:procedure CopiarVerdesHaciaElNorte(){ cantidadVerdes := nroBolitas(Verde) Mover(Norte) PonerX(cantidadVerdes, Rojo)}La lnea resaltada es exactamente la que hace uso de esta nueva herramienta. Del lado izquierdo tenemos un nombre, inventando de la misma manera que pensamos nombres para procedimientos o parmetros, que luego se puede utilizar como cualquier otro valor o expresin dentro del programa. El valor asignado a esta palabra ser el resultado de la expresin que aparezca del lado derecho. A este proceso de relacionar una palabra (una variable) a una expresin se denomina asignacin de la variable. Adems, las variables pueden ser reasignadas las veces que queramos. Por ejemplo:distintasCantidades := nroBolitas(Verde)distintasCantidades := 10La variable distintasCantidades primero vale nroBolitas(Verde), pero despus decidimos asignarle arbitrariamente el nmero 10. Dicha variable es un nombre que podemos asignar a cualquier nmero. En general, si una variable es utilizada para nombrar un tipo de dato, slo es reasignada para seguir representando valores de ese tipo. Por ejemplo, las siguientes lneas no tienen sentido:unaVariable := 15unaVariable := RojoPrimero dijimos que unaVariable describe el valor 15, y a continuacin le decimos que vale Rojo. Debemos intentar evitar este tipo de comportamiento, y pensar qu tipo tiene una variable cuando la asignamos a un dato. En lugar de hacer lo anterior, es posible utilizar distintas variables para distintos tipos de datos:unNumero := 15unColor := RojoOtro uso para las variables es acumular resultados. Dijimos anteriormente que el nombre de la variable luego puede ser utilizado como cualquier valor o expresin dentro del programa, por lo que tambin podemos asignar el valor de una variable a otras variables:unaVariable := 10otraVariable := unaVariableComo es de esperar, si unaVariable representa el valor 10, entonces otraVariable tambin vale 10, porque la primera vale exactamente eso. Y yendo an ms lejos podemos hacer lo siguiente:unaVariable := 10unaVariable := unaVariableEsto es totalmente vlido. Primero decimos que unaVariable vale 10, y luego reasignamos ese nombre al valor que posee ese mismo nombre, que es 10. Al final la variable vuelve a valer 10. Si bien este ejemplo concreto carece de sentido, s tiene sentido algo como lo siguiente:unaVariable := 10unaVariable := unaVariable + 1En este caso, la variable empieza valiendo 10, y luego pasamos a asignarle ese mismo valor que tena pero sumndole 1. La variable ahora pasa a valer 11. Para qu sirve esto? Existen casos en donde queremos acumular resultados bajo un mismo nombre de variable. Por ejemplo, si queremos sumar la cantidad de bolitas de cada celda de una columna podemos realizar un recorrido en donde sumamos al resultado actual de una variable cada cantidad de bolitas que encontramos en las distintas celdas. Supongamos que contamos entonces la cantidad de bolitas negras de toda la columna:function cantidadNegrasDeColumna(){ IrAlBorde(Sur) cantidadTotal := nroBolitas(Negro) while(puedeMover(Norte)) {Mover(Norte)cantidadTotal := cantidadTotal + nroBolitas(Negro) } return(cantidadTotal)}Esta funcin empieza por la primera celda al sur de la columna actual y cuenta la cantidad de bolitas de esa celda (la recuerda). Luego continua su recorrido hacia el norte, y mientras haya celdas al norte se mueve y suma, a la cantidad actual de bolitas, las distintas cantidades de bolitas de cada celda por la que pasa. Estamos acumulando el nmero de bolitas de todas las celdas de la columna en un nico nmero final, que terminamos por devolver al final de este recorrido (cuando no hay ms celdas al norte).