You are on page 1of 36

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 comandos
Procedimientos
Subtareas
Comentarios y precondiciones
Parametrizacin
Otro ejemplo de parametrizacin
Repeticin
Repeticin indexada
Alternativa condicional
Repeticin 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
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)

Procedimientos
En 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:

Subtareas
Esta 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 precondiciones
Adems 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.

Parametrizacin
Una 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 cuadrado
program
{
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 parametrizacin


Definamos 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 como


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

A su vez las distintas subtareas para lineas quedan definidas como


procedure 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)
}

Repeticin
Veamos 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 como
repeat(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 indexada
Existe 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.

Funciones
Hasta 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 <nombre del procedimiento> ahora


escribimos function <nombre de la funcin>.
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 programa

La 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 condicional
En 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 condicional
Otra 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.

Recorridos
La 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 tablero


En 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.

Variables
Por 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 := 10
La 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 := 15
unaVariable := Rojo
Primero 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 := 15
unColor := Rojo
Otro 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 := 10
otraVariable := unaVariable
Como 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 := 10
unaVariable := unaVariable
Esto 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 := 10
unaVariable := unaVariable + 1
En 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).

You might also like