Argentina Programa
Argentina Programa
Fundamentos
2. Programación Imperativa
Primeros Programas
Aunque la programación parece una ciencia exacta, programar es el arte
de hacer que una computadora resuelva nuestros problemas.
Ejercicio 2: El Tablero
Para empezar a programar, el primer elemento que vamos a usar es
un tablero cuadriculado, similar al del Ajedrez, Damas o Go.
4x4 3x2
Para que veas lo que te decimos, presioná el botón Continuar, y vamos a generar tu
primer tablero: un tablero de 3x3.
Ejercicio 3: El Cabezal
El tablero generado en el ejercicio anterior tenía una celda marcada:
0 1 2
2 2
1 1
0 0
0 1 2
¿Y eso por qué? Porque nuestra máquina tiene un cabezal, que en todo
momento está situado sobre una de las celdas del tablero y puede
realizar distintas operaciones sobre ella (paciencia, ya las vamos a
conocer ).
0 1 2 3 4
1 1
0 0
0 1 2 3 4
¡Algo importante! Contamos las filas hacia arriba, y las columnas hacia la
derecha. La primera fila es la de abajo de todo, y la primera columna es
la de la izquierda.
2 2
1 1
0 0
0 1 2
Como podrás ver podemos crear muchísimos tableros distintos, pero ¿el
cabezal se va a quedar siempre en el mismo casillero?
Inicial Final
0 1 2 0 1 2
2 2 2 2
1 1 1 1
0 0 0 0
0 1 2 0 1 2
program {
Mover(Norte)
}
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
0 1 2
Todo programa tiene exactamente un program: una sección del código que
declara los comandos (acciones) que queremos que la máquina realice
sobre el tablero inicial. Al ejecutar un programa obtendremos un
tablero final.
program {
}
program {
Mover(Norte)
}
program {
Mover(Norte)
Mover(Norte)
}
Creá un programa que en un tablero de 2x4 con el cabezal en el origen (la celda de
abajo a la izquierda), mueva el cabezal tres veces hacia el norte:
Inicial
Inicial
0 1
3 3
2 2
1 1
0 0
0 1
1
program {
2
Mover (Norte)
3
Mover (Norte)
4
Mover (Norte)
5
}
Enviar
0 1
3 3
2 2
1 1
0 0
0 1
Tablero final
0 1
3 3
2 2
1 1
0 0
0 1
Pero ojo: la máquina sigue estando ahí y no hay que olvidarla, sólo
hacemos esto para escribir un poco menos.
Creá un programa que mueva el cabezal dos posiciones hacia el Este y una hacia
el Sur, produciendo el siguiente efecto:
Inicial Final
0 1 2 0 1 2
2 2 2 2
1 1 1 1
0 0 0 0
Inicial Final
0 1 2 0 1 2
1
program {
2
Mover (Este)
3
Mover (Este)
4
Mover (Sur)
5
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
0 1 2
program {
Mover(Este)
Mover(Este)
Mover(Sur)
}
program {
Mover(Este)
Mover(Sur)
Mover(Este)
}
program {
Mover(Norte)
Mover(Este)
}
Pero, los humanos, solemos pensar en función del resultado final, es decir,
resaltamos el objetivo del programa. Nos importa más qué hace, y no
cómo. Esta manera denotacional nos llevaría a decir que,
simplemente, mueve el cabezal al noreste.
Por eso hay varias formas de resolver un mismo problema: podemos crear
varios programas que hagan lo mismo (el qué), pero que lo hagan de
forma diferente (el cómo).
Veamos si entendiste esto: creá otro programa que haga lo mismo que el de arriba
(mover hacia el noreste), pero de manera distinta. Ojo: tiene que funcionar en un
tablero de 2x2.
¡Dame una pista!
1
program {
2
Mover (Este)
3
Mover (Norte)
4
}
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
¡Perfecto!
¿Y cómo es esa forma? Descubrilo vos: partiendo del tablero que te mostramos acá
abajo, creá un programa que provoque que el cabezal se salga fuera de los límites.
0 1 2
2 2
1 1
0 0
0 1 2
1
program {
2
Mover (Sur)
3
}
Enviar
¡BOOM!
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
BOOM
[2:3]: No se puede mover hacia la dirección Sur: cae afuera del tablero.
¡BOOOOOOOOOOOOOOOOOM!
Por ejemplo, este es un tablero con una bolita roja y una negra:
0 1
1
1 1
0 0
1
0 1
program {
Poner(Rojo)
}
¡Probá este programa! Escribí el código en el editor, envialo y verás lo que pasa al
ejecutarlo sobre este tablero:
0 1 2
2 2
1 1
0 0
0 1 2
1
program {
2
Poner (Rojo)
3
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
1
0 1 2
0 1 2 3 4
1 1
0 0
0 1 2 3 4
program {
Poner(Rojo)
Poner(Rojo)
Poner(Azul)
Poner(Verde)
Poner(Rojo)
}
el cabezal colocará en la celda actual tres bolitas rojas, una azul y una
verde.
1
program {
2
Poner (Rojo)
3
Poner (Rojo)
4
Poner (Rojo)
5
Poner (Azul)
6
Poner (Verde)
7
}
Enviar
0 1 2 3 4
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1 1
3 1
0 0
0 1 2 3 4
Por ejemplo, los siguientes dos programas también resuelven este mismo
problema:
program {
Poner(Rojo)
Poner(Rojo)
Poner(Rojo)
Poner(Verde)
Poner(Azul)
}
program {
Poner(Rojo)
Poner(Azul)
Poner(Rojo)
Poner(Verde)
Poner(Rojo)
}
Esto es algo muy interesante que ocurre al programar: podemos trabajar con cantidades
tan grandes como queramos.
Ah, y ahora te toca a vos: creá un programa que ponga cuatro bolitas rojas y tres bolitas
negras en la celda actual.
¡Dame una pista!
program {
2
Poner (Rojo)
3
Poner (Negro)
4
Poner (Rojo)
5
Poner (Negro)
6
Poner (Rojo)
7
Poner (Negro)
8
Poner (Rojo)
9
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
4
0 1 2
program {
Sacar(Rojo)
Sacar(Rojo)
}
Sabiendo esto, creá un programa que elimine sólo la bolita roja de este tablero.
¡Tené cuidado! Prestá atención a la posición del cabezal .
0 1
1
1 1
0 0
1
0 1
1
program {
2
Mover (Sur)
3
Sacar (Rojo)
4
}
Enviar
0 1
1
1 1
0 0
1
0 1
Tablero final
0 1
1
1 1
0 0
0 1
¿Querés saber por qué? Intentá sacar una bolita verde o azul de este tablero y
descubrilo.
0 1
1
1 1
0 0
1
0 1
1
program {
2
Sacar (Verde)
3
}
Enviar
¡BOOM!
Tablero inicial
0 1
1
1 1
0 0
1
0 1
Tablero final
BOOM
[2:3]: No se puede sacar una bolita de color Verde: no hay bolitas de ese color.
Esta vez lo que pasó fue que el cabezal intentó sacar una bolita de un
color que no había, y como no sabía qué hacer se autodestruyó. Esto te
va a pasar siempre que intentes sacar una bolita que no exista, así que ¡a
prestar atención!
program {
Poner(Rojo)
Mover(Este)
Poner(Negro)
}
1
program {
2
Poner (Rojo)
3
Mover (Este)
4
Poner (Negro)
5
}
Enviar
Tablero de 2x2
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
1
0 0
1
0 1
Tablero de 3x2
Tablero inicial
0 1 2
1 1
0 0
0 1 2
Tablero final
0 1 2
1 1
1
0 0
1
0 1 2
program {
Poner(Rojo)
Mover(Este)
Poner(Negro)
}
Operacionalmente:
program {
Mover(Este)
Poner(Rojo)
Poner(Negro)
}
Operacionalmente:
1. se mueve al este
2. luego pone una roja
3. luego pone una negra
2 2
1 1
0 0
2 2
0 1 2
program {
2
Poner (Rojo)
3
Poner (Rojo)
4
Mover (Este)
5
Poner (Rojo)
6
Poner (Rojo)
7
}
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
2 2
0 1
0 1 2 3
1 1
0 0
1 1 1 1
0 1 2 3
program {
2
Poner (Rojo)
3
Mover (Este)
4
Poner (Rojo)
5
Mover (Este)
6
Poner (Rojo)
7
Mover (Este)
8
Poner (Rojo)
9
}
Enviar
0 1 2 3
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1 1
0 0
1 1 1 1
0 1 2 3
0 1 2 3
3 3
1
2 2
1 1
1 1
1 1 1
0 0
0 1 2 3
1
program {
2
Poner (Azul)
3
Mover (Norte)
4
Poner (Azul)
5
Mover (Norte)
6
Poner (Azul)
7
Mover (Este)
8
Mover (Sur)
9
Poner (Azul)
10
Mover (Sur)
11
Poner (Azul)
12
Mover (Este)
13
Poner (Azul)
14
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1
2 2
1 1
1 1
1 1 1
0 0
0 1 2 3
Ejercicio 5: Portugal
Creá un programa que dibuje una bandera portuguesa.
La bandera de Portugal se ve así:
Como no nos vamos a poner tan quisquillosos, te vamos a pedir una versión
simplificada, que se tiene que ver así:
0 1 2
1 1
1 1 1
0 0
1 1 1
0 1 2
program {
2
Poner (Verde)
3
Mover (Este)
4
Poner (Rojo)
5
Mover (Este)
6
Poner (Rojo)
7
Mover (Norte)
8
Poner (Rojo)
9
Mover (Oeste)
10
Poner (Rojo)
11
Mover (Oeste)
12
Poner (Verde)
13
Mover (Este)
14
Mover (Este)
15
}
Enviar
1 1
0 0
0 1 2
Tablero final
0 1 2
1 1
1 1 1
0 0
1 1 1
0 1 2
1. Fundamentos
2. Práctica Primeros Programas
6. Y ahora una de más cerquita
1 1 1 1 1
2 2
1 1
1
1 1 1 1 1
0 0
0 1 2 3 4
1
program {
2
Poner (Azul)
3
Mover (Este)
4
Poner (Azul)
5
Mover (Este)
6
Poner (Azul)
7
Mover (Este)
8
Poner (Azul)
9
Mover (Este)
10
Poner (Azul)
11
Mover (Norte)
12
Mover (Oeste)
13
Mover (Oeste)
14
Poner (Rojo)
15
Mover (Oeste)
16
Mover (Oeste)
17
Mover (Norte)
18
Poner (Azul)
19
Mover (Este)
20
Poner (Azul)
21
Mover (Este)
22
Poner (Azul)
23
Mover (Este)
24
Poner (Azul)
25
Mover (Este)
26
Poner (Azul)
27
}
Enviar
0 1 2 3 4
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1 1 1 1 1
2 2
1 1
1
1 1 1 1 1
0 0
0 1 2 3 4
Por ahora no podemos hacer nada mejor, pero para que lo vayas
pensando: una particularidad de nuestra bandera es su simetría, la franja
de arriba es exactamente igual a la de abajo. Si pudieramos crear un
comando que dibuje la franja celeste nuestro programa quedaría mucho
más simple...
0 1 2
2 2
1 1 1
1 1
1 1
0 0
1 1 1
0 1 2
Guille se dedica a la jardinería y, aunque no sabemos bien por qué, piensa que nuestro
tablero es un jardín, mejor hagámosle caso así no se enoja.
program {
2
Sacar (Verde)
3
Mover (Este)
4
Sacar (Verde)
5
Mover (Este)
6
Sacar (Verde)
7
Mover (Norte)
8
Sacar (Verde)
9
Mover (Norte)
10
Sacar (Verde)
11
Mover (Oeste)
12
Sacar (Verde)
13
Mover (Oeste)
14
Sacar (Verde)
15
Mover (Sur)
16
Sacar (Verde)
17
Mover (Sur)
18
}
Enviar
0 1 2
2 2
1 1 1
1 1
1 1
0 0
1 1 1
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
0 1 2
Procedimientos
Si llegaste hasta acá, entonces ya sabés:
cómo escribir un programa (program);
cómo poner y sacar bolitas, usando Poner y Sacar;
cómo desplazar el cabezal por el tablero, usando Mover.
Ejercicios
Procedimientos
Si llegaste hasta acá, entonces ya sabés:
Ejercicios
program {
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Norte)
Poner(Negro)
Mover(Oeste)
Poner(Negro)
Mover(Oeste)
Poner(Negro)
Mover(Norte)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
}
¡Muy bien!
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2 3
1
procedure DibujarCuadradoNegroDeLado3() {
2
Poner(Negro)
3
Mover(Este)
4
Poner(Negro)
5
Mover(Este)
6
Poner(Negro)
7
Mover(Norte)
8
Poner(Negro)
9
Mover(Oeste)
10
Poner(Negro)
11
Mover(Oeste)
12
Poner(Negro)
13
Mover(Norte)
14
Poner(Negro)
15
Mover(Este)
16
Poner(Negro)
17
Mover(Este)
18
Poner(Negro)
19
}
20
21
program {
22
DibujarCuadradoNegroDeLado3()
23
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2 3
¡Vamos a averiguarlo!
Prestale atención a la sintaxis del ejemplo para ver bien cómo definimos
un procedimiento y cómo lo invocamos en un program.
procedure Poner3Rojas() {
Poner(Rojo)
Poner(Rojo)
Poner(Rojo)
}
program {
Poner3Rojas()
}
¿Qué te parece que hace el nuevo procedimiento? Copiá y enviá el código para ver
qué pasa.
1
procedure Poner3Rojas() {
2
Poner(Rojo)
3
Poner(Rojo)
4
Poner(Rojo)
5
}
6
7
program {
8
Poner3Rojas()
9
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
3
0 1 2
Pero si queremos crear una tarea nueva podemos agrupar las acciones
que requiere en un procedimiento. Los procedimientos se definen con
un nombre que describa lo que hace.
procedure PonerVerdeYAzul() {
Poner(Verde)
Poner(Azul)
}
1
procedure PonerNegroYRojo() {
2
Poner(Negro)
3
Poner(Rojo)
4
}
5
program {
6
PonerNegroYRojo()
7
}
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
1
0 0
1
0 1
A esta altura ya sabemos que para programar siempre tenemos que tener
en cuenta la sintaxis y que para definir nuevos procedimientos también
tenemos reglas:
procedure Mover4AlNorte() {
Mover(Norte)
Mover(Norte)
Mover(Norte)
Mover(Norte)
}
program {
Mover4AlNorte()
}
1
procedure Poner3Verdes(){
2
Poner (Verde)
3
Poner (Verde)
4
Poner (Verde)
5
}
6
program {
7
Poner3Verdes ()
8
}
9
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
3
0 1
Por eso, su nombre debe ser único dentro de todo el programa. Recordá
que la computadora no hace más que seguir órdenes y si existiera más de
un procedimiento con el mismo nombre, no sabría cuál elegir.
1 1
0 0
3 3
0 1 2
Solución
Biblioteca
1
program {
2
Poner3Verdes ()
3
Mover (Este)
4
Poner3Verdes ()
5
}
Enviar
0 1 2
1 1
0 0
0 1 2
Tablero final
0 1 2
1 1
0 0
3 3
0 1 2
Repasemos:
Para definir un procedimiento nuevo usamos procedure y le ponemos
un nombre que describa lo que hace seguido por paréntesis (). A
continuación y entre llaves {} lo que querramos que haga.
Los procedimientos se definen una sola vez. Si ya están definidos
en la Biblioteca o en alguna parte del código no hay que volver a
hacerlo (no se pueden repetir los nombres, si se define un
procedimiento más de una vez nuestro programa va a fallar).
Para invocar un procedimiento escribimos su nombre (sin olvidar
los paréntesis() al final). ¡Y podemos hacerlo todas las veces que
sean necesarias!
Aunque también se escribe entre llaves {}, el program nunca lleva
nombre ni paréntesis.
Solución
Biblioteca
1
program {
2
Poner3Rojas ()
3
Poner3Rojas ()
4
Poner3Rojas()
5
}
6
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
9
0 1
Solución
Biblioteca
1
procedure Poner9Rojas () {
2
Poner3Rojas ()
3
Poner (Rojo)
4
Poner (Rojo)
5
Poner (Rojo)
6
Poner (Rojo)
7
Poner (Rojo)
8
Poner (Rojo)
9
}
10
11
program {
12
Poner9Rojas ()
13
}
14
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
9
0 1
Tablero inicial
0 1 2
1 1
0 0
0 1 2
Tablero final
0 1 2
1 1
0 0
9
0 1 2
0 1 2
2 2
1
1 1
1 1
0 0
0 1 2
1
3 3
1 1
2 2
1
1 1
1 1
0 0
0 1 2 3
Solución
Biblioteca
1
procedure DibujarDosPuntas () {
2
DibujarPuntaNegra ()
3
Mover (Norte)
4
Mover (Norte)
5
Mover (Este)
6
Poner (Negro)
7
Mover (Norte)
8
Poner (Negro)
9
Mover (Este)
10
Mover (Sur)
11
Poner (Negro)
12
}
13
14
program {
15
DibujarDosPuntas ()
16
}
17
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1
3 3
1 1
2 2
1
1 1
1 1
0 0
0 1 2 3
Por suerte existe una primitiva llamada IrAlBorde, que toma una dirección,
y se mueve todo lo que pueda en esa dirección, hasta llegar al borde.
program {
IrAlBorde(Este)
}
Inicial
Inicial
0 1 2 3
1 1
0 0
0 1 2 3
¡Vamos a aprovecharlo!
1
procedure RojoAlBorde () {
2
IrAlBorde (Norte)
3
IrAlBorde (Oeste)
4
Poner (Rojo)
5
}
6
7
program {
8
RojoAlBorde ()
9
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
0 1
2 2
1 1
0 0
0 1
Tablero final
0 1
2 2
1
1 1
0 0
0 1
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1
1 1
0 0
0 1 2
¡Excelente!
0 1 2 3
2 2
3 3 3 3
1 1
0 0
0 1 2 3
¡Manos a la obra!
Solución
Biblioteca
1
procedure PonerGuirnalda() {
2
Poner3Verdes()
3
Poner3Rojas()
4
}
5
6
procedure DecorarTablero() {
7
IrAlBorde (Norte)
8
IrAlBorde (Oeste)
9
PonerGuirnalda()
10
IrAlBorde (Este)
11
PonerGuirnalda()
12
}
13
program {
14
DecorarTablero()
15
}
Enviar
Tablero inicial
0 1 2 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
2 2
3 3 3 3
1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3 4
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
4 4
3 3 3 3
3 3
2 2
1 1
0 0
0 1 2 3 4
Cuanto más complejo sea el problema, más útil nos va a ser pensar una
estrategia y organizar la solución en subtareas ¡y los procedimientos
están para ayudarnos!
0 1 2 3 4
1 1 1 1 1 1 1 1
1 1
1 1 1 1 1 1 1 1
0 0
0 1 2 3 4
Como se ve en la imagen, cada celda de la línea debe tener una bolita de cada color (una
roja, una negra, una verde y una azul).
¿Cómo podemos dibujarla? ¿Cuál es la tarea que se repite? ¿Se puede definir un nuevo
procedimiento para resolverla y aprovecharlo para construir nuestra solución?
Definí un procedimiento DibujarLineaColorida que dibuje una línea multicolor de cuatro
celdas hacia el Este y al finalizarla ubique el cabezal en la celda inicial. Tené en cuenta que
siempre partimos del extremo Oeste. Invocá el nuevo procedimiento en un program.
¡Dame una pista!
procedure Colores() {
2
Poner (Azul)
3
Poner (Negro)
4
Poner (Rojo)
5
Poner (Verde)
6
}
7
procedure DibujarLineaColorida() {
8
Colores()
9
Mover (Este)
10
Colores()
11
Mover (Este)
12
Colores()
13
Mover (Este)
14
Colores()
15
IrAlBorde (Oeste)
16
}
17
program {
18
DibujarLineaColorida()
19
}
20
Enviar
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1 1 1 1 1 1 1
1 1
1 1 1 1 1 1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3 4
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1 1 1 1 1 1 1 1
1 1
1 1 1 1 1 1 1 1
0 0
0 1 2 3 4
0 1 2 3 4
4 4
1 1 1 1 1 1 1 1
3 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
2 2
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 0
1 1 1 1 1 1 1 1
0 1 2 3 4
procedure DibujarCuadradoColorido() {
2
DibujarLineaColorida()
3
Mover (Norte)
4
DibujarLineaColorida()
5
Mover (Norte)
6
DibujarLineaColorida()
7
Mover (Norte)
8
DibujarLineaColorida()
9
IrAlBorde (Sur)
10
IrAlBorde (Oeste)
11
}
12
program {
13
DibujarCuadradoColorido()
14
}
Enviar
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1 1 1 1 1 1 1 1
3 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
2 2
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 0
1 1 1 1 1 1 1 1
0 1 2 3
¡Terminaste Procedimientos!
A diferencia de la guía anterior, donde sólo usamos comandos que venían
con Gobstones, en esta lección aprendiste a crear tus propios
comandos . Y eso es lo más lindo de programar, poder inventar tus
propias tareas para resolver los problemas.
Repetición Simple
Como te contábamos cuando empezaste, programar nos da un gran
poder: nos permite automatizar tareas repetitivas y tediosas.
¿Y qué quiere decir eso de "repetitivas"? Pensemos, por ejemplo, cómo
haríamos un programa que ponga 5 bolitas azules:
program {
Poner(Azul)
Poner(Azul)
Poner(Azul)
Poner(Azul)
Poner(Azul)
}
Ejercicios
1. MoverOeste10
2. La computadora repite por nosotros
3. MoverOeste5 usando repeat
4. No todo es repetir
5. También vale después
6. Repitiendo varios comandos
7. ¿Dónde está el error?
8. Diagonal con una bolita
9. Diagonal "pesada"
10. El caso borde
11. De lado a lado, dibujamos un cuadrado
Ejercicio 1: MoverOeste10
Entremos en calor: definí un procedimiento MoverOeste10 que mueva el cabezal 10
veces hacia el Oeste.
¡Dame una pista!
1
procedure MoverOeste10() {
2
Mover (Oeste)
3
Mover (Oeste)
4
Mover (Oeste)
5
Mover (Oeste)
6
Mover (Oeste)
7
Mover (Oeste)
8
Mover (Oeste)
9
Mover (Oeste)
10
Mover (Oeste)
11
Mover (Oeste)
12
}
Enviar
0 1 2 3 4 5 6 7 8 9 10
1 1
0 0
0 1 2 3 4 5 6 7 8 9 10
Tablero final
0 1 2 3 4 5 6 7 8 9 10
1 1
0 0
0 1 2 3 4 5 6 7 8 9 10
¿Te imaginás cómo hacer lo mismo pero 20, 100 o 5000 veces? Sería
bastante molesto, ¿no?
procedure MoverOeste10() {
repeat(10) {
Mover(Oeste)
}
}
Pero no tenés por qué creernos: ¡escribí este código en el editor y fijate si funciona!
1
procedure MoverOeste10() {
2
repeat(10) {
3
Mover (Oeste)
4
}
5
}
Enviar
0 1 2 3 4 5 6 7 8 9 10
1 1
0 0
0 1 2 3 4 5 6 7 8 9 10
Tablero final
0 1 2 3 4 5 6 7 8 9 10
1 1
0 0
0 1 2 3 4 5 6 7 8 9 10
1
procedure MoverOeste5() {
2
repeat(5) {
3
Mover (Oeste)
4
}
5
}
Enviar
0 1 2 3 4 5
1 1
0 0
0 1 2 3 4 5
Tablero final
0 1 2 3 4 5
1 1
0 0
0 1 2 3 4 5
Un número entero (o sea, sin decimales), que indica cuántas veces hay
que repetir. Este número va entre paréntesis (()) luego de la palabra repeat.
program {
Mover(Sur)
repeat(4) {
Poner(Rojo)
}
Mover(Norte)
}
Fijate que Mover(Sur) lo pusimos antes del repeat y Mover(Norte) lo pusimos después. Por
lo tanto cada movimiento se ejecuta solo una vez. Teniendo en cuenta esto:
0 1 2
0 1 2
3
2 2 2 2
1 1
1 1
0 0
0 0
0 1 2
0 1 2
Recordá que no existe la dirección Noreste en Gobstones, pero si tenemos Norte y Este.
procedure Poner3AlNoreste() {
2
Mover(Norte)
3
Mover(Este)
4
repeat(3){
5
Poner(Negro)
6
}
7
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
3
1 1
0 0
0 1 2 3
¿Viste qué importante es definir bien qué comandos hay que repetir y cuáles no?
Es muy común, al principio, olvidarse de colocar las llaves o incluso pensar que no son
importantes. Pero tené mucho cuidado: poner las llaves en el lugar erróneo puede
cambiar por completo lo que hace tu programa. Mirá qué distinto sería el resultado si
hubieras puesto el Mover(Este) adentro del repeat:
procedure Poner3AlNoreste() {
Mover(Norte)
repeat(3) {
Mover(Este)
Poner(Negro)
}
}
0 1 2 3
3 3
2 2
1 1 1
1 1
0 0
0 1 2 3
1 1
0 0
0 1 2 3 4
0 1 2 3 4
1
1 1
0 0
0 1 2 3 4
1
procedure PonerAzulLejos(){
2
repeat(4){
3
Mover(Este)
4
}
5
Poner(Azul)
6
}
Enviar
0 1 2 3 4
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1
1 1
0 0
0 1 2 3 4
Miremos el código de DibujarLineaNegra6 que podríamos haber hecho sin usar repeat, con
algunos espacios en blanco para ayudarnos a reconocer la secuencia que se repite:
procedure DibujarLineaNegra6() {
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
Poner(Negro)
Mover(Este)
}
¿Notás qué es lo que se repite y cuántas veces? Bueno, eso es lo que tenés que poner en
el repeat.
procedure DibujarLineaNegra6() {
2
repeat(6) {
3
Poner(Negro)
4
Mover(Este)
5
}
6
}
Enviar
1 1
0 0
0 1 2 3 4 5 6
Tablero final
0 1 2 3 4 5 6
1 1
1 1 1 1 1 1
0 0
0 1 2 3 4 5 6
0 1 0 1
0 1
4 4
4 4
1
4 4
3 3
1
3 3
3 3 1
2 2
2 2 1
2 2
1
1 1
1 1
1
1 1
1
0 0
0 0
0 0 1
0 1
0 1 0 1
0 1
4 4
3 3
2 2
1 1
0 0
0 1
Tablero final
0 1
4 4
3 3
1
2 2
1
1 1
1
0 0
1
0 1
4 4
1
3 3
1
2 2
1
1 1
1
0 0
0 1 2 3 4
procedure Diagonal4Azul() {
2
Poner(Azul)
3
repeat(3){
4
Mover(Norte)
5
Mover(Este)
6
Poner(Azul)
7
}
8
Mover(Norte)
9
Mover(Este)
10
}
Enviar
0 1 2 3 4
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
4 4
1
3 3
1
2 2
1
1 1
1
0 0
0 1 2 3 4
¿Qué quiere decir esto? Que en vez de poner 1 bolita en cada celda,
ahora hay que poner 21. Mirá la imagen:
0 1 2 3 4
4 4
21
3 3
21
2 2
21
1 1
21
0 0
0 1 2 3 4
A diferencia del anterior, ahora lo que tenés que hacer en cada celda es
más complejo (tenés que hacer más que un simple Poner(Azul)).
0 1 2 3 4
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
4 4
21
3 3
21
2 2
21
1 1
21
0 0
0 1 2 3 4
0 1 2 3 4 5
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4 5
Tablero final
0 1 2 3 4 5
4 4
21
3 3
21
2 2
21
1 1
21
0 0
0 1 2 3 4 5
procedure LineaNegra4Este() {
repeat(4) {
Poner(Negro)
Mover(Este)
}
}
0 1 2 3
1 1
1 1 1 1
0 0
0 1 2 3
Teniendo en cuenta esto último, definí una nueva versión de LineaNegra4Este que
deje el cabezal en la última celda de la línea.
¡Dame una pista!
Ojo: al "sacar un caso para afuera" también vas a tener que reducir el
número de veces que repetís los otros casos.
1
procedure LineaNegra4Este() {
2
repeat(3){
3
Poner(Negro)
4
Mover(Este)
5
}
6
Poner(Negro)
7
}
Enviar
0 1 2 3 4
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1 1
1 1 1 1
0 0
0 1 2 3 4
0 1 2 3
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1 1
1 1 1 1
0 0
0 1 2 3
Otra variante menos común, y tal vez más difícil de construir también, es
la de procesar el primer caso aparte:
procedure LineaNegra4Este() {
Poner(Negro)
repeat(3) {
Mover(Este)
Poner(Negro)
}
}
0 1 2 3 4
0 1 2 3 5
1 1 1 1 1 1 1 1
3 3 4
1 1 1 1 1 1 1 1
2 2 3
1 1 1 1 1 1 1 1
1 1 2
1 1 1 1 1 1 1 1
0 0 1
0 1 2 3 0
0 1 2 3 4
Definí el procedimiento CuadradoNegro4 para dibujar un cuadrado de 4x4 con bolitas negras.
Al empezar, el cabezal se encuentra en la esquina inferior izquierda del cuadrado (no
necesariamente del tablero ) y cuando termine el programa el cabezal deberá quedar en el
extremo superior derecho del cuadrado. No te olvides de invocar LineaNegra4Este.
Tené en cuenta lo que hablamos en el ejercicio anterior sobre el caso borde.
¡Dame una pista!
Solución
Biblioteca
procedure CuadradoNegro4 () {
2
repeat (3) {
3
LineaNegra4Este ()
4
Mover (Norte)
5
repeat(3) {
6
Mover(Oeste)
7
}
8
}
9
LineaNegra4Este ()
10
}
Enviar
Tablero inicial
0 1 2 3
4 4
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
4 4
1 1 1 1
3 3
1 1 1 1
2 2
1 1 1 1
1 1
1 1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
1 1 1 1
3 3
1 1 1 1
2 2
1 1 1 1
1 1
1 1 1 1
0 0
0 1 2 3 4
Parámetros
Gracias a los procedimientos empezamos a dividir en subproblemas,
logrando hacer programas más complejos de una manera más fácil y
evitando repetir código.
Ejercicios
1. Pensando en subtareas
2. Dibujando un cuadrado con subtareas
3. Color esperanza
4. Los que faltan
5. Procedimientos con agujeritos
6. Llenando los espacios vacíos
7. DibujarLinea3
8. DibujarCuadradoDeLado3
9. Pasando varios parámetros
10. La ley, el orden y el BOOM
11. Un argumento para dos parámetros
12. La tercera es la vencida
0 1 2
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2
0 1 2
2 2
1 1
1 1 1
0 0
0 1 2
Solución
Biblioteca
1
procedure DibujarLineaNegra3(){
2
repeat(2){
3
Poner(Negro)
4
Mover(Este)
5
}
6
Poner(Negro)
7
VolverAtras()
8
}
9
program{
10
DibujarLineaNegra3()
11
}
Enviar
Tablero de 3 por 3
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
1 1 1
0 0
0 1 2
Tablero de 4 por 4
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
1 1 1
0 0
0 1 2 3
0 1 2
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2
0 1 2
2 2
1 1
0 0
0 1 2
Solución
Biblioteca
1
procedure DibujarCuadradoNegroDeLado3(){
2
repeat(2){
3
DibujarLineaNegra3()
4
Mover(Norte)
5
6
}
7
DibujarLineaNegra3()
8
}
9
program {
10
DibujarCuadradoNegroDeLado3()
11
}
Enviar
Tablero de 3 por 3
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2
Tablero de 4 por 4
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2 3
Solución
Biblioteca
1
procedure DibujarLineaVerde3(){
2
repeat(2){
3
Poner(Verde)
4
Mover(Este)
5
}
6
Poner(Verde)
7
VolverAtras()
8
}
9
program{
10
DibujarLineaVerde3()
11
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Tablero de 3 por 3
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1 1
0 0
1 1 1
0 1 2
Tablero de 4 por 4
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
0 0
1 1 1
0 1 2 3
Solución
Biblioteca
1
procedure DibujarLineaRoja3(){
2
repeat(2){
3
Poner(Rojo)
4
Mover(Este)
5
}
6
Poner(Rojo)
7
VolverAtras()
8
}
9
procedure DibujarLineaAzul3(){
10
repeat(2){
11
Poner(Azul)
12
Mover(Este)
13
}
14
Poner(Azul)
15
VolverAtras()
16
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
0 0
1 1 1
0 1 2 3
procedure Poner3(color) {
repeat(3) {
Poner(color)
}
}
program {
Poner3(Negro)
Poner3(Rojo)
}
1
procedure Poner3(color){
2
repeat(3){
3
Poner(color)
4
}
5
}
6
program {
7
Poner3(Negro)
8
Poner3(Rojo)
9
}
Enviar
0 1
2 2
1 1
0 0
0 1
Tablero final
0 1
2 2
3
1 1
0 0
0 1
¿Viste qué interesante lo que hicimos?
Lo primero que hicimos fue definir un procedimiento, pero con una pequeña diferencia:
toma un parámetro, llamado color.
procedure Poner3(color) {
Poner(color)
Poner(color)
Poner(color)
}
¿Y qué es un parámetro? Son esos nombres que van entre paréntesis para ser
reemplazados por valores concretos cuando invocamos al procedimiento. Por ejemplo,
si lo invocamos así..
program {
Poner3(Negro)
}
Poner(Negro)
Poner(Negro)
Poner(Negro)
Y si lo invocamos así...
program {
Poner3(Rojo)
}
Poner(Rojo)
Poner(Rojo)
Poner(Rojo)
Fijate como cada vez que aparece color se reemplaza por el valor que
le pasamos a Poner . Veamos si se entiende:
Creá un programa que ponga tres bolitas verdes. No te olvides de invocar el
procedimiento Poner3.
Solución
Biblioteca
program{
3
Poner3(Verde)
4
}
Enviar
0 1
2 2
1 1
0 0
0 1
Tablero final
0 1
2 2
3
1 1
0 0
0 1
Ejercicio 7: DibujarLinea3
¡Ahora te toca a vos!
Definí el procedimiento DibujarLinea3 que reciba un color y dibuje una línea de ese
color. Despreocupate por los programs para invocarlo con cada uno de los colores,
van por nuestra parte.
¡Dame una pista!
Solución
Biblioteca
1
procedure DibujarLinea3(color){
2
repeat(2) {
3
Poner(color)
4
Mover(Este)
5
}
6
Poner(color)
7
VolverAtras()
8
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
0 0
1 1 1
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1
0 0
1 1 1
0 1 2 3
Ejercicio 8: DibujarCuadradoDeLado3
¡Hora del último pasito! Ya definimos un procedimiento para poder
dibujar cuadrados negros (DibujarCuadradoNegroDeLado3), pero todo este
asunto de los parámetros surgió cuando quisimos hacer cuadrados de
distintos colores.
1
procedure DibujarCuadradoDeLado3(color) {
2
repeat(2){
3
DibujarLinea3(color)
4
Mover(Norte)
5
}
6
DibujarLinea3(color)
7
}
Enviar
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1 1
1 1
1 1 1
0 0
1 1 1
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1 1 1
1 1
1 1 1
0 0
1 1 1
0 1 2 3
¿Y cómo se hace esto? Muy fácil, al igual que como hacemos al escribir,
vamos a separar cada parámetro usando comas de esta manera:
Creá un program que invoque la nueva versión de DibujarLinea3 (no tenés que definirla,
sólo invocarla) y dibuje un cuadrado multicolor como este:
0 1 2 3
1 1 1 1
3 3
1
2 2
1
1 1 1
1
0 0
1 1 1 1
0 1 2 3
Solución
Biblioteca
1
program {
2
DibujarLinea3(Verde, Este)
3
Mover(Este)
4
DibujarLinea3(Rojo, Norte)
5
Mover(Norte)
6
DibujarLinea3(Negro, Oeste)
7
Mover(Oeste)
8
DibujarLinea3(Azul, Sur)
9
}
Enviar
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1 1 1 1
3 3
1
2 2
1
1
1 1
1
0 0
1 1 1 1
0 1 2 3
Creá un programa cualquiera que invoque DibujarLinea3, pero esta vez intentá
invocarlo con los argumentos invertidos.
¡Dame una pista!
1
program {
2
DibujarLinea3(Este, Verde)
3
Mover(Este)
4
DibujarLinea3(Norte, Rojo)
5
Mover(Norte)
6
DibujarLinea3(Oeste, Negro)
7
Mover(Oeste)
8
DibujarLinea3 (Sur, Azul)
9
}
Enviar
¡BOOM!
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
BOOM
Ok, hizo BOOM , pero ¿qué quiere decir eso de El parámetro de Poner debería
ser un color?
Solución
Biblioteca
1
program {
2
DibujarLinea3(Verde)
3
Mover(Este)
4
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
¡BOOM!
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
BOOM
Triada recibe tres colores por parámetro y pone tres bolitas, una al lado de la otra hacia
el Este, en el mismo orden en que se reciben. El cabezal empieza en el origen y debe
terminar sobre la última bolita de la tríada.
0 1 2
1
0 0
1 1
0 1 2
1
0 0
1 1
0 1 2
Los nombres de los parámetros elegilos vos, pero mucho cuidado: no pueden repetirse,
tenés que pensar tres nombres diferentes.
Poner(colora)
3
Mover(Este)
4
Poner(colore)
5
Mover(Este)
6
Poner(colorete)
7
}
8
Enviar
Tablero inicial
0 1 2
0 0
0 1 2
Tablero final
0 1 2
1
0 0
1 1
0 1 2
Tablero inicial
0 1 2
0 0
0 1 2
Tablero final
0 1 2
1
0 0
1 1
0 1 2
¡Terminaste Parámetros!
¡Felicitaciones!
Ejercicios
procedure Diagonal4Azul(){
repeat(4){
Poner(Azul)
Mover(Este)
Mover(Norte)
}
}
¿Te animás a definir el procedimiento Diagonal4AzulVolviendo? Este procedimiento
debería hacer lo mismo que Diagonal4Azul, pero tiene que dejar el cabezal en la
posición inicial. Recordá que podés invocar todo lo que está en la Biblioteca sin
necesidad de volver a definirlo.
0 1 2 3 4
4 4
1
3 3
1
2 2
1
1 1
1
0 0
0 1 2 3 4
Solución
Biblioteca
1
procedure Diagonal4AzulVolviendo(){
2
Diagonal4Azul()
3
repeat(4){
4
Mover(Sur)
5
Mover(Oeste)
6
}
7
}
8
Enviar
0 1 2 3 4
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
4 4
1
3 3
1
2 2
1
1 1
1
0 0
0 1 2 3 4
¡Bien!
0 1 2 3 4
6 6
1
5 5
1 1
4 4
1 1 1
3 3
1 1 1
2 2
1 1
1 1
1
0 0
0 1 2 3 4
El procedimiento debe llamarse BandaDiagonal4. ¡Ojo! prestá atención a la posición final del
cabezal.
¡Dame una pista!
Solución
Biblioteca
procedure BandaDiagonal4() {
2
repeat(3) {
3
Diagonal4AzulVolviendo()
4
Mover(Norte)
5
}
6
repeat(3) {
7
Mover(Sur)
8
}
9
}
Enviar
0 1 2 3 4
6 6
5 5
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
6 6
1
5 5
1 1
4 4
1 1 1
3 3
1 1 1
2 2
1 1
1 1
1
0 0
0 1 2 3 4
0 1
1 1
3
0 0
0 1
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
2
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
4
0 1
¿Qué podríamos representar con bolitas? Por ejemplo una fecha. Una
fecha que debemos recordar es el 24 de marzo de 1976, hoy
constituido Día de la Memoria por la Verdad y la Justicia en Argentina.
0 1 2
24 *
0 0
3
0 1 2
Solución
Biblioteca
1
procedure DiaDeLaMemoria(){
2
PonerN(24, Azul)
3
Mover(Este)
4
PonerN(3, Verde)
5
Mover(Este)
6
PonerN(1976, Negro)
7
}
Enviar
0 1 2
0 0
0 1 2
Tablero final
0 1 2
24 *
0 0
3
0 1 2
0 1 2
12 *
0 0
8
0 1 2
Solución
Biblioteca
1
procedure Fecha(dia, mes, anio) {
2
3
PonerN(dia, Azul)
4
Mover(Este)
5
PonerN(mes, Verde)
6
Mover(Este)
7
PonerN(anio, Negro)
8
}
Enviar
0 1 2
0 0
0 1 2
Tablero final
0 1 2
24 *
0 0
3
0 1 2
Tablero inicial
0 1 2
0 0
0 1 2
Tablero final
0 1 2
4 *
0 0
6
0 1 2
Inicial Final
0 1 2 3 0 1 2 3
2 2 2 2
1 1 1 1
0 0 0 0
0 1 2 3 0 1 2 3
¡Dame una pista!
procedure PonerN(cantidad,color){
repeat(cantidad){
Poner(color)
}
}
1
procedure MoverN(cantidad, direccion) {
2
repeat(cantidad){
3
Mover(direccion)
4
}
5
}
Enviar
0 1 2
0 0
0 1 2
Tablero final
0 1 2
0 0
0 1 2
Tablero inicial
1 1
0 0
Tablero final
1 1
0 0
¡Perfecto!
Recordamos entonces que entre los paréntesis del repeat no sólo pueden ir
números (como 7 o 42), sino también otros tipos de expresiones que
denoten valores numéricos (como cantidad en este caso)
Ahora, tenés que mostrarnos que podés dibujar un reloj. Lo que haremos
por ahora es solamente poner los números que aparecen en un típico
reloj de agujas:
El 12 arriba,
El 3 a la derecha,
El 9 a la izquierda, y
el 6 abajo.
Definí un procedimiento DibujarReloj(radio) que ponga los números del reloj como se
indica arriba: alrededor del casillero actual. El tamaño del reloj se indica con
el radio que recibís como parámetro: mientras más grande es el radio, más alejados
están los números del centro.
Dado el siguiente program:
program {
DibujarReloj(2)
}
0 1 2 3 4
4 4
12
3 3
2 2
9 3
1 1
0 0
6
0 1 2 3 4
¡Dividí en subtareas!
Solución
Biblioteca
1
procedure DibujarReloj(radio) {
2
MoverN(radio,Este)
3
PonerN(3, Rojo)
4
repeat(2){
5
MoverN(radio,Oeste)
6
}
7
PonerN(9, Rojo)
8
MoverN(radio,Este)
9
MoverN(radio,Sur)
10
PonerN(6, Rojo)
11
repeat(2){
12
MoverN(radio,Norte)
13
}
14
PonerN(12, Rojo)
15
MoverN(radio,Sur)
16
}
Enviar
0 1 2 3 4
4 4
3 3
2 2
1 1
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
4 4
12
3 3
2 2
9 3
1 1
0 0
6
0 1 2 3 4
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
12
1 1
9 3
0 0
6
0 1 2
0 1 2 3 4 5
1 1
0 0
3 3 3 3 3
0 1 2 3 4 5
Solución
Biblioteca
1
procedure LineaEstePesada(peso, color, longitud) {
2
repeat(longitud) {
3
PonerN(peso, color)
4
Mover(Este)
5
}
6
MoverN(longitud, Oeste)
7
}
Enviar
Tablero inicial
0 1 2 3 4
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
24 24 24 24
0 0
0 1 2 3 4
Tablero inicial
0 1 2 3 4 5 6 7
0 0
0 1 2 3 4 5 6 7
Tablero final
0 1 2 3 4 5 6 7
0 0
6 6 6 6 6 6 6
0 1 2 3 4 5 6 7
Definí un procedimiento GuardaDe5(), que haga una "guarda" de 5 azulejos (como las
que decoran las paredes). Cada azulejo está conformado por 1 bolita verde, 5
negras y 9 rojas.
0 1 2 3 4 5
1 1
5 5 5 5 5
0 0
9 1 9 1 9 1 9 1 9 1
0 1 2 3 4 5
Solución
Biblioteca
1
procedure DentroDeGuardaDe5(){
2
repeat(4){
3
PonerN(1,Verde)
4
PonerN(5,Negro)
5
PonerN(9,Rojo)
6
Mover(Este)
7
}
8
}
9
procedure GuardaDe5(){
10
DentroDeGuardaDe5()
11
PonerN(1,Verde)
12
PonerN(5,Negro)
13
PonerN(9,Rojo)
14
}
Enviar
0 1 2 3 4
0 0
0 1 2 3 4
Tablero final
0 1 2 3 4
0 5 5 5 5 5 0
9 1 9 1 9 1 9 1 9 1
0 1 2 3 4
2 2
9 1
1 1
9 1
5 5 5
0 0
9 1 9 1 9 1
0 1 2
Solución
Biblioteca
procedure Poner2Azulejos(direccion) {
2
repeat(2) {
3
Mover(direccion)
4
PonerAzulejo()
5
}
6
}
7
procedure GuardaEnL() {
8
PonerAzulejo()
9
Poner2Azulejos(Este)
10
MoverN(2,Oeste)
11
Poner2Azulejos(Norte)
12
MoverN(2,Sur)
13
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
9 1
1 5 1
9 1
5 5 5
0 0
9 1 9 1 9 1
0 1 2
En esta guía:
Expresiones
¿Se pueden hacer programas que sumen cosas?
¿Y dibujar figuras en distintas direcciones sin tener que especificar cada
una de ellas?
¿Y mirar lo que hay en el tablero?
Ejercicios
el número 5;
la cantidad de dedos de una mano;
la suma entre 3 y 2;
el número de continentes que existen en el planeta, según la ONU.
Todas las frases anteriores hablan del valor cinco, aunque no lo digan de
forma explícita.
Con esta idea e invocando PonerN, creá un programa que ponga cinco bolitas
negras, PERO sin escribir el número 5.
¡Dame una pista!
Solución
Biblioteca
1
program {
2
PonerN(4+1,Negro)
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
5
0 0
0 1
program {
PonerN(4 + 1, Negro)
}
program {
PonerN(12 - 7, Negro)
}
Y así se nos pueden ocurrir infinitas formas de "decir 5" y sólo una de ellas
lo hace de manera literal (o sea, escribiendo 5).
0 1
1 1
0 0
6
0 1
Solución
Biblioteca
1
procedure PonerSuma(x, y) {
2
PonerN(x+y,Rojo)
3
}
Enviar
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
5
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
11
0 1
0 1
1 1
0 0
45
0 1
0 1
1 1
0 0
51
0 1
Solución
Biblioteca
1
procedure ContarGente(micros, autos, bicicletas) {
2
PonerN (micros*40+autos*4+bicicletas*1, Verde)
3
}
Enviar
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
*
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
*
0 1
procedure MoverComoSalmon(direccion) {
Mover(opuesto(direccion))
}
Escribí la solución en el editor y dale Enviar. Vas a ver cómo se mueve el cabezal...
1
procedure MoverComoSalmon(direccion) {
2
Mover(opuesto(direccion))
3
}
Enviar
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
Solución
Biblioteca
1
procedure CaminarDesconfiado(pasos) {
2
MoverN(pasos div 2, Este)
3
}
Enviar
Tablero inicial
0 1 2 3 4 5
0 0
0 1 2 3 4 5
Tablero final
0 1 2 3 4 5
0 0
0 1 2 3 4 5
Tablero inicial
0 1 2 3 4 5
0 0
0 1 2 3 4 5
Tablero final
0 1 2 3 4 5
0 0
0 1 2 3 4 5
Inicial Final
0 1
0 1
1 1 1 1
1
0 0
0 0
0 1
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
1
0 0
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
1
0 1
O sea, donde hasta ahora podrías usar dir ahora también podrías
poner opuesto(dir), ya que ambas expresiones denotan direcciones.
Obviamente te queda a vos decidir en cada caso si tiene sentido
usar opuesto o no.
Solución
Biblioteca
1
repeat(longitud) {
3
Poner(color)
4
Mover(direccion)
5
}
6
MoverN(longitud, opuesto(direccion))
7
}
Enviar
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
2 2
1
1 1
1
0 0
1
0 1 2 3
Tablero inicial
0 1 2 3
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
1 1
1 1
0 0
0 1 2 3
Ele(Norte)
0 1 2 3
3 3
1
2 2
1
1 1
Ele(Norte)
2 1 1
0 0
0 1 2 3
Indudablemente, una L consta de dos líneas y dibujar una línea es la tarea que ya
resolviste en el ejercicio anterior. Así que por ese lado, tenemos la mitad del problema
resuelto.
La primera línea es fácil, porque coincide con la dirección que recibimos como
argumento... ¿pero la segunda? Bueno, ahí viene lo interesante: además de opuesto,
Gobstones nos provee dos funciones más para operar sobre las
direcciones, siguiente y previo. siguiente(direccion) retorna la dirección siguiente a la
especificada, mientras que previo(direccion) retorna la anterior, siempre pensándolo en el
sentido de las agujas del reloj:
Solución
Biblioteca
1
procedure Ele(direccion) {
2
Linea(direccion, Azul, 3)
3
Linea(siguiente(direccion),Azul,3)
4
}
Enviar
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
3 3
1
2 2
1
1 1
2 1 1
0 0
0 1 2 3
Tablero inicial
0 1 2 3
3 3
2 2
1 1
0 0
0 1 2 3
Tablero final
0 1 2 3
2 1 1
3 3
1
2 2
1
1 1
0 0
3
0 1 2
Flecha(Norte) Flecha(Oeste)
0 1 2
0 1 2
2 2
2 2 1
1
1 1
1 1 1
1 1
0 0 0 0
1
0 1 2
0 1 2
Definí el procedimiento Flecha(direccion) que dibuje una flecha roja en la dirección
correspondiente. El cabezal empieza y debe quedar siempre en el centro, como se ve en los
tableros de ejemplo.
¡Dame una pista!
procedure Punta(direccion) {
2
Mover(direccion)
3
Poner(Rojo)
4
Mover(opuesto(direccion))
5
}
6
procedure Flecha(direccion) {
7
Punta(previo(direccion))
8
Punta(direccion)
9
Punta(siguiente(direccion))
10
}
Enviar
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1
1 1
1
0 0
1
0 1 2
Tablero inicial
0 1 2
2 2
1 1
0 0
0 1 2
Tablero final
0 1 2
2 2
1
1 1
1 1
0 0
0 1 2
Ejercicio 11: Copiando bolitas
Supongamos ahora que queremos "copiar" las bolitas verdes, haciendo
que haya la misma cantidad de rojas y pensemos cómo podría ser ese
procedimiento.
Una tarea que seguro tenemos que hacer es poner muchas bolitas, y para
eso ya sabemos que existe el procedimiento PonerN que construimos
varios ejercicios atrás. El color de las bolitas que tenemos que poner
también lo sabemos: Rojo, pero... ¿cómo sabemos cuántas poner?
Lo que nos está faltando es una forma de contar cuántas bolitas verdes
hay, y para eso necesitamos otra función que nos da
Gobstones: nroBolitas(color). Lo que hace es simple: nos retorna la cantidad
de bolitas de un color determinado en la posición actual.
Solución
Biblioteca
1
procedure CopiarVerdesEnRojas() {
2
PonerN(nroBolitas(Verde), Rojo)
3
}
Enviar
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
0 1
1 1
0 0
2
0 1
Tablero final
0 1
1 1
0 0
2 2
0 1
1 1
0 0
7
0 1
Tablero final
0 1
1 1
0 0
7 7
0 1
Definí SacarTodas(color), que recibe un color y saca todas las bolitas que hay de ese color (no
debe hacer nada con el resto de los colores).
¡Dame una pista!
Solución
Biblioteca
1
procedure SacarTodas(color) {
2
SacarN(nroBolitas(color), color)
3
}
Enviar
Tablero inicial
0 1
1 1
0 0
3
0 1
Tablero final
0 1
1 1
0 0
0 1
Tablero inicial
0 1
1 1
0 0
5
0 1
Tablero final
0 1
1 1
0 0
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
¡Terminaste Expresiones!
Repasemos todo lo que aprendiste en esta guía:
Además de los literales que ya venías usando, existen también otro tipo
de expresiones que realizan algún tipo de operación y pueden depender
de dos cosas: de sus parámetros y del estado del tablero.
Aritméticas: +, -, *, div.
De direcciones: opuesto, siguiente, previo.
Númericas: nroBolitas.
Alternativa Condicional
Hasta ahora, todos los programas y procedimientos que hicimos fueron
sobre tableros conocidos, sabíamos exactamente de qué tamaño era el
tablero, dónde estaba el cabezal y cuántas bolitas había en cada celda.
Nos introduciremos ahora en el mundo de lo desconocido, donde la
programación cobra aún mucho más sentido. Con la herramienta que
veremos podremos resolver problemas nuevos y evitar errores que hasta
ahora no podíamos: sacar una bolita Roja sólo si hay alguna, movernos al
Norte si eso no provoca que nos caigamos del tablero o agregar una bolita
Azul sólo si ya hay una Verde.
Ejercicios
Con lo que sabés hasta ahora, probablemente tu primera idea sea hacer
algo como esto:
procedure SacarAzulConMiedo() {
Sacar(Azul)
}
1
procedure SacarAzulConMiedo() {
2
Sacar(Azul)
3
}
Enviar
0 1
1 1
1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
0 1
1 1
0 0
0 1
Tablero final
BOOM
[2:2]: No se puede sacar una bolita de color Azul: no hay bolitas de ese color.
Funcionó para el primer tablero porque tenía una bolita azul, pero
hizo BOOM para el segundo porque estaba vacío, claro.
procedure SacarAzulConMiedo() {
if (hayBolitas(Azul)) {
Sacar(Azul)
}
}
1
procedure SacarAzulConMiedo() {
2
if (hayBolitas(Azul)) {
3
Sacar(Azul)
4
}
5
}
Enviar
0 1
1 1
1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
¡Bien!
procedure SacarAzulConMiedo() {
if (hayBolitas(Azul)) {
Sacar(Azul)
}
}
Como notarás, introdujimos una nueva estructura de control: el if, que en castellano
significa si; entendiendo al si como condicional ("si tuviera hambre me comería una
empanada") y no como afirmación ("sí, yo rompí el teléfono").
Entonces, lo que le estamos diciendo a la computadora es "si hay bolitas azules, sacá
una bolita azul", que dicho así suena un poco tonto ¡y lo es!. Ya te dijimos que la
computadora sólo sabe cumplir órdenes.
¡Ahora te toca a vos! Modificá el procedimiento que te dimos para que saque una bolita
roja, sólo si hay alguna.
¡Dame una pista!
procedure SacarRojoConMiedo() {
2
if (hayBolitas(Rojo)) {
3
Sacar(Rojo)
4
}
5
}
Enviar
Tablero inicial
0 1
1 1
0 0
1
0 1
Tablero final
0 1
1 1
0 0
0 1
Tablero inicial
0 1
1 1
0 0
4
0 1
Tablero final
0 1
1 1
0 0
3
0 1
Tablero inicial
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
En primer lugar, tenemos la condición. Por ahora siempre fue hayBolitas(color) pero
podría ser cualquier otra cosa, ya veremos más ejemplos. Lo importante acá es que eso
es lo que decide si la acción se va a ejecutar o no.
¿Y qué es la acción? Básicamente, cualquier cosa que queramos hacer sobre el tablero.
Al igual que en el repeat, podemos hacer cuantas cosas se nos ocurran, no
necesariamente tiene que ser una sola.
Resumiendo: La acción que está dentro de la estructura del if podrá realizarse solo
cuando la condición sea verdadera.
procedure CompletarCelda() {
2
if (hayBolitas(Negro)) {
3
Poner(Azul)
4
Poner(Rojo)
5
Poner(Verde)
6
}
7
}
Enviar
Tablero inicial
0 1
1 1
2
0 0
0 1
Tablero final
0 1
1 1
1 2
0 0
1 1
0 1
Tablero inicial
0 1
1 1
0 0
1
0 1
Tablero final
0 1
1 1
0 0
1
0 1
Otra que trae True o False (y que vas a tener que usar ahora)
es puedeMover(direccion) que nos sirve para saber si el cabezal puede
moverse en una cierta dirección.
0 1
2 2
1 1
0 0
0 1
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
Por suerte, esto se escribe en Gobstones igual que en la matemática tradicional, con
un < para el menor y un > para el mayor. Ejemplo: nroBolitas(Verde) > 5 nos indica si hay
más de 5 bolitas verdes.
Sabiendo esto, intentá crear un programa que ponga 1 bolita negra sólo si hay menos de 5
bolitas negras.
program {
2
if (nroBolitas(Negro) < 5) {
3
Poner(Negro)
4
}
5
}
Enviar
Tablero inicial
0 1
2 2
1 1
3
0 0
0 1
Tablero final
0 1
2 2
1 1
4
0 0
0 1
Tablero inicial
0 1
2 2
1 1
6
0 0
0 1
Tablero final
0 1
2 2
1 1
6
0 0
0 1
Algo que también se puede hacer es negar una condición, algo que en
castellano puede sonar medio raro pero que en programación se hace un
montón. Los ejemplos anteriores quedarían: ¿no hay alguna bolita roja?
¿no me puedo mover al Este? ¿no hay más de 3 bolitas azules?
Original Negada
1
procedure AsegurarUnaBolitaVerde() {
2
if (not hayBolitas(Verde)) {
3
Poner(Verde)
4
}
5
}
Enviar
0 1
1 1
0 0
1
0 1
Tablero final
0 1
1 1
0 0
1
0 1
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
1
0 1
Para estos casos, en Gobstones tenemos una nueva palabra clave que nos
ayuda a cumplir nuestra tarea: el else. En castellano significa si no y hace
justamente lo que necesitamos: ejecuta una serie de acciones si no se
cumple la condición que pusimos en el if.
procedure MoverComoSea() {
if (puedeMover(Oeste)) {
Mover(Oeste)
} else {
Mover(Norte)
}
}
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
0 1
1 1
0 0
0 1
Tablero final
0 1
1 1
0 0
0 1
¡Espectacular!
0 1 2
1 1 1
2 2
1 1 1
1 1
1 1 1
0 0
0 1 2
Tablero final
0 1 2
1 1 1
2 2
1 1
1 1
1
1 1 1
0 0
0 1 2
0 1 2
2 2
1 1 1
1 1
1 1 1
0 0
1 1 1
0 1 2
Tablero final
0 1 2
2 2
1 1 1
1
1 1
1 1
0 0
1 1 1
0 1 2
Funciones
Cuando introdujimos la noción de procedimientos, dijimos que:
Ejercicios
procedure MoverSegunBolitas() {
if (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde) > 10) {
Mover(Este)
} else {
Mover(Norte)
}
}
1
procedure MoverSegunBolitas() {
2
if (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde) > 10) {
3
Mover(Este)
4
} else {
5
Mover(Norte)
6
}
7
}
Enviar
0 1
1 1
3 2
0 0
4 3
0 1
Tablero final
0 1
1 1
3 2
0 0
4 3
0 1
0 1
1 1
3 2
0 0
0 1
Tablero final
0 1
1 1
3 2
0 0
0 1
Entonces, lo que nos está faltando es algún mecanismo para poder darle
un nombre a esa expresión compleja; algo análogo a
los procedimientos pero que sirva para encapsular expresiones.
function nroBolitasTotal() {
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
}
1
function nroBolitasTotal() {
2
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
nroBolitasTotal() -> 12
Tablero inicial
0 1
1 1
3 2
0 0
4 3
0 1
nroBolitasTotal() -> 5
Tablero inicial
0 1
1 1
3 2
0 0
0 1
1
procedure MoverSegunBolitas() {
2
if (nroBolitasTotal() > 10) {
3
Mover(Este)
4
} else {
5
Mover(Norte)
6
}
7
}
Enviar
0 1
1 1
3 2
0 0
4 3
0 1
Tablero final
0 1
1 1
3 2
0 0
4 3
0 1
0 1
1 1
3 2
0 0
0 1
Tablero final
0 1
1 1
3 2
0 0
0 1
Ejercicio 4: todasExcepto
Te toca ahora definir tu primera función: todasExcepto(color). Lo que tiene
que hacer es sencillo, contar cuántas bolitas hay en la celda actual sin
tener en cuenta las del color recibido por parámetro.
Por ejemplo, todasExcepto(Verde) debería contar todas las bolitas azules,
negras y rojas que hay en la celda actual (o dicho de otra forma: todas las
bolitas que hay menos las verdes).
Definí la función todasExcepto para que retorne la cantidad de bolitas que no sean del
color que se le pasa por parámetro.
¡Dame una pista!
1
function todasExcepto(color) {
2
return (nroBolitasTotal() - nroBolitas(color))
3
}
Enviar
todasExcepto() -> 8
Tablero inicial
0 1
1 1
3 2
0 0
4 3
0 1
todasExcepto() -> 10
Tablero inicial
0 1
1 1
3 2
0 0
4 3
0 1
Las funciones, como cualquier otra expresión, se pueden usar para definir
nuevas funciones.
En este casillero:
4 3
0 0
2 1
4 3
0 0
9 1
Solución
Biblioteca
1
function rojoEsDominante() {
2
return (nroBolitas(Rojo) > todasExcepto(Rojo))
3
}
Enviar
0 1
1 1
3 2
0 0
4 3
0 1
0 1
1 1
3 2
0 0
10 3
0 1
Ejercicio 6: En libertad
Queremos definir la función esLibreCostados(), que determine si el cabezal
tiene libertad para moverse hacia los costados (es decir, Este y Oeste).
Antes que nada, pensemos, ¿de qué tipo tiene que ser el valor que
retorna nuestra función? Será...
Pero, ups, hay un problema más; hay que hacer DOS preguntas:
¿se puede mover al Este? Y ¿se puede mover al Oeste?.
Bueno, existe el operador && que sirve justamente para eso: toma dos
expresiones booleanas y devuelve True solo si ambas son verdaderas. Si
sabés algo de lógica, esto es lo que comunmente se
denomina conjunción y se lo suele representar con el símbolo ∧.
1
function esLibreCostados() {
2
return (puedeMover(Este) && puedeMover(Oeste))
3
}
Enviar
0 1 2
1 1
0 0
0 1 2
0 1 2
1 1
0 0
0 1 2
1
function hayAlgunaBolita() {
2
return (hayBolitas(Azul) || hayBolitas(Verde) || hayBolitas(Negro) || hayBolitas(Rojo) )
3
}
Enviar
1 1
0 0
0 1
0 1
1 1
0 0
1 3
0 1
0 1
1 1
8
0 0
0 1
0 1
1 1
0 0
2
0 1
Tanto && como || pueden usarse varias veces sin la necesidad de usar
paréntesis, siempre y cuando tengan expresiones booleanas a ambos
lados.
1
function estoyEnUnBorde() {
2
return (not puedeMover(Norte) || not puedeMover(Este) || not puedeMover(Sur) || not
puedeMover(Oeste))
3
}
Enviar
0 1 2
2 2
1 1
0 0
0 1 2
0 1 2
2 2
1 1
0 0
0 1 2
0 1 2
2 2
1 1
0 0
0 1 2
Definí la función hayBolitasAl(direccion, color) que informe si hay alguna bolita del color
especificado en la celda vecina hacia la dirección dada.
Ojo: como ya dijimos, la última línea siempre tiene que tener un return.
1
function hayBolitasAl(direccion, color) {
2
Mover(direccion)
3
return (hayBolitas(color))
4
}
Enviar
0 1 2
2 2
1 1
1
0 0
1
0 1 2
0 1 2
2 2
1 1
1
0 0
1
0 1 2
0 1 2
2 2
1 1
1
0 0
1
0 1 2
Esto pasa porque en Gobstones las funciones son puras, no tienen efecto
real sobre el tablero. En ese sentido decimos que son las compañeras
ideales: después de cumplir su tarea dejan todo como lo encontraron.
Ejercicio 10: Lo ideal también se puede romper
Como en la definición de hayBolitasAl se usa Mover, es obvio que hay casos
en los cuales podría romperse: basta con posicionar el cabezal en el
origen y preguntar si hayBolitas de algún color al Oeste.
Pero, ¿no era que las funciones eran puras y no tenían efecto real? ¿Qué
pasa si una función hace BOOM?
Hagamos la prueba: vamos a probar la función hayBolitasAl del ejercicio anterior con
casos donde no pueda moverse el cabezal. Presioná Enviar y mirá el resultado.
1
function hayBolitasAl(direccion, color) {
2
Mover(direccion)
3
return (hayBolitas(color))
4
}
Enviar
Tablero inicial
0 1 2
2 2
1 1
1
0 0
1
0 1 2
Tablero final
BOOM
[2:2]: No se puede mover hacia la dirección Sur: cae afuera del tablero.
Tablero inicial
0 1 2
2 2
1 1
1
0 0
1
0 1 2
Tablero final
BOOM
[2:2]: No se puede mover hacia la dirección Oeste: cae afuera del tablero.
¡BOOM!
Las funciones también pueden producir BOOM y por lo tanto tenés que
tener el mismo cuidado que al programar un procedimiento: que el
cabezal no salga del tablero, no intentar sacar bolitas de un color que no
hay, etc.
Para este tablero devolvería True: Y para este tablero devolvería False:
Para este tablero devolvería True: Y para este tablero devolvería False:
0 1
0 1
4 4 4 4
1
3 3
3 3
2 2
2 2
1 1
1 1
0 0
0 0
0 1
0 1
Solución
Biblioteca
1
function hayBolitasLejosAl(direccion, color, distancia) {
2
repeat(distancia) {
3
Mover(direccion)
4
}
5
return (hayBolitas(color))
6
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
0 1 2
2 2
1
1 1
0 0
0 1 2
0 1 2 3 4
1 1
0 0
1
0 1 2 3 4
0 1 2 3 4
1 1
1
0 0
0 1 2 3 4
Solución
Biblioteca
1
function estoyRodeadoDe(color) {
2
return (hayBolitasAl(Norte, color) && hayBolitasAl(Este, color) && hayBolitasAl(Sur, color) &&
3
hayBolitasAl(Oeste, color))
4
}
Enviar
0 1 2
2 2
1
1 1
1 1
0 0
1
0 1 2
0 1 2
1
2 2
1 1
1 1
1
0 0
0 1 2
0 1 2
2 2
1
1 1
1 1
0 0
0 1 2
0 1 2
2 2
1
1 1
1 1
0 0
0 1 2
0 1 2
2 2
1
1 1
1
0 0
0 1 2
0 1 2
1
2 2
1
1 1
1
0 0
0 1 2
El límite puede ser por alguno de dos factores: porque estoy en un borde y entonces no
me puedo mover en alguna dirección, o porque estoy rodeado de bolitas rojas que me
cortan el paso. Si ocurre alguna de esas dos condiciones, quiere decir que hay un límite.
Solución
Biblioteca
function hayLimite() {
2
}
Enviar
Tablero inicial
0 1 2
2 2
1
1 1
1 1
0 0
1
0 1 2
0 1 2
2 2
1 1
0 0
0 1 2
Tablero inicial
0 1 2
2 2
1
1 1
1
0 0
1
2
0 1
¡Terminaste Funciones!
Esta lección fue bastante intensa, aprendiste unas cuantas cosas:
¡Sigamos programando!
Capítulo 2: Programación Imperativa
¿Ya estás para salir del tablero? ¡Acompañanos a aprender más
sobre programación imperativa y estructuras de datos de la mano del
lenguaje JavaScript!
Lecciones
1. Introducción a JavaScript
2. Funciones, definición
3. Funciones, uso
4. Probando funciones
5. Haciendo cuentas
6. Poniendo topes
7. Libros de la buena memoria
8. Booleanos
9. Palabras, sólo palabras
10. Operando strings
11. ¡GRITAR!
12. ¿Y qué tal si...?
13. ¿De qué signo sos?
14. El retorno del booleano
15. Los premios
16. Tipos de datos
17. Datos de todo tipo
1. Comprando Hardware
2. ¿Me conviene?
3. Triangulos
4. Cuadrados
5. ¿Está afinado?
6. ¿Está cerca?
7. Cartelitos
8. Más Cartelitos
9. Cartelitos óptimos
10. Cara o ceca
11. ¡Envido!
12. ¡Quiero retruco!
13. ¡Quiero vale cuatro!
3. Variables y procedimientos
1. ¿Y el tablero?
2. Impresión por pantalla
3. Martin Fierro
4. ¿Y los procedimientos?
5. ¿Y el program?
6. Coerciones
7. El círculo de la vida
8. PIenso que así es más fácil
9. Esto no tiene valor
10. Variables globales
11. La buena fortuna
12. ¿Y esto cuánto vale?
4. Lógica booleana
5. Listas
1. Series favoritas
2. Y esto, es una lista
3. Juegos de azar
4. Listas vacías
5. ¿Cuántos elementos tenés?
6. Agregando sabor
7. Trasladar
8. ¿Y dónde está?
9. Contiene
10. Enésimo elemento
11. Más premios
12. No te olvides de saludar
6. Registros
7. Recorridos
Apéndice
Sin embargo, en los programas "reales" rara vez trabajamos con tableros
y bolitas de colores: la programación va más allá de eso. ¿Cómo es
entonces esto de vivir fuera del tablero?
¡Acompañanos!
Ejercicios
1. Introducción a JavaScript
2. Funciones, definición
3. Funciones, uso
4. Probando funciones
5. Haciendo cuentas
6. Poniendo topes
7. Libros de la buena memoria
8. Booleanos
9. Palabras, sólo palabras
10. Operando strings
11. ¡GRITAR!
12. ¿Y qué tal si...?
13. ¿De qué signo sos?
14. El retorno del booleano
15. Los premios
16. Tipos de datos
17. Datos de todo tipo
¡Acompañanos!
function doble(numero) {
return 2 * numero;
}
function doble(numero) {
return (2* numero)
}
Solución
Consola
1
function mitad(numero) {
2
return numero / 2;
3
}
Enviar
doble(3)
function doble(numero) {
return 2 * numero;
}
function siguienteDelDoble(numero) {
return doble(numero) + 1;
}
O incluso mejor:
function doble(numero) {
return 2 * numero;
}
function siguiente(numero) {
return numero + 1;
}
function siguienteDelDoble(numero) {
return siguiente(doble(numero));
}
Solución
Consola
1
function anterior(numero) {
2
return numero - 1;
3
}
4
function triple(numero) {
5
return numero * 3;
6
}
7
function anteriorDelTriple(numero) {
8
return anterior(triple(numero));
9
}
Enviar
La consola es una herramienta muy útil para hacer pruebas rápidas sobre
lo que estás haciendo: te permite, por ejemplo, probar expresiones,
funciones que vengan con JavaScript, o incluso funciones que vos
definas en el editor.
4+5
[Link](4.5)
funcionMisteriosa(1, 2, 3) (ya la definimos por vos y la podés usar)
>4 + 5
=> 9
> [Link](4.5)
=> 5
> funcionMisteriosa(1, 2, 3)
=> 9
>
[Link](4.4)
[Link](4.6)
[Link](4, 7)
[Link](4, 7)
> [Link](4.4)
=> 4
> [Link](4.6)
=> 5
> [Link](4, 7)
=> 7
> [Link](4, 7)
=> 4
Ejercicio 6: Poniendo topes
Hagamos un alto en nuestro camino y miremos las
funciones [Link] y [Link], que nos pueden ahorrar más trabajo del que
parece.
Necesitamos una función que diga cuánta plata queda en tu cuenta (que
tiene un cierto saldo) si extráes un cierto monto:
Como ves, esto es casi una resta entre saldo y monto, con la salvedad de
que estamos poniendo un tope inferior: no puede dar menos de cero .
Solución
Consola
1
function extraer(saldo, monto) {
2
return [Link](saldo - monto, 0);
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Ah, y si estás pensando “en Gobstones podría haber hecho esto con un if”,
¡tenés razón!. Pero esta solución es mucho más breve y simple .
function esDiaFavorito(diaDelMes) {
return diaDelMes === 1 ;
}
> esDiaFavorito(13)
false
> esDiaFavorito(1)
true
¡Ahora te toca a vos! Dani también dice que a alguien leGustaLeer, cuando la
cantidad de libros que recuerda haber leído es mayor a 20. Por ejemplo:
> leGustaLeer(15)
false
> leGustaLeer(45)
true
Solución
Consola
1
function leGustaLeer(libros) {
2
return libros > 20
3
}
Enviar
¡Bien hecho!
Ejercicio 8: Booleanos
Ahora miremos a los booleanos con un poco más de detalle:
Ejemplos:
Solución
Consola
1
function estaEntre(x, y, z) {
2
return (x > y) && (x < z);
3
}
4
function estaFueraDeRango(x, y, z) {
5
return (x < y) || (x > z);
6
}
Enviar
¡Bien hecho!
¿Y qué podemos hacer con los strings? Por ejemplo, compararlos, como a
cualquier otro valor:
Veamos si queda claro: definí la función esFinDeSemana que tome un string que
represente el nombre de un día de la semana, y nos diga si es "sábado" o "domingo".
> esFinDeSemana("sábado")
true
> esFinDeSemana("martes")
false
Solución
Consola
1
function esFinDeSemana(dia) {
2
return (dia === "sábado") || (dia === "domingo")
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
> longitud("biblioteca")
10
> longitud("babel")
5
Solución
Biblioteca
Consola
1
function longitudNombreCompleto(nombre, apellido) {
2
return longitud(nombre) + 1 + longitud(apellido);
3
}
Enviar
Por ejemplo:
> gritar("miguel")
"¡MIGUEL!"
> gritar("benito")
"¡BENITO!"
Definí la función gritar. Te dejamos para que uses la función convertirEnMayuscula, que,
ehm... bueno... básicamente convierte en mayúsculas un string .
¡Dame una pista!
Solución
Biblioteca
Consola
1
function gritar(palabra) {
2
return "¡" + convertirEnMayuscula(palabra) + "!";
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
//Equivalente a [Link]
function valorAbsoluto(unNumero) {
if (unNumero >= 0) {
return unNumero;
} else {
return -unNumero;
}
}
Veamos si se entiende: definí la función maximo, que funcione como [Link] (¡no
vale usarla!) y retorne el máximo entre dos números. Por ejemplo, el máximo entre
4 y 5 es 5, y el máximo entre 10 y 4, es 10.
Solución
Biblioteca
Consola
1
function maximo(numero1, numero2) {
2
if (numero1 > numero2) {
3
return numero1;
4
} else {
5
return numero2;
6
}
7
}
Enviar
Agus se olvida siempre de como tiene que cuidar sus plantas , por eso
definió la función cuidadoSegun(dia) que le recuerda que los lunes tiene que
fertilizarlas, los viernes las tiene que fumigar y el resto de los días las tiene
que regar.
function cuidadoSegun(dia) {
if (dia === "lunes") {
return "fertilizar";
} else if (dia === "viernes") {
return "fumigar";
} else {
return "regar";
}
}
¡Ahora te toca a vos! Definí la función signo, que dado un número nos retorne:
1 si el número es positivo
0 si el número es cero
-1 si el número es negativo
Solución
Biblioteca
Consola
1
function signo(numero) {
2
if (numero > 0) {
3
return 1
4
} if (numero === 0) {
5
return 0
6
} if (numero < 0) {
7
return -1
8
}
9
}
Enviar
function esMayorDeEdad(edad) {
if (edad >= 18) {
return true;
} else {
return false;
}
}
function esMayorDeEdad(edad) {
return edad >= 18;
}
es positivo, y
es menor a 100, y
no es el 15.
Solución
Biblioteca
Consola
1
function esNumeroDeLaSuerte(numero) {
2
return (numero >= 0) && (numero < 100) && (numero !== 15)
3
}
Enviar
En general, como regla práctica, si tenés ifs que devuelven trues o falses,
probablemente lo estás haciendo mal . Y si bien funcionará, habrás escrito
código innecesariamente complejo y/o extenso.
Ejemplo:
> medallaSegunPuesto(1)
"oro"
> medallaSegunPuesto(5)
"nada"
Solución
Biblioteca
Consola
1
function medallaSegunPuesto(puesto) {
2
if (puesto === 1) {
3
return "oro";
4
}
5
if (puesto === 2) {
6
return "plata";
7
}
8
if (puesto === 3) {
9
return "bronce";
10
} else {
11
return "nada";
12
}
13
}
Enviar
Además, existen operaciones que sirven para todos los tipos de datos, por
ejemplo:
>5 + 6
=> 11
> 6 === 6
=> true
>8 > 6
=> true
> !true
=> false
=> 0
>
4 + 4 vale 8.
"4" + "4" vale "44".
"on" + "ce" vale "once".
true && false vale false.
5 >= 6 vale false.
Ejercicios
1. Comprando Hardware
2. ¿Me conviene?
3. Triangulos
4. Cuadrados
5. ¿Está afinado?
6. ¿Está cerca?
7. Cartelitos
8. Más Cartelitos
9. Cartelitos óptimos
10. Cara o ceca
11. ¡Envido!
12. ¡Quiero retruco!
13. ¡Quiero vale cuatro!
> cuantoCuesta(25, 8)
4100
Solución
Biblioteca
Consola
1
function cuantoCuesta(pulgada, gb) {
2
return 60 * pulgada + 200 * gb + 1000;
3
}
Enviar
> meConviene(25, 8)
false // porque el monitor es demasiado chico
> meConviene(42, 12)
true // cumple las tres condiciones
Solución
Biblioteca
Consola
1
function meConviene(pulgadas, gb) {
2
return cuantoCuesta(pulgadas, gb) < 6000 && pulgadas >= 32 && gb >= 8;
3
}
Enviar
Ejercicio 3: Triangulos
¡Hora de hacer un poco de geometría! Queremos saber algunas cosas
sobre un triángulo:
Solución
Biblioteca
Consola
1
function perimetroTriangulo(lado1, lado2, lado3) {
2
return lado1 + lado2 + lado3;
3
}
4
function areaTriangulo(base, altura) {
5
return base * altura / 2;
6
}
Enviar
Ejercicio 4: Cuadrados
Y ahora es el turno de los cuadrados; queremos saber
Solución
Biblioteca
Consola
1
function perimetroCuadrado(lado) {
2
return lado * 4;
3
}
4
function areaCuadrado(lado) {
5
return lado * lado;
6
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Definí una función estaAfinado, que reciba la frecuencia (un número) del la central, y
retorne si dicha frecuencia es igual a 440Hz.
> estaAfinado(440)
true
Solución
Biblioteca
Consola
1
function estaAfinado(frecuencia) {
2
return frecuencia === 440;
3
}
Enviar
> estaCerca(443)
true //está en el rango 437-443
> estaCerca(442)
true //ídem caso anterior
> estaCerca(440)
false //está en el rango,
//pero es exactamente 440
> estaCerca(430)
false //está fuera del rango
Solución
Biblioteca
Consola
1
function estaCerca(frecuencia) {
2
return frecuencia >= 437 && frecuencia <= 443 && frecuencia !== 440;
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Ejercicio 7: Cartelitos
Para una importante conferencia, el comité organizador nos pidió que
escribamos cartelitos identificatorios que cada asistente va a tener.
Solución
Biblioteca
Consola
1
function escribirCartelito(titulo, nombre, apellido) {
2
return titulo + " " + nombre + " " + apellido;
3
}
Enviar
1. el título;
2. el nombre;
3. el apellido;
4. un booleano que nos indique si queremos un cartelito corto con
sólo título y apellido, o uno largo, como hasta ahora.
// cartelito corto
> escribirCartelito("Lic.", "Tomás", "Peralta", true)
"Lic. Peralta"
// cartelito largo
> escribirCartelito("Ing.", "Dana", "Velázquez", false)
"Ing. Dana Velázquez"
Solución
Biblioteca
Consola
1
//modificá esta función
2
function escribirCartelito(titulo, nombre, apellido, corto) {
3
if (corto) {
4
return titulo + " " + apellido;
5
} else {
6
return titulo + " " + nombre + " " + apellido;
7
}
8
}
Enviar
1
function escribirCartelitoOptimo(titulo, nombre, apellido) {
2
return escribirCartelito(titulo, nombre, apellido, (longitud(nombre + apellido) > 15));
3
}
Enviar
Es allí que tomamos una moneda y decimos: si sale cara, comemos pizzas,
si no, empanadas.
Definí una función decisionConMoneda, que toma tres parámetros y retorna el segundo
si el primero es "cara", o el tercero, si sale "ceca". Por ejemplo:
Solución
Biblioteca
Consola
1
function decisionConMoneda(lado, decision1, decision2) {
2
if (lado === "cara") {
3
return decision1;
4
} else {
5
return decision2;
6
}
7
}
Enviar
Definí una función valorEnvido, que tome un número de carta y retorne su valor de
envido.
> valorEnvido(12)
0
> valorEnvido(3)
3
Solución
Biblioteca
Consola
1
function valorEnvido(carta) {
2
if (carta > 7) {
3
return 0;
4
} else {
5
return carta;
6
}
7
}
Enviar
Si las dos cartas son del mismo palo, el valor del envido es la suma
de sus valores de envido más 20.
De lo contrario, el valor del envido es el mayor valor de envido
entre ellas.
Solución
Biblioteca
Consola
1
function puntosDeEnvidoTotales(carta1, palo1, carta2, palo2) {
2
if (palo1 === palo2) {
3
return 20 + valorEnvido(carta1) + valorEnvido(carta2);
4
} else {
5
return [Link](valorEnvido(carta1), valorEnvido(carta2));
6
}
7
}
Enviar
truco 2
retruco 3
vale cuatro 4
Definí la función valorCantoTruco, que tome el canto y retorne cuántos puntos vale.
> valorCantoTruco("retruco")
3
Asumí que sólo te van a pasar como argumento un string que represente un canto
de truco. Por ejemplo, no vamos a probar la función para el
caso valorCantoTruco("zaraza")
Solución
Biblioteca
Consola
1
function valorCantoTruco(canto) {
2
if (canto === "truco") {
3
return 2;
4
}
5
if (canto === "retruco") {
6
return 3;
7
}
8
if (canto === "vale cuatro") {
9
return 4;
10
}
11
}
Enviar
Variables y procedimientos
JavaScript, como la mayoría de los lenguajes comerciales (es decir,
lenguajes que se usan para desarrollar software "real"), no es tan puro en
su separación de funciones y procedimientos. Veamos por qué...
Ejercicios
1. ¿Y el tablero?
2. Impresión por pantalla
3. Martin Fierro
4. ¿Y los procedimientos?
5. ¿Y el program?
6. Coerciones
7. El círculo de la vida
8. PIenso que así es más fácil
9. Esto no tiene valor
10. Variables globales
11. La buena fortuna
12. ¿Y esto cuánto vale?
Ejercicio 1: ¿Y el tablero?
Hasta ahora en esta película hay un gran personaje que está faltando: el
tablero. Seguro está por aparecer, de forma triunfal y rimbombante...,
¿no?
1. El tablero nos servía para ver lo que nuestro programa hacía y qué
resultados generaba. Nos permitía también observar los cambios
de estado a causa del programa. Pero ahora ya tenemos
experiencia suficiente como para lanzarnos a programar sin tener
que "ver" lo que sucede.
2. Ahora contamos con la consola: una herramienta poderosa que
nos permite hacer pruebas más detalladas y flexibles.
¿No nos creés? Te presentamos un desafío: usando la consola, decí con tus propias
palabras qué hace la función funcionMisteriosa, que recibe dos números enteros como
argumentos.
¡Vas a ver que podés averiguarlo sin tener un tablero!
=> "wooooowwwwwwww!"
=> "woww!"
=> "woooooooooowwwwwwwwwwwwwww!"
>
function funcionEgocentrica() {
imprimir("soy una función que imprime por pantalla");
imprimir("y estoy por devolver el valor 5");
return 5;
}
=> <function>
> funcionEgocentrica()
> funcionEgocentrica()
>
Sin embargo, sólo podemos escribir strings y, una vez que escribimos en
la pantalla, no hay vuelta atrás: no hay forma de retroceder o deshacer.
Solución
Consola
1
function versosMartinFierro() {
2
imprimir("Aquí me pongo a cantar");
3
imprimir("Al compás de la vigüela;");
4
imprimir("Que el hombre que lo desvela");
5
imprimir("Una pena extraordinaria");
6
return 0;
7
}
Enviar
¡Bien hecho!
Acá parecería que llamamos a esta function porque nos interesa su efecto
de imprimir líneas; nos da igual lo que retorna. Quizás más que una
función, necesitamos definir un procedimiento. ¿Se podrá hacer esto en
JavaScript?
¡De la misma forma que las funciones!: usando la palabra clave function.
function versosMartinFierro() {
imprimir("Aquí me pongo a cantar");
imprimir("Al compás de la vigüela;");
imprimir("Que el hombre que lo desvela");
imprimir("Una pena extraordinaria");
}
Solución
Consola
1
function versosMartinFierro() {
2
imprimir("Aquí me pongo a cantar");
3
imprimir("Al compás de la vigüela;");
4
imprimir("Que el hombre que lo desvela");
5
imprimir("Una pena extraordinaria");
6
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
Ejercicio 5: ¿Y el program?
Ahora bien, más allá de que podamos consultar el resultado de una
función a través de la consola, también aprendimos anteriormente que los
programas tienen un punto de entrada: el program. ¿Dónde quedó?
imprimir("Hola, mundo!");
O si queremos un programa que tire tres veces los dados e imprima sus
resultados, podemos escribirlo así:
imprimir("Tirando dados");
imprimir("La primera tirada dio " + tirarDado());
imprimir("La segunda tirada dio " + tirarDado());
imprimir("La tercera tirada dio " + tirarDado());
Solución
Consola
1
imprimir("Tirando dados");
2
imprimir("La primera tirada dio " + tirarDado());
3
imprimir("La segunda tirada dio " + tirarDado());
4
imprimir("La tercera tirada dio " + tirarDado());
Enviar
Ejercicio 6: Coerciones
Volvamos un momento al código anterior. ¿Notás algo extraño en esta
expresión?
Veamos si queda claro, definí una función elefantesEquilibristas, que tome un número
de elefantes y devuelva una rima de una conocida canción:
> elefantesEquilibristas(3)
"3 elefantes se balanceaban"
> elefantesEquilibristas(462)
"462 elefantes se balanceaban"
Solución
Consola
1
function elefantesEquilibristas(numero) {
2
return numero + " elefantes se balanceaban"
3
}
Enviar
Solución
Consola
1
function perimetroCirculo(radio) {
2
return radio * 2 * 3.14159265358979;
3
}
4
function areaCirculo(radio) {
5
return radio * radio * 3.14159265358979;
6
}
Enviar
Las variables nos permiten nombrar y reutilizar valores. Similar a cómo los
procedimientos y funciones nos permiten dar nombres y reutilizar
soluciones a problemas más pequeños. Por ejemplo, si hacemos...
let primerMes = "enero"
Solución
Consola
1
let pi = 3.14159265358979;
2
function perimetroCirculo(radio) {
3
return radio * 2 * pi;
4
}
5
function areaCirculo(radio) {
6
return radio * radio * pi;
7
}
Enviar
function sumaSinSentido() {
return numero + 8;
}
> sumaSinSentido(2)
return numero + 8;
^
> sumaSinSentido(2)
return numero + 8;
^
>
¡Sí! Cuando declarás una variable tenés que darle un valor inicial, lo cual
se conoce como inicializar la variable.
function cuentaExtravagante(unNumero) {
let elDoble = unNumero * 2;
if (elDoble > 10) {
return elDoble;
} else {
return 0;
}
}
function puedeLlevar(pesoEquipaje) {
return pesoEquipaje <= pesoMaximoEquipajeEnGramos;
}
Veamos si queda claro: definí una función ascensorSobrecargado, que toma una
cantidad de personas y retorna si entre todas superan la carga máxima de 300 kg.
Tené en cuenta que nuestra función va a utilizar dos variables globales:
Solución
Consola
1
let cargaMaximaEnKilogramos = 300;
2
function ascensorSobrecargado(cantidadpersonas) {
3
return cantidadpersonas * pesoPromedioPersonaEnKilogramos >= cargaMaximaEnKilogramos;
4
}
Enviar
function pasarUnDiaNormal() {
diasSinAccidentesConVelociraptores = diasSinAccidentesConVelociraptores + 1
}
function tenerAccidenteConVelociraptores() {
diasSinAccidentesConVelociraptores = 0;
}
Solución
Consola
1
function aumentarFortuna() {
2
pesosEnMiBilletera = pesosEnMiBilletera * 2
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
x += y; //equivalente a x = x + y;
x *= y; //equivalente a x = x * y;
x -= y; //equivalente a x = x - y;
x++; //equivalente a x = x + 1;
function cuentaExtravagante() {
let numero = 8;
numero *= 2;
numero += 4;
return numero;
}
Ejercicios
¿Y esto para qué sirve? Por ejemplo, para modelar casos de alternancia
como prender y apagar una luz :
function apretarInterruptor() {
lamparaPrendida = !lamparaPrendida;
}
Solución
Consola
1
let mochilaAbierta = true;
2
function usarCierre() {
3
mochilaAbierta = !mochilaAbierta;
4
}
Enviar
Por ejemplo, si contamos con una función esPar, basta con negarla para
saber si un número es impar.
function esImpar(numero) {
return !esPar(numero);
}
Solución
Consola
1
function esMayorDeEdad(edad) {
2
return edad >= 18;
3
}
4
function esMenorDeEdad(edad) {
5
return !esMayorDeEdad(edad);
6
}
7
Enviar
Solución
Consola
1
function esPeripatetico(profesion, nacionalidad, kilometros) {
2
return profesion === "filósofo" && nacionalidad === "griego" && kilometros > 2;
3
}
Enviar
Por ejemplo, supongamos que una casa consume poca energía si se usa
el aire acondicionado a 24 grados y tiene al menos 5 lamparitas bajo
consumo. Podemos representar las expresiones de la siguiente forma:
A: En la casa se usa el aire acondicionado a 24 grados
B: La casa tiene al menos 5 lamparitas bajo consumo
A ^ B: La casa consume poca energía
A B A^B
V V V
V F F
F V F
F F F
¿No nos creés? Probá en la consola la función consumePocaEnergia, que recibe una
temperatura y una cantidad de lamparitas, y comprobá si se comporta como en la
tabla:
> consumePocaEnergia(24, 5)
> consumePocaEnergia(24, 0)
> consumePocaEnergia(21, 7)
> consumePocaEnergia(18, 1)
> consumePocaEnergia(24, 5)
=> true
> consumePocaEnergia(24, 0)
=> false
> consumePocaEnergia(21, 7)
=> false
> consumePocaEnergia(18, 1)
=> false
>
=> true
=> true
=> false
=> true
Ejercicio 6: Y ahora... ¿quién podrá ayudarnos?
Nuestra amiga Dory necesitaba hacer algunos trámites en el banco, pero
cuando llegó notó que estaba cerrado.
Para evitar que le ocurra nuevamente, vamos a definir una función que
ayude a la gente despistada como ella.
Es feriado, o
Es fin de semana, o
No estamos dentro del horario bancario.
Definí las funciones esFinDeSemana y estaCerrado. Tené en cuenta que los días se
reciben en minúscula:
Solución
Biblioteca
Consola
1
function esFinDeSemana(dia) {
2
return dia === "sabado" || dia === "domingo";
3
}
4
function estaCerrado(esFeriado, dia, horario) {
5
return esFeriado || esFinDeSemana(dia) || !dentroDeHorarioBancario(horario);
6
}
Enviar
Ejercicio 7: Claroscuro
Oli está diseñando una página web y se está centrando en el contraste de
sus componentes. Para lograrlo, nos pidió que definamos la
función tieneContraste que recibe como argumentos el color de la letra y el
color del fondo de la página y retorna si la página tiene contraste.
> esTonoClaro('rojo')
false
> esTonoClaro('blanco')
true
¡Ahora te toca a vos! Definí la función tieneContraste. Para que la página tenga
contraste tiene que tener el fondo claro y la letra no o bien tener la letra clara y el
fondo no.
Solución
Consola
1
function tieneContraste(fondo,letra){
2
return esTonoClaro(letra) && !esTonoClaro(fondo) || !esTonoClaro(letra) && esTonoClaro(fondo);
3
}
Enviar
la letra tiene tono claro el fondo tiene tono claro tiene contraste
=> false
=> false
tienContraste("blanco", "negro");
^
A B A⊻B
V V F
V F V
F V V
F F F
Veamos si se entiende: definí la función genérica xor, que tome dos booleanos y
retorne el valor de verdad correspondiente.
Solución
Consola
1
function xor(a, b){
2
return (a && !b) || (!a && b);
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas
5 * 3 + 8 / 4 - 3 = 14
=> false
=> true
=> false
=> true
>
Siguiente Ejercicio: Un ejercicio sin precedentes
¡Intentá resolverlo en una única función! Después vamos a ver cómo quedaría si
delegamos.
¡Dame una pista!
Solución
Consola
1
function sePuedeConcentrar(bebida,temp,bool) {
2
return (bebida === "té" && temp >= "95" && bool || (bebida === "mate" && temp === 80 &&
bool ) )
3
}
Enviar
Definí la función de 3 parámetros puedeSubirse que recibe una altura de una persona
en metros, si está acompañada y si tiene alguna afección cardíaca. Ejemplo:
Solución
Consola
1
function puedeSubirse(altura, acompañadaAdulto, afeccionCardiaca){
2
return ((altura >= 1.5) || (altura >= 1.2 && acompañadaAdulto)) && !afeccionCardiaca
3
}
Enviar
Listas
La programación no sería tan divertida y poderosa si sólo pudieramos
trabajar con una cosa por vez: muchas veces no vamos a querer
simplemente operar un string, un booleano o un número, sino varios a la
vez.
Ejercicios
1. Series favoritas
2. Y esto, es una lista
3. Juegos de azar
4. Listas vacías
5. ¿Cuántos elementos tenés?
6. Agregando sabor
7. Trasladar
8. ¿Y dónde está?
9. Contiene
10. Enésimo elemento
11. Más premios
12. No te olvides de saludar
seriesFavoritasDeAna
seriesFavoritasDeHector
["hola","mundo!"]
["hola","hola"]
Biblioteca:
/**/
//
// Por ejemplo:
//
// > longitud("hola")
// 4
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"
//
// Por ejemplo:
//
// true
/**/
/**/
//
// Por ejemplo:
//
// ¡estoy imprimiendo!
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2
/**/
//
// Por ejemplo:
//
// true
// false
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// 3
//
// > cancionesFavoritas
//
// > listaDeCompras
//
// 0
// 2
// -1
Consola:
¿Acaso hay una cantidad máxima de elementos? ¡No, no hay límite! Las
listas pueden tener cualquier cantidad de elementos.
Biblioteca
/**/
/**/
/**/
/**/
Consola
Biblioteca
numerosDeLoteria
salioCara
[[1, 2, 3], [4, 5, 6]]
Biblioteca
/**/
/**/
/**/
/**/
Consola:
> numerosDeLoteria
=> [2,11,17,32,36,39]
> salioCara
=> [false,false,true,false]
> [[1, 2, 3], [4, 5, 6]]
=> [[1,2,3],[4,5,6]]
>
Ejercicio 4: Listas vacías
Genial, ¡parece que una lista puede contener cualquier tipo de elemento!
Podemos tener listas de booleanos, de números, de strings, de listas...
let unaListaVacia = []
Biblioteca
/**/
/**/
/**/
/**/
Consola:
> unaListaVacia = []
=> []
>
Ejercicio 5: ¿Cuántos elementos tenés?
Por el momento ya sabemos qué cosas podemos representar con listas, y
cómo hacerlo. Pero, ¿qué podemos hacer con ellas?
longitud([])
longitud(numerosDeLoteria)
longitud([4, 3])
Biblioteca
/**/
/**/
/**/
/**/
Consola:
> longitud([])
=> 0
> longitud(numerosDeLoteria)
=> 6
> longitud([4, 3])
=> 2
>
Ejercicio 6: Agregando sabor
Las listas son muy útiles para contener múltiples elementos. ¡Pero hay
más! También podemos agregarle elementos en cualquier momento,
utilizando la función agregar, que recibe dos parámetros: la lista y el
elemento. Por ejemplo:
Biblioteca
/**/
/**/
/**/
> pertenencias
=> ["espada","escudo","antorcha"]
> agregar(pertenencias, "ballesta")
=> undefined
> pertenencias
=> ["espada","escudo","antorcha","ballesta"]
> remover(pertenencias)
=> undefined
> "ballesta"
=> "ballesta"
> pertenencias
=> ["espada","escudo","antorcha","ballesta"]
Ejercicio 7: Trasladar
Bueno, ya hablamos bastante; ¡es hora de la acción !
Solución
Biblioteca
Consola
1
function trasladar(lista1, lista2, elemento){
2
remover(lista1, elemento);
3
agregar(lista2, elemento);
4
}
Enviar
¡Felicitaciones!
posicion(diasLaborales, "osvaldo")
/**/
/**/
/**/
/**/
function listasIguales(unArray, otroArray) /* ... */
// Retorna un booleano que nos dice si dos listas son iguales
//
// Por ejemplo:
//
// > listasIguales([1, 2, 3], [1, 2, 3])
// true
// > listasIguales([1, 2, 3], [4, 5, 3])
// false
Consola:
Definí la función contiene que nos diga si una lista contiene un cierto elemento.
Solución
Biblioteca
Consola
1
function contiene(lista, numero) {
2
return posicion(lista, numero) >= 0;
3
}
Enviar
¡Bien hecho!
> mesesDelAnio[0]
"enero"
> ["ese", "perro", "tiene", "la", "cola", "peluda"][1]
"perro"
Biblioteca
/**/
/**/
/**/
/**/
let mesesDelAnio = ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto",
"septiembre", "octubre", "noviembre", "diciembre"];
consola
> [][0]
=> undefined
> [mesesDelAnio]
=>
[["enero","febrero","marzo","abril","mayo","junio","julio","agosto"
,"septiembre","octubre","noviembre","diciembre"]]
> ["ese", "perro", "tiene", "la", "cola", "peluda"][1]
=> "perro"
>
Ejercicio 11: Más premios
Si le pedís un elemento en una posición igual o mayor al tamaño de la
lista, vas a obtener undefined. No parece algo terrible, pero el problema es
que con undefined no podés hacer nada realmente útil.
> medallaSegunPuesto(1)
"oro"
> medallaSegunPuesto(2)
"plata"
> medallaSegunPuesto(3)
"bronce"
> medallaSegunPuesto(4)
"nada"
> medallaSegunPuesto(5)
"nada"
Solución
Biblioteca
Consola
1
let medalla=["oro", "plata", "bronce"]
2
function medallaSegunPuesto(puesto) {
3
if (puesto >= 4) {
4
return "nada"
5
} else {
6
return medalla[puesto - 1]
7
}
8
}
Enviar
Si teníamos $500 en nuestra billetera, después del for nos van a quedar
$303 porque:
Consola
>
Biblioteca:
/**/
function longitud(unString) /* ... */
// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4
/**/
/**/
/**/
/**/
Solucion
function saludar(personas) {
¡Terminaste Listas!
¡Felicitaciones!
Por último viste una introducción a cómo recorrerla, aunque este tema lo
profundizaremos un poco más adelante.
Registros
Muchas veces, cuando representamos cosas de la vida real en nuestros
programas, necesitamos poder agrupar múltiples características de esas
cosas de alguna forma.
Ejercicios
estatuaDeLaLibertad
cristoRedentor
torreEiffel
tajMahal
coliseo
Biblioteca
/**/
/**/
/**/
/**/
Por ejemplo, podríamos almacenar un libro de modo que cada campo del
registro fuese alguna característica: su título, su autor, su fecha de
publicación, y más.
/**/
/**/
/**/
Solucion:
¡Buenas habilidades de búsqueda! Los registros, al igual que las listas, son
una estructura de datos porque nos permiten organizar información. Pero
¿en qué se diferencia un registro de una lista?
En las listas podemos guardar muchos elementos de un mismo tipo que
representen una misma cosa (por ejemplo todos números, o todos
strings). No existen límites para las listas: pueden tener muchos
elementos, ¡o ninguno!
> tajMahal
{ nombre: "Taj Mahal", locacion: "Agra, India", anioDeConstruccion: 1653 }
> [Link]
"Agra, India"
> [Link]
1653
Declaramos los planetas mercurio, marte y saturno como registros con la siguiente
información: nombre, temperaturaPromedio y si tieneAnillos. ¡Probalos en la consola!
Biblioteca
/**/
/**/
/**/
/**/
/**/
=> {nombre:"Marte",temperaturaPromedio:-63,tieneAnillos:false}
> saturno
=> {nombre:"Saturno",temperaturaPromedio:-139,tieneAnillos:true}
> [Link]
=> undefined
> [Link]
=> undefined
>
Ejercicio 4: Temperatura de planeta
Ahora que agregamos registros de planetas, ¡trabajemos un poco con
ellos!
> temperaturaDePlaneta(mercurio)
"Mercurio tiene una temperatura promedio de 67 grados"
> temperaturaDePlaneta(saturno)
"Saturno tiene una temperatura promedio de -139 grados"
> temperaturaDePlaneta(venus)
"Venus tiene una temperatura promedio de 462 grados"
/**/
/**/
/**/
/**/
/**/
Solucion:
}
¡Muy bien! Tu solución pasó todas las pruebas
[Link] = -140;
> leeme
{ ruta: "C:\[Link]", creacion: "23/09/2004" }
> leeme
{ ruta: "C:\documentos\[Link]", creacion: "23/09/2004" }
/**/
/**/
/**/
Solucion
[Link] = nuevaruta
Bibliotecaq
/**/
/**/
/**/
/**/
Solucion
function esDelMilenioPasado(archivo) {
Por ejemplo, una lista puede ser el campo de un registro. Mirá estos
registros de postres, de los cuales sabemos cuántos minutos de cocción
requieren y sus ingredientes:
Biblioteca:
> masDificilDeCocinar(flanCasero, cheesecake)
{ ingredientes: ["huevos", "leche", "azúcar", "vainilla"], tiempoDeCoccion: 50 }
/**/
/**/
/**/
/**/
Solucion:
return postre1;
} else {
return postre2;
¡Sí! Así como trabajamos con listas de números, booleanos, strings o más
listas, también podemos listar registros. Se puede hacer todo lo que
hacías antes, como por ejemplo remover, saber su longitud o preguntar por
el elemento de cierta posición utilizando los corchetes [].
/**/
/**/
/**/
/**/
/**/
¡Sí! Así como trabajamos con listas de números, booleanos, strings o más
listas, también podemos listar registros. Se puede hacer todo lo que
hacías antes, como por ejemplo remover, saber su longitud o preguntar por
el elemento de cierta posición utilizando los corchetes [].
Biblioteca:
/**/
/**/
/**/
/**/
/**/
Consola:
> postresFavoritos
=> [{ingredientes:["galletitas","dulce de
leche","crema"],tiempoDeCoccion:20},{ingredientes:["huevos","leche"
,"azúcar","vainilla"],tiempoDeCoccion:50},{ingredientes:["queso
crema","frambuesas"],tiempoDeCoccion:80},{ingredientes:["jugo de
limón","almidón de maíz","leche","huevos"],tiempoDeCoccion:65}]
> monumentosDeAmerica
=> [{nombre:"Monumento Nacional a la Bandera",locacion:"Rosario,
Argentina",anioDeConstruccion:1957},{nombre:"Estatua de la
Libertad",locacion:"Nueva York, Estados Unidos de
América",anioDeConstruccion:1886},{nombre:"Cristo
Redentor",locacion:"Rio de Janeiro,
Brasil",anioDeConstruccion:1931}]
Definí el procedimiento agregarAPostresRapidos, que toma una lista con postres rápidos
y un postre por parámetro. Si el tiempo de cocción es de una hora o menos, se
agrega el registro a la lista.
¡Dame una pista!
Biblioteca:
/**/
/**/
/**/
/**/
Solucion:
agregar(postresRapidos, postre);
¡No se puede vivir a base de postres! Bueno, quizás sí, pero mantengamos
una alimentación saludable . Mediante un registro queremos modelar un
menú completo: consiste en un plato principal , los vegetales de la
ensalada que acompaña , y un postre como lo veníamos trabajando, es
decir, sigue siendo un registro.
Por ejemplo, el siguiente es un menú con bife de lomo como plato
principal, una ensalada de papa, zanahoria y arvejas como
acompañamiento y un cheesecake de postre. Como el registro es un poco
extenso, y para que sea más legible, lo vamos a escribir de la siguiente
forma:
let menuDelDia = {
platoPrincipal: "bife de lomo",
ensalada: ["papa", "zanahoria", "arvejas"],
postre: { ingredientes: ["queso crema", "frambuesas"], tiempoDeCoccion: 80 }
};
Averiguá qué devuelve el campo ingredientes del campo postre del registro menuInfantil.
¡Está un registro adentro del otro! La sintaxis es la siguiente:
[Link]
Biblioteca
/**/
/**/
/**/
/**/
/**/
> [Link]
=> ["galletitas","dulce de leche","crema"]
>
Ejercicio 11: ¡Azúcar!
Para terminar, trabajemos una vez más con los menúes.
Biblioteca:
/**/
/**/
/**/
/**/
Solcion
function endulzarMenu(menuDelDia) {
agregar([Link], "azúcar")
¡Terminaste Registros!
Durante la lección aprendiste cuál es la utilidad de esta estructura de
datos llamada registro, cómo acceder a sus campos y modificarlos, y
hasta viste que pueden anidarse (es decir, que haya un registro dentro de
otro). ¡Felicitaciones!
Recorridos
En lecciones anteriores definimos funciones, usamos registros y listas.
Ahora que tenemos todas esas herramientas, llega el momento de
combinarlas y aprender a correr las listas y hacer cosas más complejas.
¡Acompañanos!
Ejercicios
"Obvio, solo tenemos que sumar las ganancias de todos los balances",
dijimos, y escribimos el siguiente código:
function gananciaSemestre(balances) {
return balances[0].ganancia + balances[1].ganancia +
balances[2].ganancia + balances[3].ganancia +
balances[4].ganancia + balances[5].ganancia;
}
"Gracias ", nos dijo Ana, y se fue calcular las ganancias usando la función
que le pasamos. Pero un rato más tarde, volvió contándonos que también
había registrado los balances del primer trimestre de este año:
Y nos preguntó: "¿Podría usar esta función que me dieron para calcular las
ganancias del primer trimestre?".
¿Tiene algún problema la función gananciaSemestre que escribimos anteriormente?
¿Funcionará con los balances trimestrales? ¿Y con los cuatrimestrestrales?
¡Probala en la consola!
Biblioteca
let balancesUltimoSemestre = [{ mes: "julio", ganancia: 50 }, { mes: "agosto", ganancia: -12 }, { mes: "se
ptiembre", ganancia: 1000 }, { mes: "octubre", ganancia: 300 }, { mes: "noviembre", ganancia: 200 }, {
mes: "diciembre", ganancia: 0 }];
let balancesPrimerTrimestre = [{ mes: "enero", ganancia: 80 }, { mes: "febrero", ganancia: 453 }, { mes:
"marzo", ganancia: 1000 }];
function gananciaSemestre(balances) {
return balances[0].ganancia + balances[1].ganancia +
balances[2].ganancia + balances[3].ganancia +
balances[4].ganancia + balances[5].ganancia;
> gananciaSemestre
=> <function>
>
> gananciaSemestre
=> <function>
>
Ejercicio 2: ¿Y el resto de las ganancias?
La función gananciaSemestre anterior tiene dos problemas :
Lo que nos gustaría es poder sumar las ganancias de todos los balances
de una lista, sin importar cuántos haya realmente; queremos una
función gananciaTotal, que pueda sumar balances de cualquier período de
meses: semestres, cuatrimestres, trimestres, etc. ¡Qué difícil!
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 3 }
])
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 3 },
{ mes: "marzo", ganancia: 1 },
{ mes: "abril", ganancia: 8 },
{ mes: "mayo", ganancia: 8 },
{ mes: "junio", ganancia: -1 }
])
> gananciaTotal([])
function gananciaTotal0(balancesDeUnPeriodo) {
let sumatoria = 0;
return sumatoria;
}
function gananciaTotal1(balancesDeUnPeriodo) {
let sumatoria = 0;
sumatoria = sumatoria + balancesDeUnPeriodo[0].ganancia;
return sumatoria;
}
¿Y si tuviera 2 elementos?
function gananciaTotal2(balancesDeUnPeriodo) {
let sumatoria = 0;
sumatoria = sumatoria + balancesDeUnPeriodo[0].ganancia;
sumatoria = sumatoria + balancesDeUnPeriodo[1].ganancia;
return sumatoria;
}
¿Y si tuviera 3 elementos?
function gananciaTotal3(balancesDeUnPeriodo) {
let sumatoria = 0;
sumatoria = sumatoria + balancesDeUnPeriodo[0].ganancia;
sumatoria = sumatoria + balancesDeUnPeriodo[1].ganancia;
sumatoria = sumatoria + balancesDeUnPeriodo[2].ganancia;
return sumatoria;
}
function gananciaTotal4(balancesDeUnPeriodo) {
let sumatoria = 0;
return sumatoria;
¡Bien hecho!
function gananciaTotalN(unPeriodo) {
let sumatoria = 0; // esto siempre está
//... etc
return sumatoria; //esto siempre está
}
function gananciaTotal(balancesDeUnPeriodo) {
let sumatoria = 0;
for (let balance of balancesDeUnPeriodo) {
sumatoria = sumatoria + [Link];
}
return sumatoria;
}
Como ves, el for...of nos permite visitar y hacer algo con cada elemento de
una lista; en este caso, estaremos visitando
cada balance de balancesDeUnPeriodo.
> gananciaTotal([])
> gananciaTotal([
{ mes: "noviembre", ganancia: 5 }
])
> gananciaTotal([
{ mes: "marzo", ganancia: 8 },
{ mes: "agosto", ganancia: 10 }
])
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 10 },
{ mes: "marzo", ganancia: -20 }
])
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 10 },
{ mes: "marzo", ganancia: -20 },
{ mes: "abril", ganancia: 0 },
{ mes: "mayo", ganancia: 10 }
])
Biblioteca
function gananciaTotal(balancesDeUnPeriodo) {
let sumatoria = 0;
for (let balance of balancesDeUnPeriodo) {
sumatoria = sumatoria + [Link];
}
return sumatoria;
}
> gananciaTotal([])
=> 0
> gananciaTotal([
{ mes: "noviembre", ganancia: 5 }
])
=> 5
> gananciaTotal([
{ mes: "marzo", ganancia: 8 },
{ mes: "agosto", ganancia: 10 }
])
=> 18
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 10 },
{ mes: "marzo", ganancia: -20 }
])
=> -8
> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 10 },
{ mes: "marzo", ganancia: -20 },
{ mes: "abril", ganancia: 0 },
{ mes: "mayo", ganancia: 10 }
])
=> 2
>
Ejercicio 5: Cuentas claras
¡Ana tiene nuevos requirimientos! Ahora nos pidió lo siguiente: "Quiero
saber cuántos balances fueron positivos, es decir, aquellos en los que la
ganancia fue mayor a cero".
Solucion
function cantidadDeBalancesPositivos(balancesDeUnPeriodo) {
let cantidad = 0;
if ([Link] > 0) {
cantidad = cantidad + 1;
return cantidad;
> gananciaPromedio([
{ mes: "marzo", ganancia: 8 },
{ mes: "agosto", ganancia: 10 }
])
9
Solucion
function gananciaPromedio(balances) {
function cantidadDeBalancesPositivos(balancesDeUnPeriodo) {
let cantidad = 0;
for (let balance of balancesDeUnPeriodo) {
if ([Link] > 0) {
cantidad = cantidad + 1;
}
}
return cantidad;
}
Solucion
function promedio(listaDeNumeros) {
return sumatoria(listaDeNumeros) / longitud(listaDeNumeros);
}
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
for (let numero of listaDeNumeros) {
sumatoria = sumatoria + numero;
}
return sumatoria;
}
¡Pero nosotros no tenemos una lista de números sino de registros! ¿Y
entonces?
Completá la función ganancias que toma una lista de balances y devuelve una lista
que solo posea solo las ganancias de cada uno.
> ganancias([
{ mes: "enero", ganancia: 40 },
{ mes: "febrero", ganancia: 12 },
{ mes: "marzo", ganancia: 8}
])
[40, 12, 8]
Solución
function ganancias(balancesDeUnPeriodo) {
agregar(ganancias, [Link])
return ganancias;
/*function promedio(listaDeNumeros) {
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
return sumatoria;
}
*/
Solución
¡Muy bien! Ahora ya sabemos cómo filtrar una lista. En criollo, aprendimos
a obtener los elementos de una lista que cumplen una condición
determinada. En este caso obtuvimos una nueva lista con los balances
que presentaban una ganancia positiva.
Bilbioteca
function ganancias(balancesDeUnPeriodo) {
let ganancias = [];
for (let balance of balancesDeUnPeriodo) {
agregar(ganancias, [Link])
}
return ganancias;
}
/*function promedio(listaDeNumeros) {
return sumatoria(listaDeNumeros) / longitud(listaDeNumeros);
}
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
for (let numero of listaDeNumeros) {
sumatoria = sumatoria + numero;
}
return sumatoria;
}
*/
function balancesPositivos(balancesDeUnPeriodo) {
let balances = [];
for (let balance of balancesDeUnPeriodo) {
if ([Link] > 0) {
agregar(balances, balance);
}
}
return balances;
}
function promedio(listaDeNumeros) {
return sumatoria(listaDeNumeros) / longitud(listaDeNumeros);
}
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
for (let numero of listaDeNumeros) {
sumatoria = sumatoria + numero;
}
return sumatoria;
}
Solución
function gananciasDeBalancesPositivos(balancesDeUnPeriodo) {
return ganancias(balancesPositivos(balancesDeUnPeriodo)) ;
function promedioDeBalancesPositivos(balancesDeUnPeriodo) {
return promedio(gananciasDeBalancesPositivos(balancesDeUnPeriodo));
Usando esta nueva función, definí la función maximaGanancia que nos diga cuál es la
ganancia más alta entre los balances de un período de tiempo.
> maximaGanancia([
{ mes: "enero", ganancia: 87 },
{ mes: "febrero", ganancia: 12 },
{ mes: "marzo", ganancia: 8}
])
87
Biblioteca
function ganancias(balancesDeUnPeriodo) {
let ganancias = [];
for (let balance of balancesDeUnPeriodo) {
agregar(ganancias, [Link])
}
return ganancias;
}
/*function promedio(listaDeNumeros) {
return sumatoria(listaDeNumeros) / longitud(listaDeNumeros);
}
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
for (let numero of listaDeNumeros) {
sumatoria = sumatoria + numero;
}
return sumatoria;
}
*/
Solución
Si hay una función para calcular el máximo de una lista también hay una
para calcular el mínimo. ¿Te imaginás como se llama?
Definí la función minimaGananciaPositiva que nos diga cuál es la ganancia más baja de
todos los balances positivos.
> minimaGananciaPositiva([
{ mes: "enero", ganancia: -40 },
{ mes: "febrero", ganancia: 42 },
{ mes: "marzo", ganancia: 8},
{ mes: "abril", ganancia: -5}
])
8
Biblioteca
function ganancias(balancesDeUnPeriodo) {
let ganancias = [];
for (let balance of balancesDeUnPeriodo) {
agregar(ganancias, [Link])
}
return ganancias;
}
/*function promedio(listaDeNumeros) {
return sumatoria(listaDeNumeros) / longitud(listaDeNumeros);
}
function sumatoria(listaDeNumeros) {
let sumatoria = 0;
for (let numero of listaDeNumeros) {
sumatoria = sumatoria + numero;
}
return sumatoria;
}
*/
function balancesPositivos(balancesDeUnPeriodo) {
let balances = [];
for (let balance of balancesDeUnPeriodo) {
if ([Link] > 0) {
agregar(balances, balance);
}
}
return balances;
}
function gananciasDeBalancesPositivos(balancesDeUnPeriodo) {
return ganancias(balancesPositivos(balancesDeUnPeriodo)) ;
}
function promedioDeBalancesPositivos(balancesDeUnPeriodo) {
return promedio(gananciasDeBalancesPositivos(balancesDeUnPeriodo));
}
Solución
function minimaGananciaPositiva(balance) {
return minimo(gananciasDeBalancesPositivos(balance));
meses, la cual dada una lista con registros devuelve una lista de
meses ;
afortunados, que filtra aquellos registros que tuvieron una ganancia
mayor a $1000 ;
mesesAfortunados, devuelve aquellos meses que fueron afortunados.
> meses([
{ mes: "enero", ganancia: 870 },
{ mes: "febrero", ganancia: 1000 },
{ mes: "marzo", ganancia: 1020 },
{ mes: "abril", ganancia: 2300 },
{ mes: "mayo", ganancia: -10 }
])
["enero", "febrero", "marzo", "abril", "mayo"]
> afortunados([
{ mes: "enero", ganancia: 870 },
{ mes: "febrero", ganancia: 1000 },
{ mes: "marzo", ganancia: 1020 },
{ mes: "abril", ganancia: 2300 },
{ mes: "mayo", ganancia: -10 }
])
[ { mes: "marzo", ganancia: 1020 }, { mes: "abril", ganancia: 2300 }]
> mesesAfortunados([
{ mes: "enero", ganancia: 870 },
{ mes: "febrero", ganancia: 1000 },
{ mes: "marzo", ganancia: 1020 },
{ mes: "abril", ganancia: 2300 },
{ mes: "mayo", ganancia: -10 }
])
["marzo", "abril"]
Biblioteca
/**/
/**/
/**/
/**/
Solución
function meses(gananciasDeUnPeriodo){
let mes=[]
agregar(mes,[Link])
return mes;
}
function afortunados (gananciasDeUnPeriodo){
let afortunado=[]
if([Link]>1000){
agregar(afortunado,balance)
return afortunado
return meses(afortunados(gananciasDeUnPeriodo))
¡Terminaste Recorridos!
En esta última lección te reencontraste con el for...of y resolviste
problemas más complejos con él . Más especificamente creaste funciones
para filtrar y/o transformar los elementos de una lista.
Objetos y mensajes
La programación con objetos, a veces también llamada orientada
a objetos, es quizás el paradigma de programación más utilizado hoy en
día para construir software. Y parte de una idea muy simple: podemos
representar al mundo como un conjunto de
objetos que interactúan entre ellos.
Ahora bien: ¿qué es un objeto? Un objeto es .... ¡una cosa! (¡braaaaavo! ).
Bueno, bueno, no cualquier cosa, sino algo que es capaz de hacer alguna
tarea, la cual conocemos como responsabilidad del objeto.
Ejercicios
Pepita, además de ser un ave que come y vuela (como todo pájaro), es un
objeto, que vive en el mundo de los objetos, al cual conocemos
como ambiente.
¿No nos creés que Pepita está viva y es un objeto? Escribí en la consola Pepita y fijate
qué sucede. Cuando te convenzas, pasá al siguiente ejercicio.
¡Dame una pista!
> Pepita
=> Pepita
Ejercicio 3: Un mundo de objetos
Como vimos, Pepita es un objeto. Pero Pepita no está sola en este mundo.
¡Hay muchos más!
Por ejemplo, existe otra golondrina, llamada Norita, que también vive en
este ambiente.
Como ya te vendrás dando cuenta, en este paradigma bajo el cual
estamos trabajando absolutamente todo es un objeto: también los
números, las cadenas de texto (o strings) y los booleanos.
> Pepita
> Norita
> 87
> 'hola mundo'
> true
De todas formas tené cuidado. A Pepita y Norita las creamos por vos. Y los
números y booleanos vienen de regalo. Si probás con otra cosa, como por
ejemplo Felix, te va a tirar un error.
> Pepita
=> Pepita
> Norita
=> Norita
> 87
=> 87
> 'hola mundo'
=> "hola mundo"
> true
=> true
> Felix
uninitialized constant Felix (NameError)
>
Ejercicio 4: El derecho a la Identidad
Un aspecto muy importante de los objetos es que tienen identidad: cada
objeto sabe quién es y gracias a esto sabe también que es diferente de
los demás. Por ejemplo, Pepita sabe que ella es diferente de Norita, y
viceversa.
Pero esto no parece ser muy útil. ¿Qué cosas sabrá hacer una golondrina
como Pepita? ¿Sabrá, por ejemplo, cantar!?
> [Link]!
> [Link]!
=> "pri pri pri"
>
Ejercicio 6: Mensajes, segunda parte
Ehhhh, ¿qué acaba de pasar acá?
> [Link]!
> [Link]!
undefined method `bailar!' for Pepita:Module (NoMethodError)
>
Ejercicio 7: No entendí...
¡Buu, Pepita no sabía bailar!
Descubramos qué otras cosas sabe hacer Pepita. Probá enviarle los siguientes
mensajes y fijate cuáles entiende y cuales no ¡y anotalos! Este conocimiento nos
servirá en breve.
> [Link]!
> [Link]
> Pepita.comer_lombriz!
> Pepita.volar_en_circulos!
> Pepita.se_la_banca?
> [Link]!
undefined method `pasear!' for Pepita:Module (NoMethodError)
> [Link]
=> 100
> Pepita.comer_lombriz!
=> nil
> Pepita.volar_en_circulos!
=> nil
> Pepita.se_la_banca?
undefined method `se_la_banca?' for Pepita:Module (NoMethodError)
>
Ejercicio 8: Un poco de sintaxis
¡Pausa! Analicemos la sintaxis del envío de mensajes:
> energia
> Pepita energia
> Pepita..energia
¡Un momento! ¿Por qué algunos mensajes terminan en ! y otros no? Enviá
nuevamente esos mensajes. Fijate qué devuelve cada uno (lo que está a la derecha
del =>) y tratá de descubrir el patrón.
¡Dame una pista!
> [Link]
=> 100
> [Link]!
=> "pri pri pri"
> Pepita.comer_lombriz!
=> nil
> Pepita.volar_en_circulos!
=> nil
>
Ejercicio 10: Hacer versus Devolver
Cuando se envía un mensaje a un objeto, y este lo entiende, puede
reaccionar de dos formas diferentes:
Podría producir un efecto, es decir hacer algo. Por ejemplo, el
mensaje cantar! reproduce el sonido del canto de Pepita.
O también podría devolver otro objeto. Por ejemplo el
mensaje energia devuelve siempre un número.
Como convención, a los mensajes con efecto (es decir, que hacen algo)
les pondremos un signo de exclamación ! al final.
Solución
# Escribí acá los mensajes que quieras mandarle a Pepita, uno debajo del otro. [Link]
Pepita.comer_lombriz! Pepita.comer_lombriz! Pepita.volar_en_circulos!
Pepita.comer_lombriz! [Link]
¿Pero podría haber más de un objeto que entienda los mismos mensajes?
A Pepita ya la conocemos bien: canta, come, etc. Su amiga Norita, por otro lado, no
aprendió nunca a decirnos su energía. Y Mercedes es una reconocida cantora.
Usando la consola, averiguá cuál es la interfaz de cada una de ellas, y completá el
listado de mensajes que cada una entiende en el editor.
¡Dame una pista!
Solucion
interfaz_pepita = %w(
energia
cantar!
comer_lombriz!
volar_en_circulos!
interfaz_norita = %w(
cantar!
comer_lombriz!
volar_en_circulos!
interfaz_mercedes = %w(
cantar!
¡Así es! Puede haber más de un objeto que entienda el mismo mensaje.
Notá que sin embargo no todos los objetos están obligados a reaccionar
de igual forma ante el mismo mensaje:
[Link]!
=> "pri pri pri"
[Link]!
=> "priiiip priiiip"
[Link]!
=> "♪ una voz antigua de viento y de sal ♫"
Esto significa que dos o más objetos pueden entender un mismo mensaje,
pero pueden comportarse de formas diferentes. Ya hablaremos más de
esto en próximas lecciones.
interfaz_compartida_entre_mercedes_y_norita = %w(
cantar!
interfaz_compartida_entre_pepita_y_norita = %w(
cantar!
comer_lombriz!
volar_en_circulos!
interfaz_compartida_entre_todas = %w(
cantar!
Pepita.comer_alpiste! 40
> Pepita.volar_hacia!(Iruya)
=> nil
> Pepita.comer_alpiste!(39)
=> nil
> Pepita.comer_alpiste!(6, Norita)
wrong number of arguments (given 2, expected 1) (ArgumentError)
>
Ejercicio 15: Más argumentos
Como ves, si enviás un mensaje con una cantidad incorrecta de
argumentos...
Veamos si va quedando claro: escribí un programa que haga que Pepita coma 500
gramos de alpiste, vuele a Iruya, y finalmente vuelva a Obera.
Solución
Pepita.comer_alpiste!(500)
Pepita.volar_hacia!(Iruya)
Pepita.volar_hacia!(Obera)
¡Muy bien! Tu solución pasó todas las pruebas
¡Perfecto!
el objeto receptor es 2;
el mensaje es +;
el argumento es 3.
> 5.+ 6
> 3.< 27
> Pepita.== Norita
> 5.+(6)
=> 11
> 3.<(27)
=> true
> Pepita.==(Norita)
=> false
>
Ejercicio 17: Recapitulando
En un mundo de objetos, todo lo que tenemos son objetos y mensajes. A
estos últimos, podemos distinguirlos según la forma en que se escriben:
Vamos a enviar algunos mensajes para terminar de cerrar la idea. Te toca escribir
un programa que haga que Pepita:
Este programa tiene que andar sin importar con cuanta energía arranque Pepita.
¡Dame una pista!
Solucion
Pepita.comer_alpiste!(90)
Pepita.volar_hacia!(Iruya)
Pepita.comer_alpiste!([Link] / 10)
Pero aún queda mucho más por aprender. ¡Te esperamos en la próxima
lección!
Objetos y mensajes
La programación con objetos, a veces también llamada orientada
a objetos, es quizás el paradigma de programación más utilizado hoy en
día para construir software. Y parte de una idea muy simple: podemos
representar al mundo como un conjunto de
objetos que interactúan entre ellos.
Ejercicios
Pero aún queda mucho más por aprender. ¡Te esperamos en la próxima
lección!
En la lección anterior, creamos por vos todos los objetos. Peeeero esto no
siempre será así: en general, programar con objetos se trata también de
crearlos (es decir, traerlos al mundo) y decirles cómo se deben comportar.
Ejercicios
1. Creando a Pepita
2. Pepita, ¿me entendés?
3. Los mejores, los únicos, los métodos en objetos
4. Perdiendo energía
5. Atributos
6. Conociendo el país
7. Leyendo el estado
8. Cuestión de estado
9. ¿Dónde estás?
10. Volando alto
11. Delegar es bueno
12. ¿Es mi responsabilidad?
module Norita
end
module Pepita
end
module Pepita
end
Consola
> [Link]
undefined method `energia' for Pepita:Module (NoMethodError)
> Pepita.comer_lombriz!
undefined method `comer_lombriz!' for Pepita:Module (NoMethodError)
> Pepita.volar_en_circulos!
undefined method `volar_en_circulos!' for Pepita:Module
(NoMethodError)
>
Ejercicio 3: Los mejores, los únicos, los métodos en objetos
¿Otra vez undefined method? ¿Y ahora qué falta?
module Pepita
def [Link]!
end
end
Todos los métodos comienzan con def y terminan con end. Si nos
falta alguna de estos dos la computadora no va a entender nuestra
solución.
Todos los métodos que pertenezcan al mismo objeto van dentro
del mismo module.
Agregale a la definición de Pepita los métodos necesarios para que pueda responder
a los mensajes cantar!, comer_lombriz! y volar_en_circulos!.
Solución
module Pepita
def [Link]!
end
def self.comer_lombriz!
end
def self.volar_en_circulos!
end
end
Perfecto, ahora Pepita entiende casi todos los mismos mensajes que en la
lección anterior. Pero, ¿hacen lo mismo?
Ahora bien, los métodos que definiste recién no eran muy interesantes: se
trataba de métodos vacíos que evitaban que el programa se rompiera,
pero no hacían nada. En realidad, Pepita tiene energía y los diferentes
mensajes que entiende deberían modificarla.
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia = @energia - 10
end
end
Una vez más, ya definimos a Pepita por vos. Probá, en orden, las siguientes
consultas:
> Pepita.volar_en_circulos!
> Pepita.volar_en_circulos!
> [Link]
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia = @energia - 10
end
end
Sabiendo esto:
solución
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia-=10
end
def self.comer_lombriz!
@energia+=20
end
end
Solo tenés que poner uno debajo del otro de la siguiente forma:
def self.comprar_libro!
@plata -= 300
@libros += 1
end
Biblioteca
module Iruya
end
module Obera
end
module GralLasHeras
end
module Calamuchita
end
module Ushuaia
end
Solucion:
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_lombriz!
@energia += 20
end
@ciudad = Iruya
def self.volar_hacia!(destino)
@ciudad = destino
@energia -=100
end
end
¡Muy bien! Tu solución pasó todas las pruebas
> [Link]
undefined method `energia' for Pepita:Module (NoMethodError)
module Pepita
#...atributos y métodos anteriores...
def energia
@energia
end
end
Ya agregamos el método energia por vos. Probá en la consola ahora las siguientes
consultas:
> [Link]
> [Link] = 120
> energia
module Pepita
@energia = 100
@ciudad = Obera
#...etc...
end
Lo que podemos observar es que su estado está conformado
por ciudad y energia, dado que son sus atributos.
module Obera
#...más cosas que ahora no interesan...
end
module Pepita
@energia = 100
@ciudad = Obera
module Kiano1100
#...más cosas que ahora no interesan...
end
module RolamotoC115
#...más cosas que ahora no interesan...
end
module Enrique
@celular = Kiano1100
@dinero_en_billetera = 13
@frase_favorita = 'la juventud está perdida'
end
Solucion
estado_pepita = %w(
energia
ciudad
estado_kiano1100 = %w(
)
estado_rolamotoC115 = %w(
estado_enrique = %w(
celular
dinero_en_billetera
frase_favorita
module Pepita
@energia = 100
@ciudad = Obera
def [Link]
@energia
end
def [Link]!
end
def self.comer_lombriz!
@energia += 20
end
def self.volar_en_circulos!
@energia -= 10
end
def self.volar_hacia!(destino)
@energia -= 100
@ciudad = destino
end
def [Link]
@ciudad
end
end
Aunque en el mapa real no sea así, imaginaremos que las ciudades están
ubicadas en línea recta, para facilitar los cálculos:
Por ejemplo, si Pepita está en Obera y quiere volar a Iruya debe recorrer 670
kilómetros, por lo que perderá 335 unidades de energía.
> [Link]
=> 17
> (-17).abs
=> 17
Sabiendo esto:
Para que el ejemplo tenga sentido, vamos a hacer que Pepita arranque con
la energía en 1000.
Solucion
module BuenosAires
def [Link]
end
end
module Obera
def [Link]
1040
end
end
module Iruya
def [Link]
1710
end
end
module Pepita
@energia = 1000
@ciudad = Obera
def [Link]
@energia
end
def [Link]
@ciudad
end
def [Link]!
'pri pri pri'
end
def self.comer_lombriz!
@energia += 20
end
def self.volar_en_circulos!
@energia -= 10
end
def self.volar_hacia!(destino)
@ciudad = destino
end
end
¡Buen trabajo!
module Pepita
# ...etc...
def self.volar_hacia!(destino)
@energia -= (@[Link] - [Link]).abs / 2
@ciudad = destino
end
end
module Pepita
# ...etc...
def self.volar_hacia!(destino)
self.gastar_energia! destino #¡Ojo! No hicimos Pepita.gastar_energia!(destino)
@ciudad = destino
end
def self.gastar_energia!(destino)
@energia -= (@[Link] - [Link]).abs / 2
end
end
module Obera
def [Link]
1040
end
end
module Iruya
def [Link]
1710
end
end
module BuenosAires
def [Link]
0
end
end
Solucion
module Pepita
@energia = 1000
@ciudad = Obera
def [Link]
@energia
end
def [Link]
@ciudad
end
def [Link]!
end
def self.comer_lombriz!
@energia += 20
end
def self.volar_en_circulos!
@energia -= 10
end
def self.volar_hacia!(destino)
self.gastar_energia!(destino)
@ciudad = destino
end
def self.distancia_a(destino)
(@[Link] - [Link]).abs
end
def self.gastar_energia!(destino)
@energia -= distancia_a(destino) / 2
end
end
Dicho de otra manera, ¿es necesario contar con una golondrina para
poder calcular la distancia entre dos lugares? ¿Cual es el objeto más
pequeño que podría saber hacer esto?
¿Lo pensaste? La respuesta es simple: ¡la misma ciudad! Por
ejemplo, BuenosAires podría entender un mensaje distancia_a, que tome otra
ciudad y devuelva la distancia entre ésta y sí misma.
Modificá la solución del ejercicio anterior para que sean las ciudades las que
calculan las distancias. Pensá que no solo Obera debe tener este método, sino
también BuenosAires e Iruya, para cuando tenga que volver.
Solucion
module Obera
def [Link]
1040
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Iruya
def [Link]
1710
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module BuenosAires
def [Link]
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Pepita
@energia = 1000
@ciudad = Obera
def [Link]
@energia
end
def [Link]
@ciudad
end
def [Link]!
end
def self.comer_lombriz!
@energia += 20
end
def self.volar_en_circulos!
@energia -= 10
end
def self.volar_hacia!(destino)
self.gastar_energia!(destino)
@ciudad = destino
end
def self.gastar_energia!(destino)
@energia -= @ciudad.distancia_a(destino) / 2
end
end
Polimorfismo y encapsulamiento
Ya que te vas familiarizando con este paradigma, aprovecharemos para
hacer algunas reflexiones sobre cómo los objetos interactúan entre sí.
Solucion
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
end
def [Link]?
[Link] >1000
end
end
Intentá respetarla cuando crees tus propios mensajes, acordate que uno
de los objetivos del código es comunicar nuestras ideas a otras
personas... y las convenciones, muchas veces, nos ayudan con esto.
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
def [Link]?
[Link] >1000
end
def self.hacer_lo_que_quiera!
if [Link]?
self.comer_alpiste!(10)
end
end
end
module Jardinero
def [Link]!(planta)
if planta.necesita_agua?
[Link] { [Link]! planta }
else
self.sacar_bichos! planta
end
end
end
Es un mensaje que entienden los números que sirve para ejecutar una
porción de código varias veces. En este caso regaríamos 3 veces la planta
recibida como argumento.
Ahora que conocimos la existencia de times y vimos cómo hacer else...
Modificá la solución para que si Pepita no está débil vuele en círculos 3 veces.
Solucion
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
end
def [Link]?
[Link] >1000
end
def self.hacer_lo_que_quiera!
if [Link]?
self.comer_alpiste!(10)
else
[Link] {self.volar_en_circulos!}
end
end
end
module Docente
def self.nota_conceptual(nota)
if nota > 8
"Sobresaliente"
else
if nota > 6
"Satisfactoria"
else
"No satisfactoria"
end
end
end
end
Ahora que vimos estas condiciones anidadas que poco tienen que ver con
el nido de Pepita , vamos a conocer el comportamiento definitivo de
Pepita cuando hace lo que quiere:
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
end
def [Link]?
[Link] >1000
end
def self.hacer_lo_que_quiera!
if [Link]?
self.comer_alpiste!(10)
elsif [Link]?
[Link] { self.volar_en_circulos! }
else
[Link] { self.volar_en_circulos! }
end
end
end
def self.nota_conceptual(nota)
if nota > 8
"Sobresaliente"
else
if nota > 6
"Satisfactoria"
else
"No satisfactoria"
end
end
end
Lo podemos escribir:
def self.nota_conceptual(nota)
if nota > 8
"Sobresaliente"
elsif nota > 6
"Satisfactoria"
else
"No satisfactoria"
end
end
Antes de seguir, ¿te animás a editar tu solución para que use elsif?
Definí a Pepo según las reglas anteriores. Te dejamos el código de Pepita para usar
como base, modificá y borrá las partes que no correspondan.
Biblioteca
module Obera
def [Link]
1040
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Iruya
def [Link]
1710
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module BuenosAires
def [Link]
0
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
[Link] < 100
end
def [Link]?
[Link] >1000
end
def self.hacer_lo_que_quiera!
if [Link]?
self.comer_alpiste!(10)
elsif [Link]?
[Link] { self.volar_en_circulos! }
else
[Link] { self.volar_en_circulos! }
end
end
end
Solucion
module Pepo
@energia = 1000
def [Link]
@energia
end
def self.comer_alpiste!(gramos)
@energia += gramos / 2
end
def self.volar_en_circulos!
@energia -= 15
else
@energia -= 5
end
end
def self.hacer_lo_que_quiera!
self.comer_alpiste!(120)
end
end
Biblioteca
module Obera
def [Link]
1040
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Iruya
def [Link]
1710
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module BuenosAires
def [Link]
0
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Pepita
@energia = 1000
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 10
end
def self.comer_alpiste!(gramos)
@energia += gramos * 15
end
def [Link]?
@energia < 100
end
def [Link]?
@energia > 1000
end
def self.hacer_lo_que_quiera!
if [Link]?
self.comer_alpiste!(10)
end
if [Link]?
[Link] { self.volar_en_circulos! }
end
end
end
Solucion
module Pachorra
def self.entrenar_ave!
[Link] {Pepita.volar_en_circulos!}
Pepita.comer_alpiste!(30)
[Link] {Pepita.volar_en_circulos!}
Pepita.hacer_lo_que_quiera!
end
end
¡Muy bien! Tu solución pasó todas las pruebas
Solucion
module Pachorra
def self.firmar_contrato!(ave)
@ave = ave
end
def self.entrenar_ave!
[Link] {@ave.volar_en_circulos!}
@ave.comer_alpiste!(30)
[Link] {@ave.volar_en_circulos!}
@ave.hacer_lo_que_quiera!
end
end
module Norita
@energia = 500
def self.volar_en_circulos!
@energia -= 30
end
def self.comer_alpiste!(gramos)
@energia -= gramos
end
end
> Pachorra.entrenar_ave!
undefined method `hacer_lo_que_quiera!' for Norita:Module (NoMethodError)
module Emilce
def self.entrenar_ave!
[Link] { @ave.volar_en_circulos! }
@ave.comer_alpiste! 8
end
end
Solucion
norita_puede_entrenar_con_pachorra = false
norita_puede_entrenar_con_emilce = true
pepita_puede_entrenar_con_pachorra = true
pepita_puede_entrenar_con_emilce = true
pepo_puede_entrenar_con_pachorra = true
pepo_puede_entrenar_con_emilce = true
Según las rutinas que definen, cada entrenador/a solo puede trabajar con
ciertas aves:
Dicho de otra manera, la rutina nos define cuál debe ser la interfaz que
debe respetar un objeto para poder ser utilizado.
Ejercicio 10: ¿¿Polimor-qué??
¿Qué pasa si dos objetos, como Pepita, Norita o Pepo son capaces de
responder a un mismo mensaje? Podemos intercambiar un objeto por
otro sin notar la diferencia, como experimentaste recién.
En nuestro caso:
¡Claro que sí! Podemos agregarle los mensajes que le faltan, en este
caso hacer_lo_que_quiera!.
¿Y qué hace Norita cuando le decimos que haga lo que quiera? Nada.
@energia = 500
def [Link]
@energia
end
def self.volar_en_circulos!
@energia -= 30
end
def self.comer_alpiste!(gramos)
@energia -= gramos
end
def self.hacer_lo_que_quiera!
end
end
[Link] = Pepita
module Emilce
def [Link]=(ave_nueva)
@ave = ave_nueva
end
def self.entrenar_ave!
[Link] { @ave.volar_en_circulos! }
@ave.comer_alpiste!(8)
end
end
¿Te animás a cambiar el código de Pachorra para que siga esta convención?
module Pachorra
def [Link]=(ave_nueva)
@ave = ave_nueva
end
def self.entrenar_ave!
[Link] { @ave.volar_en_circulos! }
@ave.comer_alpiste! 30
[Link] { @ave.volar_en_circulos! }
@ave.hacer_lo_que_quiera!
end
end
Los setters deben llevar el mismo nombre del atributo al que están
asociados, agregando un = al final.
Los getters usan exactamente el mismo nombre que el atributo del
cual devuelven el valor pero sin el @.
Aquellos getters que devuelven el valor de un atributo booleano
llevan ? al final.
module Obera
def [Link]
1040
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Iruya
def [Link]
1710
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module BuenosAires
def [Link]
0
end
def self.distancia_a(destino)
([Link] - [Link]).abs
end
end
module Pehuajo
end
module Malaquita
end
module Paris
end
module Manuelita
@energia = 100
@ciudad = Pehuajo
@mineral_preferido = Malaquita
@donde_va = Paris
def [Link]
@energia
end
def [Link]
@ciudad
end
def self.mineral_preferido=(mineral)
@mineral_preferido = mineral
end
def self.mineral_preferido
@mineral_preferido
end
def self.donde_va=(ciudad)
@donde_va = ciudad
end
end
Solucion
atributos = %w(
energia
ciudad
mineral_preferido
donde_va
atributos_con_getter = %w(
energia
ciudad
mineral_preferido
)
atributos_con_setter = %w(
mineral_preferido
donde_va
Si hacemos bien las cosas, quien use nuestros objetos sólo verá lo que
necesite para poder interactuar con ellos. A esta idea la conocemos
como encapsulamiento, y es esencial para la separación
de responsabilidades de la que veníamos hablando.
Solucion
module Inodoro
@cafeina_en_sangre = 90
def self.cafeina_en_sangre
@cafeina_en_sangre
end
def [Link]
@compinche
end
def [Link]=(nuevo_compinche)
@compinche = nuevo_compinche
end
end
module Eulogia
@enojada = false
def [Link]?
@enojada
end
end
module Mendieta
@ganas_de_hablar = 5
def self.ganas_de_hablar
@ganas_de_hablar
end
def self.ganas_de_hablar=(ganas)
@ganas_de_hablar = ganas
end
end
@cafeina_en_sangre = 90
def self.cafeina_en_sangre
@cafeina_en_sangre
end
def [Link]
@compinche
end
def [Link]=(nuevo_compinche)
@compinche = nuevo_compinche
end
def self.tomar_mate!
@cafeina_en_sangre +=10
@compinche.recibir_mate!
end
end
module Eulogia
@enojada = false
def [Link]?
@enojada
end
def self.recibir_mate!
@enojada = true
end
end
module Mendieta
@ganas_de_hablar = 5
def self.ganas_de_hablar
@ganas_de_hablar
end
def self.ganas_de_hablar=(ganas)
@ganas_de_hablar = ganas
end
def self.recibir_mate!
@ganas_de_hablar = 0
end
end
Referencias
Hasta ahora venimos hablando mucho de objetos y mensajes. Pero
ocasionalmente se nos escapó una palabra: referencia. ¿Qué es? ¿Cómo se
relacionan las referencias con los objetos y los atributos?
Ejercicios
1. Variables
2. Las variables son referencias
3. Referencias implícitas
4. Múltiples referencias
5. Identidad, revisada
6. Equivalencia
7. Objetos bien conocidos
8. Atributos y parámetros
9. Lo 100to
10. Objetos compartidos
11. Para cerrar
Ejercicio 1: Variables
Hasta ahora, en objetos, un programa es simplemente una secuencia de
envíos de mensajes. Por ejemplo, éste es un programa que convierte en
mayúsculas al string "hola".
> "hola".upcase
=> "HOLA"
Sin embargo, podemos hacer algo más: declarar variables. Por ejemplo,
podemos declarar una variable saludo, inicializarla con "hola", enviarle
mensajes...
saludo_formal=saludo
¡Momento, momento!
¿Qué sucedió aquí? Hasta ahora habíamos visto que tenemos objetos y
mensajes, y sólo le podíamos enviar mensajes a los objetos,
como Pepita, 14, u "hola". ¿Le acabamos de enviar un mensaje a una
variable?
saludo = "hola"
...lo que estamos haciendo es crear una referencia saludo que apunta al
objeto "hola", que representamos mediante una flechita:
Y cuando tenemos...
[Link]
Veamos si se entiende hasta acá: creá una variable llamada despedida que apunte al
objeto "adiós", y luego enviale el mensaje size().
¡Dame una pista!
Solucion
despedida = "adiós"
[Link]()
¡Muy bien! Tu solución pasó todas las pruebas
¡Bien! Acabás de crear este ambiente, en criollo, el lugar donde viven los
objetos con los cuales podemos
interactuar:
Sucede que hay muchos tipos de referencias, y una de ellas son las
variables del programa. Pero, ¿no podíamos enviarles mensajes
"directamente" al objeto? Por ejemplo, ¿dónde están las referencias en
estos casos?:
"ni hao".upcase
^
+-- Acá hay una referencia implícita al objeto "ni hao"
[Link]
^
+-- Y acá, otra referencia implícita a "HOLA"
. Las referencias explícitas son las que vimos hasta ahora. Por ejemplo:
otro_saludo = "buen día" # se crea la variable otro_saludo que referencia al objeto "buen día"
despedida = otro_saludo # se crea la variable despedida que, por asignarle la referencia otro_saludo, apunt
a al mismo objeto
> "buen día".equal? "buen día"
=> false
> [Link]? "buen día"
=> false
En ambos casos el resultado fue false, dado que aquellos strings son
objetos distintos, a pesar de que tengan los mismos caracteres. Cada vez
que escribimos un string estamos creando un nuevo objeto. Sin embargo:
persona = "Graciela"
hija_de_hector = "Graciela"
hermana_de_tito = persona
hija_de_elena = "Gracielita"
hermana_de_ana = hermana_de_tito
mama_de_gustavo = "hermana_de_ana"
tia_de_gonzalo = hija_de_hector
jercicio 6: Equivalencia
Entonces, ¿qué pasa si lo que quiero es comparar los objetos no por su
identidad, sino por que representen la misma cosa?
... las 3 referencias distintas apuntan a objetos equivalentes entre sí, pero
no idénticos.
module Fito
@felicidad = 100
def [Link]!(calorias)
@felicidad += calorias * 0.001
end
def [Link]
@felicidad
end
end
A objetos como Fito se los conocen como objetos bien conocidos: cuando
los definimos no sólo describimos su comportamiento
(comer!(calorias) y felicidad) y estado (@felicidad), sino que además les damos
un nombre o etiqueta a través de la cual podemos conocerlos. ¿Te suena?
module AbuelaClotilde
def self.alimentar_nieto!
[Link]!(2000)
[Link]!(1000)
end
end
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia -= 10
end
def [Link]=(una_ciudad)
@ciudad = una_ciudad
end
def [Link]
@ciudad
end
end
Escribí un programa que defina la ciudad de Pepita de forma que apunte a Iruya. Y
pensá: ¿cuántas referencias a Iruya hay en este programa?
Biblioteca
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia -= 10
end
def [Link]=(una_ciudad)
@ciudad = una_ciudad
end
def [Link]
@ciudad
end
end
module Iruya
end
Solucion
[Link] = Iruya
¿Lo pensaste?
Ejercicio 9: Lo 100to
Miremos este método con más detenimiento:
def self.volar_en_circulos!
@energia = @energia - 10
end
Lo que estamos haciendo es cambiar la energía de Pepita: pasa de su valor
actual, @energia, a ese valor menos 10. Por ejemplo, pasa de 100 a 90.
¿Significa esto que el 100 se transforma en un 90 ?
¡Veamos si se entiende!
En este código...
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia -= 10
end
def [Link]=(una_ciudad)
@ciudad = una_ciudad
end
end
module Iruya
end
...si bien:
module Fito
def [Link]=(un_amigo)
@amigo = un_amigo
end
def self.es_feliz_como_su_amigo?
@[Link] > 105
end
end
[Link]=Juli
[Link]=Juli
[Link] {AbueloGervasio.alimentar_nieto!}
[Link] = Juli
[Link] = Juli
[Link] { AbueloGervasio.alimentar_nieto! }
Cada vez que Jor picantea el plato del día le agrega 5 ajíes.
¡Hoy hay Fideos! Decimos que los Fideos están picantes si el plato
tiene más de 2 ajíes. Inicialmente no tiene ajíes.
Cuando descartamos la salsa de los Fideos dejan de tener ajíes.
Luchi necesita saber qué plato suavizar y cuántos ajíes sacarle para
hacerlo. Si el plato tiene más de 10 ajíes, directamente descarta la
salsa para poder usarla en otra comida.
Solucion
module Jor
@plato_del_dia= plato_de_hoy
end
def [Link]!
@plato_del_dia.agregar_ajies! 5
end
end
module Fideos
def [Link]
@ajies
end
@ajies = 0
def [Link]?
[Link] > 2
end
@ajies += cantidad
end
@ajies -= cantidad
end
def self.descartar_la_salsa!
@ajies = 0
end
end
module Luchi
if plato_del_dia.ajies > 10
plato_del_dia.descartar_la_salsa!
elsif plato_del_dia.picantes?
plato_del_dia.quitar_ajies! (cantidad)
end
end
end
¡Terminaste Referencias!
Repasemos lo recién visto: en un ambiente hay muchos objetos, pero en
realidad no interactuamos con ellos directamente, sino a través de
referencias, que son nombres o etiquetas que les damos a los objetos.
variables de un programa
variables locales de un método
parámetros de un método
atributos de un objeto
y el nombre global de un objeto bien conocido.
Colecciones
Ya lo sabemos: un objeto es una "cosa" o ente que cumple ciertas
responsabilidades. Pero... ¿qué sucede cuando queremos tratar no una
sola cosa, sino a varias al mismo tiempo?
Ejercicios
1. Entrando en Calor
2. Creando una lista
3. Algunos mensajes básicos
4. Set o no set
5. Mejorando la Juegoteca
6. ¿Bloques? ¿Eso se come?
7. Bloques con parámetros
8. Filtrando quienes cumplen
9. El que busca encuentra
10. ¿Alguno cumple? ¿Todos cumplen?
11. El viejo y querido map
12. ¿Cuántos cumplen? ¿Cuánto suman?
13. Jugando a todo
module CarlosDuty
@cantidad_logros=0
def [Link]
dificultad=30-@cantidad_logros*0.5
end
def [Link]!(un_tiempo)
if (un_tiempo>2)
@cantidad_logros+=1
end
end
def [Link]?
true
end
end
module TimbaElLeon
@dificultad=25
def [Link]!(un_tiempo)
@dificultad+=un_tiempo
end
def [Link]
@dificultad
end
def [Link]?
false
end
end
module Metroide
@nivel_espacial=3
def [Link]!(un_tiempo)
@nivel_espacial+=1
end
def [Link]?
@nivel_espacial>5
end
def [Link]
100
end
end
Es importante que notes que todos estos objetos responden a los mismos
mensajes: dificultad, violento? y jugar!(un_tiempo). Como aprendiste con las
golondrinas, nuestros videojuegos son polimórficos para ese conjunto
de mensajes.
[2, 3, 3, 9]
Veamos si se entiende: definí un objeto Juegoteca que tenga un atributo juegos con su
correspondiente getter. La Juegoteca tiene que tener en primer lugar el
juego CarlosDuty, luego TimbaElLeon y por último Metroide.
Biblioteca
module CarlosDuty
# El estado y la interfaz de este objeto están ocultos pero satisfacen lo requerido en el ejercicio anterior.
end
module TimbaElLeon
# El estado y la interfaz de este objeto están ocultos pero satisfacen lo requerido en el ejercicio anterior.
end
module Metroide
# El estado y la interfaz de este objeto están ocultos pero satisfacen lo requerido en el ejercicio anterior.
end
Solución
1
module Juegoteca
2
@juegos = [CarlosDuty, TimbaElLeon, Metroide]
3
def [Link]
4
@juegos
5
end
6
end
Enviar
numeros_de_la_suerte.include? 6
# Devuelve true, porque contiene al 6...
numeros_de_la_suerte.include? 8
# ...devuelve false, porque no contiene al 8.
numeros_de_la_suerte.size
# Devuelve 3, porque contiene al 6, 42 y 9
Biblioteca
> numeros_de_la_suerte
=> [6, 42, 9]
> numeros_de_la_suerte.delete 42
=> 42
> numeros_de_la_suerte.push 12
=> [6, 9, 12]
> numeros_de_la_suerte.size
=> 3
> numeros_de_la_suerte.include?
wrong number of arguments (given 0, expected 1) (ArgumentError)
>
Ejercicio 4: Set o no set
Hasta ahora sólo vimos un tipo de colección: las listas. ¡Pero hay más!
Otro tipo muy común de colecciones son los sets (conjuntos), los cuales
tienen algunas diferencias con las listas:
Algo importante a tener en cuenta es que tanto las listas como los sets
tienen mensajes en común. Dicho de otro modo, son polimórficos para
algunos mensajes. Por ejemplo: push, delete, include? y size.
Nuestra Juegoteca maneja puntos. Agregá el código necesario para que entienda los
siguientes mensajes:
module Juegoteca
@puntos = 0
def [Link]
@juegos
end
def [Link]
@puntos
end
def self.adquirir_juego!(un_juego)
@[Link] (un_juego)
@puntos+=150
end
def self.borrar_juego!(un_juego)
@[Link](un_juego)
end
def [Link]?
end
def self.juego_recomendable?(un_juego)
end
end
Hay una diferencia notable entre los primeros dos mensajes (push y delete)
y los otros dos (include? y size):
un_numero = 7
incrementador = proc { un_numero = un_numero + 1 }
otro_numero = 5
duplicador = proc { otro_numero = otro_numero * 2 }.call
¿Cuánto vale un_numero luego de las primeras dos líneas? Tené en cuenta
que la secuencia de envío de mensajes en el bloque del primer ejemplo
está sin ejecutar. En cambio, en el ejmplo de otro_numero estamos
enviando el mensaje call. Por lo tanto:
un_numero = 3
sumar_a_otros_dos = proc { |un_sumando, otro_sumando| un_numero = un_numero + un_sumando + otr
o_sumando }
> sumar_a_otros_dos.call(1,2)
=> 6
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
Solucion
Quizá estés pensando, ¿qué tiene que ver todo esto con las
colecciones? ¡Paciencia! En el siguiente ejercicio veremos cómo combinar
colecciones y bloques para poder enviar mensajes más complejos.
algunos_numeros = [1, 2, 3, 4, 5]
mayores_a_3 = algunos_numeros.select { |un_numero| un_numero > 3 }
¿Y cuándo se aplica ese bloque que recibe el select? ¡El select es quien
decide! La colección va a aplicarlo con cada uno de los objetos (un_numero)
cuando corresponda durante el seleccionado (o filtrado) de elementos.
> mayores_a_3
=> [4, 5]
module CarlosDuty
@cantidad_logros = 0
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module Metroide
@nivel_espacial = 3
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
Solucion
¡Muy bien! Tu solución pasó todas las pruebas
algunos_numeros = [1, 2, 3, 4, 5]
uno_mayor_a_3 = algunos_numeros.find { |un_numero| un_numero > 3 }
> uno_mayor_a_3
=> 4
module CarlosDuty
@cantidad_logros = 0
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module Metroide
@nivel_espacial = 3
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
solución
module Juegoteca
def [Link]
@juegos
end
def self.juego_mas_dificil_que(una_dificultad)
end
end
Un dato curioso para tener en cuenta: ¡los mensajes find y detect hacen
exactamente lo mismo!
Siguiente Ejercicio: ¿Alguno cumple? ¿Todos cumplen?
Biblioteca
module CarlosDuty
@cantidad_logros = 0
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module Metroide
@nivel_espacial = 3
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
Solucion
module Juegoteca
def [Link]
@juegos
end
def self.mucha_violencia?
end
def self.muy_dificil?
end
end
¡Muy bien! Tu solución pasó todas las pruebas
Al igual que el resto de los mensajes que vimos hasta ahora, map no
modifica la colección original ni sus elementos, sino que devuelve
una nueva colección.
module CarlosDuty
@cantidad_logros = 0
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module Metroide
@nivel_espacial = 3
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
Solucion
module Juegoteca
def [Link]
@juegos
end
def self.juegos_violentos
end
def self.dificultad_violenta
end
end
module Juegoteca
def [Link]
@juegos
end
def self.juegos_violentos
end
def self.promedio_de_violencia
[Link]? }
end
end
golondrinas
.select { |una_golondrina| una_golondrina.energia > 100 }
.each { |una_golondrina| una_golondrina.volar_hacia! Iruya }
Definí el método jugar_a_todo! en la Juegoteca, que haga jugar a cada uno de los
juegos durante 5 horas. Recordá que los juegos entienden jugar!(un_tiempo).
Biblioteca
module CarlosDuty
@cantidad_logros = 0
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module TimbaElLeon
@dificultad = 25
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
module Metroide
@nivel_espacial = 3
def [Link]?
# ...
end
def [Link]
# ...
end
def [Link]!(un_tiempo)
# ...
end
end
Solucion
module Juegoteca
def [Link]
@juegos
end
def self.jugar_a_todo!
end
end
¡Terminaste Colecciones!
¡Felicitaciones! A lo largo de esta guía aprendiste:
Clases e Instancias
Nuestros ambientes se están volviendo más interesantes, con más objetos
y comportamientos más complejos. Sin embargo, al seguir agregando
objetos podemos perder organización y comenzar a repetir lógica.
Ejercicios
1. Zombi caminante
2. Atacando un zombi
3. Otro zombi caminante
4. ¡¿Vivos?!
5. Clases
6. Instancias
7. Al menos tenemos salud
8. Inicializando instancias
9. Ahora sí: invasión
10. Al menos tenemos (menos) salud
11. Súper zombi
12. Ejercitando
13. Aliados
¡Comenzá esta lección!
module Bouba
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
end
end
¡Muy bien! Tu solución pasó todas las pruebas
Además cuenta con un nivel de energia, que inicia en 1000, pero todavía no
haremos nada con él. Definí un método getter para este atributo.
module Juliana
@energia = 1000
def [Link]
@energia
end
zombi.recibir_danio!(puntos)
end
end
Ahora que Juliana sabe atacar!, veamos contra quién más se puede
enfrentar...
module Bouba
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
end
end
module Kiki
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
end
end
Ejercicio 4: ¡¿Vivos?!
¿Acaso Bouba y Kiki pensaron que eran invencibles? Cuando su salud llega a
0, su vida termina... nuevamente. ¡Son zombis, después de todo!
Definí el método sin_vida? que nos dice si la salud de Bouba o Kiki es cero.
Solucion
module Bouba
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
end
def self.sin_vida?
@salud == 0
end
end
module Kiki
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
end
def self.sin_vida?
@salud == 0
end
end
¡Muy bien! Tu solución pasó todas las pruebas
Ejercicio 5: Clases
Si tenemos más de un objeto que se comporta exactamente de la misma
forma, lo que podemos hacer es generalizar ese comportamiento
definiendo una clase. Por ejemplo, si tenemos dos celulares con el mismo
saldo y ambos tienen las mismas
funcionalidades, realizar_llamada! y cargar_saldo! :
module CelularDeMaría
@saldo = 25
def self.realizar_llamada!
@saldo -= 5
end
def self.cargar_saldo!(pesos)
@saldo += pesos
end
end
module CelularDeLucrecia
@saldo = 25
def self.realizar_llamada!
@saldo -= 5
end
def self.cargar_saldo!(pesos)
@saldo += pesos
end
end
class Celular
def initialize
@saldo = 25
end
def realizar_llamada!
@saldo -= 5
end
def cargar_saldo!(pesos)
@saldo += pesos
end
end
module Bouba
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
@salud = [(@salud - puntos*2), 0].max
end
def self.sin_vida?
@salud == 0
end
end
module Kiki
@salud = 100
def self.sabe_correr?
false
end
def [Link]
"¡agrrrg!"
end
def [Link]
@salud
end
def self.recibir_danio!(puntos)
@salud = [(@salud - puntos*2), 0].max
end
def self.sin_vida?
@salud == 0
end
end
Solucion
class Zombi
def initialize
@salud = 100
end
def sabe_correr?
false
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
end
def sin_vida?
@salud == 0
end
end
¡Muy bien! Tu solución pasó todas las pruebas
Las clases sólo nos sirven para generalizar objetos que tengan el mismo
comportamiento: mismos métodos y mismos atributos. En nuestro
caso, el código de ambos celulares y de ambos zombis es el mismo, por
eso pudimos generalizarlo.
Ejercicio 6: Instancias
Como habrás visto, definir una clase es muy similar a definir un objeto.
Tiene métodos, atributos... ¿cuál es su particularidad, entonces? La clase
es un objeto que nos sirve como molde para crear nuevos objetos.
celular_de_maría = [Link]
celular_de_lucrecia = [Link]
Celular, al igual que todas las clases, entiende el mensaje new, que crea una
nueva instancia de esa clase.
¡Ahora te toca a vos! Definí bouba y kiki como instancias de la clase Zombi.
Biblioteca
class Zombi
def initialize
@salud = 100
end
def sabe_correr?
false
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
@salud = [(@salud - puntos*2), 0].max
end
def sin_vida?
@salud == 0
end
end
Solucion
bouba = [Link]
kiki = [Link]
class Zombi
def initialize
@salud = 100
end
def salud
@salud
end
end
Pero ahora que @salud aparece en la clase Zombi, ¿eso significa que
comparten el atributo? Si Juliana ataca a bouba, ¿disminuirá también la
salud de kiki?
¡Averigualo! Hacé que Juliana ataque a cada zombi con distintos puntos de daño y
luego consultá la salud de ambos.
Biblioteca
module Juliana
def [Link]!(zombi, puntos)
zombi.recibir_danio!(puntos)
end
end
class Zombi
def initialize
@salud = 100
end
def salud
@salud
end
def sabe_correr?
false
end
def sin_vida?
@salud == 0
end
def recibir_danio!(puntos)
@salud = [@salud - puntos * 2, 0].max
end
def gritar
"agrrrg!"
end
end
bouba = [Link]
kiki = [Link]
Consola
Pero nos quedó un método misterioso por aclarar: initialize. Al trabajar con
clases tenemos que inicializar los atributos en algún lugar. ¡Para eso es
que existe ese método!
module Juliana
@energia = 1000
def [Link]
@energia
end
def [Link]!(zombi, puntos)
zombi.recibir_danio!(puntos)
end
end
Solucion
class Sobreviviente
def initialize
@energia =1000
end
def energia
@energia
end
zombi.recibir_danio!(puntos)
end
end
juliana = [Link]
anastasia = [Link]
Vivero.agregar_planta! [Link]
Vivero.agregar_planta! [Link]
Vivero.agregar_planta! [Link]
...y el Vivero las guarda en una colección @plantas, luego las podemos regar
a todas...
def regar_todas!
@[Link] { |planta| [Link]! }
end
...a pesar de que no tengamos una referencia explícita para cada planta.
¡Puede ocurrir que no necesitemos darle un nombre a cada una!
class Zombi
def initialize
@salud = 100
end
def gritar
# ...
# La lógica de este método está oculta pero satisface lo requerido anteriormente.
end
def salud
# ...
# La lógica de este método está oculta pero satisface lo requerido anteriormente.
end
def sabe_correr?
# ...
# La lógica de este método está oculta pero satisface lo requerido anteriormente.
end
def recibir_danio!(puntos_danio)
# ...
# La lógica de este método está oculta pero satisface lo requerido anteriormente.
end
def sin_vida?
# ...
# La lógica de este método está oculta pero satisface lo requerido anteriormente.
end
end
Solucion
class Sobreviviente
def initialize
@energia =1000
end
def energia
@energia
end
zombi.recibir_danio!(puntos)
end
def ataque_masivo!(zombis)
end
end
juliana = [Link]
anastasia = [Link]
class Zombi
def initialize
@salud = 100
end
def sabe_correr?
false
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
end
def sin_vida?
@salud == 0
end
end
caminantes = []
[Link] { [Link]([Link]) }
Por lo tanto, los casos en los que un objeto puede conocer a otro son:
class Planta
def initialize(centimetros)
@altura = centimetros
end
def regar!
@altura += 2
end
end
Ahora podemos crear plantas cuyas alturas varíen utilizando una única
clase. Internamente, los parámetros que recibe new se pasan también
a initialize:
brote = [Link] 2
arbusto = [Link] 45
arbolito = [Link] 110
¡Ahora te toca a vos! Modificá la clase Zombi para que initialize pueda recibir la salud
inicial del mismo.
Solucion
class Zombi
@salud
def initialize(nivel_de_salud)
@salud = nivel_de_salud
end
def sabe_correr?
false
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
end
def sin_vida?
@salud == 0
end
end
class Zombi
@salud
def initialize(nivel_de_salud)
@salud = nivel_de_salud
end
def sabe_correr?
false
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
@salud = [(@salud - puntos*2), 0].max
end
def sin_vida?
@salud == 0
end
end
Solucion
class SuperZombi
def initialize(nivel_de_salud)
@salud = nivel_de_salud
end
def sabe_correr?
true
end
def gritar
"¡agrrrg!"
end
def salud
@salud
end
def recibir_danio!(puntos)
end
def sin_vida?
@salud == 0
end
def regenerarse!
@salud = 100
end
end
Sin embargo habrás notado que, aunque esos últimos dos métodos son
distintos, hay cuatro que son idénticos: salud, gritar, sin_vida?, y su
inicialización mediante initialize. ¡Hasta tienen un mismo atributo, @salud!
¿Acaso eso no significa que estamos repitiendo mucha lógica en ambas
clases?
¡Así es! Pero todavía no contamos con las herramientas necesarias para
solucionarlo.
def initialize
@energia = 1000
end
def energia
@energia
end
zombie.recibir_danio!(danio)
end
def ataque_masivo!(zombis)
@energia *= 0.5
end
def beber!
@energia *= 1.25
end
end
class Sobreviviente
def initialize
@energia = 1000
end
def energia
@energia
end
def ataque_masivo!(zombis)
[Link] { |zombi| atacar!(zombi, 15) }
@energia *= 0.5
end
def beber!
@energia *= 1.25
end
end
Solucion
class Aliado
def initialize
@energia = 500
end
def energia
@energia
end
zombi.recibir_danio!(puntos)
@energia *= 0.95
end
def ataque_masivo!(zombis)
@energia *= 0.5
end
def beber!
@energia *= 1.1
end
end
Ejercicios
Solucion
class Celular
def initialize
@bateria =100
end
def bateria
@bateria =80
end
end
def cargar_a_tope!
@bateria =100
end
end
¡Excelente!
Pero bien sabemos que no solo utilizamos celulares y que en los últimos
años las computadoras portatiles le ganaron terreno a las de escritorio...
Ejercicio 2: Notebook
¡Ahora es el turno de la Notebook!
La clase Notebook entiende los mismos mensajes que Celular y se comporta
parecido pero no exactamente igual. La diferencia está en que a la hora
de utilizar! una notebook, su @bateria disminuye en la cantidad de minutos
que la utilicemos.
class Celular
def initialize
@bateria =100
end
def bateria
@bateria =80
end
def utilizar! (minutos)
@bateria = @bateria - minutos/2
end
def cargar_a_tope!
@bateria =100
end
end
Solucion
class Notebook
def initialize
@bateria = 100
end
def utilizar!minutos
@bateria -= minutos
end
def cargar_a_tope!
@bateria = 100
end
end
¡Muy bien! Pero... las clases Celular y Notebook son demasiado parecidas,
¿no?
Más específicamente en los métodos initialize y cargar_a_tope! son iguales.
Ejercicio 3: Su superclase
Una forma de organizar las clases cuando programamos en objetos es
establecer una jerarquía. En nuestro caso podemos pensar
que Celular y Notebook se pueden englobar en algo más grande que las
incluya, la idea de Dispositivo.
class Ave
def volar!
@energia -= 20
end
end
El símbolo < significa "hereda de": por ejemplo, Condor hereda de Ave, que
está más arriba en la jerarquía. Otra manera de decirlo es que
cada Condor es un Ave.
La herencia nos permite que las subclases (Condor y Halcon) posean los
mismos métodos y atributos que la superclase Ave. Es decir, las instancias
de Condor y de Halcon van a saber volar! de la misma forma, pero cuando les
enviemos el mensaje dormir! cada una hará algo diferente.
class Dispositivo
def initialize
@bateria = 100
end
def bateria
@bateria
end
def cargar_a_tope!
@bateria = 100
end
end
def utilizar!(minutos)
@bateria -= minutos/2
end
end
def utilizar!(minutos)
@bateria -= minutos
end
end
¡Genial!
Para recapitular, cuando dos objetos repiten lógica, creamos una clase
con el comportamiento en común. En el caso que dos clases repitan
lógica deberíamos crear una nueva clase a la cual llamamos superclase. A
esta nueva clase llevaremos los métodos repetidos y haremos que las
clases originales hereden de ella. Estas subclases que heredan de la
superclase solo contendrán su comportamiento particular.
Sabemos que tanto los celulares como las notebooks están descargados
si tienen 20 o menos de batería.
Solucion
class Dispositivo
def initialize
@bateria = 100
end
def bateria
@bateria
end
def descargado?
@bateria <= 20
end
def cargar_a_tope!
@bateria = 100
end
end
class Notebook<Dispositivo
def utilizar!(minutos)
@bateria -= minutos
end
end
class Celular<Dispositivo
def utilizar!(minutos)
@bateria -= minutos/2
end
end
Biblioteca
class Dispositivo
def initialize
@bateria = 100
end
def bateria
@bateria
end
def descargado?
@bateria <= 20
end
def cargar_a_tope!
@bateria = 100
end
end
class Notebook<Dispositivo
def utilizar!(minutos)
@bateria -= minutos
end
end
class Celular<Dispositivo
def utilizar!(minutos)
@bateria -= minutos/2
end
end
un_celu = [Link]
=> #<Celular:0x00007fa2c5cadae0 @bateria=100>
> una_notebook = [Link]
=> #<Notebook:0x00007f618861dac8 @bateria=100>
> un_celu.descargado?
=> false
> un_celu.utilizar! 180
=> 10
> un_celu.descargado?
=> true
> una_notebook.utilizar! 100
=> 0
> una_notebook.cargar_a_tope!
=> 100
> una_notebook.descargado?
=> false
>
Definí las clases Moto, Auto y MedioDeTransporte y hace que las dos primeras hereden
de la tercera. También definí los
métodos initialize, recorrer!, cargar_combustible!, entran? y maximo_personas donde
correspondan.
Solucion
class MedioDeTransporte
def initialize(litros)
@combustible = (litros)
end
def cargar_combustible!(unos_litros)
@combustible += (unos_litros)
end
def entran?(unas_personas)
end
end
def maximo_personas
end
def recorrer!(km)
@combustible -= km / 2
end
end
def maximo_personas
end
def recorrer!(km)
@combustible -= km
end
end
¡Excelente!
Definí la clase Colectivo con sus métodos correspondientes. No te olvides que los
colectivos son medios de transporte.
Biblioteca
class MedioDeTransporte
def initialize(combustible)
# ...
end
def cargar_combustible!(combustible)
# ...
end
def entran?(pasajeros)
# ...
end
def maxi_personas
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
Solucion
def maximo_personas
20
end
@combustible-=kilometros*2
end
end
class MedioDeTransporte
def initialize(combustible)
# ...
end
def cargar_combustible!(combustible)
# ...
end
def entran?(pasajeros)
# ...
end
def maxi_personas
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
Solucion
class Colectivo<MedioDeTransporte
def maximo_personas
20
end
@combustible-=kilometros*2
end
true
end
def initialize
@combustible = 100
@pasajeros=0
end
end
¡Genial!
¡Vamos a verlo!
class Saludo
def saludar
"Buen día"
end
end
class MedioDeTransporte
def initialize(combustible)
# ...
end
def cargar_combustible!(combustible)
# ...
end
def entran?(pasajeros)
# ...
end
def maxi_personas
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
def recorrer!(kilometros)
# ...
end
end
Solucion
class Colectivo<MedioDeTransporte
def initialize
@combustible=100
@pasajeros=0
end
def cargar_combustible!(combustible)
super
@pasajeros=0
end
def recorrer!(km)
@combustible-=km*2
end
def maximo_personas
20
end
def entran?(personas)
true
end
end
¡Esto nos da una nueva posibilidad! Podemos hacer que SuperZombi herede
de Zombi para:
class Zombi
def initialize(salud_inicial)
@salud = salud_inicial
end
def salud
@salud
end
def gritar
"¡agrrrg!"
end
def sabe_correr?
false
end
def sin_vida?
@salud == 0
end
def recibir_danio!(puntos)
end
end
def sabe_correr?
true
end
def recibir_danio!(puntos)
end
def regenerarse!
@salud = 100
end
end
¡No, tranqui! Lo que quiere decir es que tiene sentido que existan
instancias de la clase Zombi. Esto significa que podemos tener tanto
objetos SuperZombi como Zombi.
class Zombi
def initialize(salud)
@salud= salud
end
def salud
@salud
end
def gritar
"¡agrrrg!"
end
def sabe_correr?
false
end
def sin_vida?
@salud == 0
end
def descansar!(minutos)
@salud += minutos
end
def recibir_danio!(puntos)
end
end
def sabe_correr?
true
end
def recibir_danio!(puntos)
end
def regenerarse!
@salud = 100
end
end
class Sobreviviente
def initialize
@energia = 1000
end
def energia
@energia
end
def beber!
@energia *= 1.25
end
class Aliado
def initialize
@energia = 500
end
def energia
@energia
end
def beber!
@energia *= 1.10
end
class Persona
def energia
@energia
end
def atacar!(zombi,danio)
zombi.recibir_danio! danio
end
end
def initialize
@energia = 1000
end
def beber!
@energia *= 1.25
end
end
def initialize
@energia = 500
end
def atacar!(zombi,danio)
super
@energia *= 0.95
end
def beber!
@energia *= 1.10
end
end
¡Terminaste Herencia!
¡Ya tenemos una nueva herramienta para evitar repetir lógica!
Apéndice
Conceptos generales
o Programa
o Sintaxis
o Paradigma
o Lenguaje de programación
o Computadora
o Error
El lenguaje Gobstones
El entorno de Gobstones
o Tablero
o Bolitas
o Cabezal
o Boom
o Palabras reservadas
Fundamentos de programación
o Programas
o Procedimientos
o Repetición simple
o Parámetros y argumentos
o Alternativa condicional
o Funciones
Procedimientos primitivos
Funciones primitivas
Bibliografía complementaria
Conceptos generales
Programa
Sintaxis
Paradigma
Un paradigma de programación es un conjunto de conceptos, estrategias
y buenas prácticas que nos brindan un marco para resolver problemas de
programación y comunicar su solución a otras personas.
Lenguaje de programación
Computadora
Error
El lenguaje Gobstones
Gobstones es un lenguaje gráfico desarrollado por docentes e
investigadores de la Universidad Nacional de Quilmes, diseñado para la
enseñanza de ideas básicas de programación.
El entorno de Gobstones
Tablero
Bolitas
Cabezal
Boom
Palabras reservadas
Los lenguajes cuentan con palabras reservadas para fines específicos, eso
significa que no podemos usarlas en cualquier situación. Algunos
ejemplos de Gobstones son program, procedure y function.
Fundamentos de programación
Programas
program {
Mover(Este)
Poner(Azul)
}
Procedimientos
Nombre
Todos los procedimientos llevan un nombre que explica la tarea que
realiza. Es importante que sea un nombre expresivo, es decir, que deje
claro lo que hace. De esa forma, cuando leemos su nombre podemos
entender su objetivo a simple vista, sin necesidad de profundizar en cómo
está hecho.
Subtareas
Los procedimientos son una herramienta muy útil para organizar la
resolución de un problema. Identificar y separar las partes que componen
un problema nos permite resolver las pequeñas tareas que lo conforman
y, al reunirlas, poder solucionarlo. Al utilizar procedimientos reconocemos
esas tareas, les ponemos nombre y las resolvemos definiendo un nuevo
procedimiento. De esta forma tenemos el procedimiento creado y a
disposición para invocarlo todas las veces que sean necesarias.
Definición e invocaciones
La definición de un procedimiento es la porción de código que desarrolla
la tarea que resuelve. Esta definición no implica su uso, solo su existencia.
Para definir un procedimiento debemos utilizar la palabra
reservada procedure luego el nombre elegido en con la primera letra de
cada palabra en mayúsculas (DeEstaForma) seguido por paréntesis (). Por
último, entre llaves, las acciones y comandos que lo conforman. Por
ejemplo:
procedure PonerUnaBolitaDeCadaColor(){
Poner(Rojo)
Poner(Verde)
Poner(Azul)
Poner(Negro)
}
program {
PonerUnaBolitaDeCadaColor()
}
Repetición simple
La repetición es una herramienta de programación que nos permite
automatizar la repetición de alguna tarea indicando el número de veces
consecutivas que deseamos hacerla.
program{
repeat(5){
Poner(Azul)
}
}
Caso borde
Tenemos que prestar atención al orden en el que damos las instrucciones
que reúne la repetición para garantizar que al comienzo y al final (o en los
“bordes”) se comporte como esperamos. Si no consideramos los casos
bordes en una repetición en la que combinamos acciones y movimientos
en el tablero es muy probable que pasemos celdas sin completar la
acción deseada o nos salgamos de los márgenes del tablero. Una buena
estrategia para evitarlo es considerar el último caso por fuera de la
repetición.
Por ejemplo, queremos colocar una bolita azul en cada celda de este
tablero:
program{
repeat(3){
Poner(Azul)
Mover(Este)
}
Poner(Azul)
}
Parámetros y argumentos
// Al invocar el procedimiento podemos elegir hacia qué dirección queremos movernos. Por ejemplo, si q
uisiéramos un programa que nos permita movernos dos celdas al Oeste deberíamos hacer:
program {
Mover2PasosHaciaEl(Oeste)
}
Alternativa condicional
Cuando un problema presenta escenarios que pueden variar necesitamos
algún tipo de herramienta para evaluar el contexto y tomar decisiones. La
alternativa condicional se ocupa precisamente de esto. ¿Cómo lo hace?
Primero evalúa el valor de verdad de una expresión booleana, que actúa
de condición y según se cumpla o no, realiza una acción determinada. Por
ejemplo, tenemos que decidir qué hacer según la cantidad de bolitas de
una celda, si un número es mayor que otro o si llegué a un extremo del
tablero.
program {
if(hayBolitas(Azul)) {
Sacar(Azul)
} // en este caso si hay al menos una bolita azul va a sacar una.
}
program {
if(hayBolitas(Azul)) {
Sacar(Azul)
} else {
Poner(Azul)
} // en este caso si hay al menos una bolita azul va a sacar una. Si no hay ninguna bolita azul va a poner
una.
}
Funciones
function nroBolitasTotal() {
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
}
Procedimientos primitivos
Poner(color)
program {
Poner(Rojo) // pone una bolita roja en la casilla actual.
}
Sacar(color)
program {
Sacar(Negro) // saca una bolita negra de las que hay en la casilla actual.
}
Mover(direccion)
program {
Mover(Este) // mueve el cabezal una vez hacia el Este.
}
IrAlBorde(direccion)
program {
IrAlBorde(Norte) // mueve el cabezal de la celda actual a la última celda en la dirección Norte.
}
VaciarTablero()
Saca todas las bolitas del tablero, dejando el cabezal en la posición en la
que estaba. Ejemplo:
program {
VaciarTablero() // En un tablero con alguna o muchas bolitas, las saca todas.
}
Funciones primitivas
nroBolitas(color)
nroBolitas(Rojo) // retorna 4
opuesto(direccion)
opuesto(numero)
siguiente(direccion)
previo(direccion)
Retorna una dirección: la anterior a la recibida como argumento, es decir,
la próxima en sentido anti horario. Ejemplo:
hayBolitas(color)
puedeMover(direccion)
Bibliografía complementaria
[Link]
[Link]
Apéndice
Declaración de Funciones
Operadores matemáticos
A partir de la Lección 1: Funciones y tipos de datos
4+5
10 - 5
8*9
10 / 5
Operadores lógicos
Comparaciones
// para números
4 >= 5
4>5
4 <= 5
4<5
Alternativa Condicional
if (hayPersonasEnEspera()) {
llamarSiguientePersona();
}
if (hayPersonasEnEspera()) {
llamarSiguientePersona();
} else {
esperarSiguientePersona();
}
Por último, podemos combinar varios ifs para tomar decisiones ante
múltiples condiciones:
if (hayPersonasEnEspera()) {
llamarSiguientePersona();
} else if (elPuestoDebeSeguirAbierto()) {
esperarSiguientePersona();
} else {
cerrarPuesto();
}
Variables
pesosEnMiBilletera = 65;
diasQueFaltanParaElVerano = 7;
pesosEnMiBilletera = pesosEnMiBilletera * 2;
diasQueFaltanParaElVerano = diasQueFaltanParaElVerano - 1;
pesosEnMiBilletera *= 2;
diasQueFaltanParaElVerano -= 1;
Repetición indexada
let patrimoniosDeLaHumanidad = [
{declarado: 1979, nombre: "Parque nacional Tikal", pais: "Guatemala"},
{declarado: 1983, nombre: "Santuario histórico de Machu Picchu", pais: "Perú"}
{declarado: 1986, nombre: "Parque nacional do Iguaçu", pais: "Brasil"},
{declarado: 1995, nombre: "Parque nacional de Rapa Nui", pais: "Chile"},
{declarado: 2003, nombre: "Quebrada de Humahuaca", pais: "Argentina"}
]
let cantidadPatrimoniosDeclaradosEnEsteSiglo = 0;
for (let patrimonio of patrimoniosDeLaHumanidad) {
if ([Link] >= 2000) {
cantidadPatrimoniosDeclaradosEnEsteSiglo += 1;
}
}
Biblioteca simplificada
Utilizamos una biblioteca de funciones inspirada en la que ya viene con
JavaScript, pero simplifiacada para que sea más sencilla y segura de usar.
A continuación listamos las principales funciones que se pueden usar,
indicando el equivalente real en JavaScript cuando corresponda.
longitud(unString)
> longitud("hola")
4
convertirEnMayuscula(unString)
> convertirEnMayuscula("hola")
"HOLA"
comienzaCon(unString, otroString)
imprimir(unString)
tirarDado()
> tirarDado()
5
> tirarDado()
1
> tirarDado()
2
listasIguales(unaLista, otraLista)
longitud(unaLista)
length de listas
agregar(unaLista, unElemento)
remover(unaLista, unElemento)
posicion(unaLista, unElemento)
Bibliografía complementaria
[Link]
[Link]
Apéndice
El lenguaje Ruby
Conceptos de programación con objetos
o Objeto
o Ambiente
o Envío de mensajes
o Definición de objetos
o Definición de métodos
o Interfaz
o Asignación
o self
o Responsabilidad y delegación
o Atributos
o Estado
o Accessors
o Encapsulamiento
o Convenciones para la nominación de métodos
o Alternativa Condicional
o Polimorfismo
o Referencias
o Colecciones
o Bloques de código
o Clases e instancias
o Herencia
o Redefinición
o Clases abstractas
o super
Operadores
o Operadores matemáticos
o Operadores lógicos
o Comparaciones
Métodos usuales
o [Link]
o [Link] bloque
o [Link]
o [Link]
o [Link]?
o [Link]? otro_objeto
o [Link] elemento
o [Link] elemento
o [Link]? elemento
o [Link]
o [Link] bloque_con_condicion
o [Link] bloque_con_condicion
o [Link]? bloque_con_condicion
o [Link] bloque
o [Link] bloque_con_condicion
o [Link] bloque
o [Link] bloque
o [Link]
Bibliografía complementaria
El lenguaje Ruby
Ruby es un lenguaje de Programación Orientada a Objetos gratis y de
código abierto creado en Japón. Su sintaxis amigable lo hace muy
popular sobre todo en el desarrollo web.
Envío de mensajes
> [Link]!
> [Link]! 20
Definición de objetos
module Pepita
end
module Norita
end
Definición de métodos
module Pepita
def [Link]!
end
def [Link]!(distancia)
end
Interfaz
numero_favorito = 8
color_favorito = "Violeta"
self
module Gaby
@esta_alegre = false
def self.escuchar_musica!
@esta_alegre = true
[Link]!
end
def [Link]!
# No es importante esta definición
end
end
Responsabilidad y delegación
module Pepita
@energia = 100
def [Link]!
end
def [Link]=(una_ciudad)
@ciudad = una_ciudad
end
def [Link]!(distancia)
@energia = @energia - distancia * 2
end
Estado
Accessors
def [Link]
@energia
end
def [Link]=(nueva_energia)
@energia = nueva_energia
end
end
Encapsulamiento
module AutoDeFabi
@patente = "AAA 111"
@nafta = 200
@color = "rojo"
def [Link]
@patente
end
def [Link]=(un_color)
@color = un_color
end
def [Link]!(cantidad)
@nafta += cantidad
end
end
module Fabi
def self.pintar_auto!(un_color)
[Link] = un_color
end
def self.cargar_nafta!(una_cantidad)
[Link]! una_cantidad
end
end
module Pepita
@energia = 100
def [Link]
@energia
end
def [Link]=(nueva_energia)
@energia = nueva_energia
end
def [Link]!(distancia)
@energia = @energia - distancia * 2
end
def [Link]?
@energia < 10
end
end
if [Link]?
[Link]! 10
end
if [Link]?
[Link]! 10, "alpiste"
else
[Link]! 15
end
if [Link]?
[Link]!
elsif [Link]?
[Link]!
else
[Link]!
end
Polimorfismo
module Agus
def [Link]=(un_celular)
@celular = un_celular
end
def self.realizar_llamada!(minutos)
@[Link]! minutos
end
end
module CelularPersonal
@saldo = 200
def [Link]!(minutos)
@saldo -= minutos
end
end
module CelularLaboral
@minutos_consumidos = 0
def [Link]!(minutos)
@minutos_consumidos += minutos
end
end
Referencias
las variables
dia = "domingo"
[Link]
module Pepita
def [Link]!
end
end
[Link]!
los atributos
module Pepita
@ciudad = GeneralLasHeras
def [Link]
@[Link]
end
end
los parámetros
module Guille
@paginas_leidas = 0
def [Link]!(libro)
@paginas_leidas = @paginas_leidas + libro.cantidad_de_paginas
end
end
Colecciones
Bloques de código
> saludador = proc { |saludo, nombre| saludo + " " + nombre + ", que lindo día para programar, ¿no?" }
Por último, para ejecutar el código dentro del bloque debemos enviarle el
mensaje call con los argumentos correspondientes.
> anio_nuevo.call
=> 2022
Clases e instancias
module Firulais
@energia = 200
def [Link]!(un_tiempo)
@energia -= un_tiempo
end
def self.recibir_duenio!
@energia += 100
end
end
module Stimpy
@energia = 300
def [Link]!(un_tiempo)
@energia -= un_tiempo
end
def self.recibir_duenio!
@energia += 100
end
end
class Perro
def initialize(energia)
@energia = energia
end
def jugar!(un_tiempo)
@energia -= un_tiempo
end
def recibir_duenio!
@energia += 100
end
end
Herencia
class Gato
def initialize(energia)
@energia = energia
end
def jugar!(un_tiempo)
@energia -= un_tiempo
end
def recibir_duenio!
@energia -= 10
end
end
class Perro
def initialize(energia)
@energia = energia
end
def jugar!(un_tiempo)
@energia -= un_tiempo
end
def recibir_duenio!
@energia += 100
end
end
def jugar!(un_tiempo)
@energia -= un_tiempo
end
end
Por último es necesario hacer que las clases Gato y Perro hereden
de Mascota utilizando <:
Redefinición
def recibir_duenio!
@energia *= 2
end
end
Clases abstractas
super
Por ejemplo:
Operadores
Operadores matemáticos
Operadores lógicos
Comparaciones
Metodos usuales
A lo largo del capítulo "Programación con Objetos" utilizamos algunos
métodos en la resolución de ejercicios. A continuación te los listamos en
el orden que aparecen.
[Link]
> (-8).abs
=> 8
> (3 - 7).abs
=> 4
[Link] bloque
> [Link]
=> 40
[Link]
[Link]
Lección 4: Referencias
Nos permite saber si numero es par.
> [Link]?
=> true
> [Link]?
=> false
[Link]? otro_objeto
[Link] elemento
> numeros_de_la_suerte.push 9
> numeros_de_la_suerte
=> [8, 7, 42, 9]
[Link] elemento
> numeros_de_la_suerte.delete 7
> numeros_de_la_suerte
=> [8, 42]
[Link]? elemento
[Link]
[Link] bloque_con_condicion
[Link] bloque_con_condicion
[Link]? bloque_con_condicion
[Link] bloque
[Link] bloque_con_condicion
[Link] bloque
[Link] bloque
[Link]
Bibliografía complementaria
[Link]
[Link]
[Link] (en inglés)
Examen
Ejercicio 8: Ejercicio 8
En un curso tenemos un conjunto de estudiantes, a la hora de cerrar las
actas es necesario saber cuántas personas aprobaron . Teniendo en
cuenta que cada estudiante sabe responder al mensaje aprobo_materia?...
module Alumnado
def self.cantidad_de_gente_aprobada
@[Link]{|un_estudiante| un_estudiante.aprobo_materia?}
end
end
module Alumnado
2
@estudiantes = [May, Gus, Ro, Agus, Lu, Ale]
3
4
def self.cantidad_de_gente_aprobada
5
@[Link]{|un_estudiante| un_estudiante.aprobo_materia?}
6
end
7
end