0% encontró este documento útil (0 votos)
44 vistas537 páginas

Argentina Programa

El documento presenta una introducción a la programación a través del lenguaje Gobstones. Explica conceptos básicos como programas, tableros, cabezales y movimientos. Muestra ejemplos de programas sencillos que mueven el cabezal en el tablero y ejercicios para que el lector cree sus propios programas de movimiento.

Cargado por

miaandradepi
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
44 vistas537 páginas

Argentina Programa

El documento presenta una introducción a la programación a través del lenguaje Gobstones. Explica conceptos básicos como programas, tableros, cabezales y movimientos. Muestra ejemplos de programas sencillos que mueven el cabezal en el tablero y ejercicios para que el lector cree sus propios programas de movimiento.

Cargado por

miaandradepi
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

1.

Fundamentos

¿Nunca programaste antes? Aprendé los fundamentos de la


programación utilizando Gobstones, un innovador lenguaje gráfico en
el que utilizás un tablero con bolitas para resolver problemas.

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!

3. Programación con Objetos

El paradigma de objetos, a veces también conocido como orientado a


objetos nos propone solucionar problemas y modelar nuestra realidad
empleando objetos que se comunican entre ellos intercambiando
mensajes. ¡Adentrémonos en el mundo de los objetos y Ruby!

Primeros Programas
Aunque la programación parece una ciencia exacta, programar es el arte
de hacer que una computadora resuelva nuestros problemas.

Momento... ¿arte? ¡Sí! Hay muchas formas de resolver un problema y


encontrarlas es un proceso creativo . El resultado de este proceso es
un programa: una descripción de la solución al problema que puede
ser ejecutada por una máquina.

Saber programar nos da un gran poder: en lugar de hacer tareas


repetitivas y tediosas, usaremos nuestros conocimientos e imaginación
para automatizarlas (por suerte, la computadora no se aburre ).

Pero, ¿cómo le explicamos a la máquina de qué forma resolver el


problema? Necesitamos escribirla en un idioma que tanto ella como las
personas podamos entender: el lenguaje de programación.

¡Aprendamos cómo hacerlo de la mano del lenguaje Gobstones!

Ejercicio 1: ¡Hola, computadora!


En nuestra vida cotidiana sabemos cómo hacer para comunicarnos con
otras personas. Si necesitamos pedirles que hagan algo, tenemos que
decirles por favor . Pero... ¿cómo hacemos si le tenemos que pedir algo a
una computadora?

Para que la computadora nos entienda, vamos a tener que aprender SU


lenguaje . En realidad, las computadoras entienden más de un lenguaje,
muchos de ellos los vamos a aprender a lo largo de este curso.

En este capítulo vamos a conocer Gobstones, un lenguaje educativo


diseñado por docentes argentinos .

Gobstone usa un tablero y bolitas de colores. El tablero es muy similar a


un tablero de ajedrez: tiene diferentes celdas por las que podemos
movernos. Para hacerlo, vamos a utilizar un cabezal que en todo
momento está situado sobre una de las celdas del tablero y puede
realizar distintas operaciones, como, por ejemplo, poner bolitas.

Ahora es tu turno. ¡Empecemos a programar!

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.

Estos tableros pueden ser de cualquier tamaño, por ejemplo,

4x4 3x2

Siempre vamos a necesitar un tablero sobre el


cual ejecutar nuestros programas, ¡pero despreocupate! nos vamos a
encargar de crearlos por vos en cada uno de los ejercicios. Lo interesante
es que un mismo programa puede ejecutarse sobre distintos tableros,
potencialmente produciendo resultados diferentes.

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

Por ejemplo, el siguiente es un tablero de 5x2, con el cabezal en la


segunda fila y la cuarta columna.

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.

Vamos a ver otro ejemplo?

Presioná Continuar y generaremos un tablero 3x3 con el cabezal en la segunda


columna y tercera fila.
¡Muy bien!
Tablero final
0 1 2

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?

Ejercicio 4: Que comience el movimiento


Hasta ahora lo que vimos no fue muy emocionante, porque no te
enseñamos cómo darle instrucciones a la máquina y sólo te mostramos
un tablero . En este ejercicio vamos a aprender una de las órdenes que
podemos darle a la máquina: mover el cabezal.

Por ejemplo, partiendo de un tablero inicial vacío con el cabezal en el


origen (abajo a la izquierda), podemos fácilmente crear un programa que
mueva el cabezal una posición hacia el norte:

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

El código del programa (es decir, el texto de la descripción de la solución


que le daremos a la computadora) que logra esto es el siguiente:

program {
Mover(Norte)
}

¿No nos creés? Escribí el código anterior en el editor y dale Enviar.


¡Dame una pista!
1
program {
2
Mover(Norte)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


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

0 1 2

¡Felicitaciones, creaste tu primer programa! Éste, al ser ejecutado por la


máquina, provoca que el cabezal se mueva una posición hacia el Norte.

Pero programar no se trata de copiar y pegar código. Acompañanos al


próximo ejercicio para entender qué es lo que hicimos exactamente.
Ejercicio 5: Que siga el movimiento
Entendamos qué es lo que acabamos de hacer: ¡crear un programa!

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.

La sintaxis de un program es bastante simple:

1. escribimos una línea (renglón) que diga program, seguido de una


llave de apertura: {
2. a continuación, los comandos: uno por línea
3. y finalmente, una última llave que cierra la que abrimos
anteriormente }

Vamos a ver algunos ejemplos de programs:

 uno que no hace nada

program {
}

 uno que mueve el cabezal una posición hacia el norte

program {
Mover(Norte)
}

 uno que mueve el cabezal dos posiciones hacia el norte

program {
Mover(Norte)
Mover(Norte)
}

¡Te toca a vos!

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

¡Dame una pista!

1
program {
2
Mover (Norte)
3
Mover (Norte)
4
Mover (Norte)
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Los lenguajes de programación son creados con algunas palabras que


solo se pueden utilizar con un fin determinado. Se las llama palabras
reservadas . En Gobstones, el lenguaje que estamos utilizando, program es
una palabra reservada.

Como ya sabemos que nuestros programas son ejecutados por la


máquina, de ahora en más diremos "creá un programa que haga ..." en vez
de "creá un programa que provoque que la máquina haga ...".

Pero ojo: la máquina sigue estando ahí y no hay que olvidarla, sólo
hacemos esto para escribir un poco menos.

Ejercicio 6: Para todos lados


Como te imaginarás, el cabezal no sólo se puede mover hacia el Norte, y
un programa puede combinar cualquier tipo de movimientos.

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

¡Dame una pista!

1
program {
2
Mover (Este)
3
Mover (Este)
4
Mover (Sur)
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


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

0 1 2

Notá que estos dos programas hacen lo mismo:

program {
Mover(Este)
Mover(Este)
Mover(Sur)
}
program {
Mover(Este)
Mover(Sur)
Mover(Este)
}

Moraleja: como te decíamos al principio ¡no hay una sóla forma de


resolver un problema!

Y además, el orden, a veces, no es tan importante. Acompañanos a


entender mejor esto.

Ejercicio 7: El orden de las cosas


Cuando trabajamos en Gobstones, hacemos las cosas en un cierto orden.
Por ejemplo, si tenemos este programa:

program {
Mover(Norte)
Mover(Este)
}

una forma posible de leerlo (llamada operacional) es como lo haría una


máquina, en orden, de arriba hacia abajo:

1. primero se mueve al norte: Mover(Norte)


2. luego se mueve al este: Mover(Este)

Y de hecho se ejecuta de esa forma. Esto es cómo lo hace.

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

¡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

0 0

0 1
¡Perfecto!

Recién creamos un programa en el que el orden no afecta lo que


queremos hacer. Pero esto no será siempre así, en breve nos toparemos
con problemas en los que hay que tener más cuidado con el orden de los
comandos.

Ejercicio 8: Sí, esto también se puede romper


Hasta ahora veníamos tratando de esquivar el asunto, pero seguro ya
habrás pensado que tiene que haber alguna forma de romper esto
(incluso es posible que ya te haya pasado).

Si bien nunca vamos a querer que nuestro programa se rompa, es algo


que definitivamente te va a pasar muchas veces. Pero no es motivo para
frustrarse ni mucho menos, te aseguramos que a todo el mundo le pasó
alguna vez (bueno, también 2, 3, 100, 800 veces...).

Dicho esto, te vamos a mostrar una forma de hacerlo, simplemente para


que no te asustes tanto cuando te pase de verdad .

¿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

¡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

[2:3]: No se puede mover hacia la dirección Sur: cae afuera del tablero.

¡BOOOOOOOOOOOOOOOOOM!

Ey, ¿qué pasó?


Tu programa falló, se rompió, o como lo llamamos en el universo
Gobstones: hizo BOOM.

Y, ¿qué significa esto?


Que los comandos que le diste a la computadora no se pueden ejecutar, y
hay algo que vas a tener que cambiar para que funcione. En este ejercicio
eso no tiene sentido porque lo hicimos a propósito, pero tenelo en
cuenta para cuando falles en el futuro.

Siguiente Ejercicio: Nuestras primeras bolitas

Ejercicio 9: Nuestras primeras bolitas


Genial, ya entendiste cómo mover el cabezal del tablero usando la
operación Mover y las direcciones (Sur, Oeste, etc). Vayamos un paso más
allá: las bolitas.

En cualquier celda de nuestro tablero podemos poner bolitas. Las hay de


distintos colores:
 rojas (Rojo);
 azules (Azul);
 negras (Negro);
 y verdes (Verde).

Por ejemplo, este es un tablero con una bolita roja y una negra:

0 1

1
1 1

0 0
1

0 1

Además de moverse, el cabezal también puede poner bolitas en la celda


actual. Para eso contamos con la operación Poner, que le dice al cabezal
que deposite una bolita del color dado:

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

¡Muy bien! Tu solución pasó todas las pruebas


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

0 1 2

¡Felicitaciones! Acabás de escribir un programa que pone una bolita roja


en la celda actual.

Ejercicio 10: Más y más bolitas


Algo interesante de nuestros tableros es que en sus celdas podemos
poner cualquier cantidad de bolitas de cualquier color.

Por ejemplo, si tenemos este tablero:

0 1 2 3 4

1 1

0 0
0 1 2 3 4

y ejecutamos el siguiente programa:

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.

¡Escribí este programa en el editor y fijate cómo queda el tablero!

1
program {
2
Poner (Rojo)
3
Poner (Rojo)
4
Poner (Rojo)
5
Poner (Azul)
6
Poner (Verde)
7
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


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
3 1

0 0

0 1 2 3 4

Notá que en este problema, si cambiamos el orden en


que llamamos (usamos a) Poner, el resultado no cambia: siempre nos
terminará quedando un tablero con tres bolitas rojas, una azul y una
verde.

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

Ejercicio 11: Poné tus primeras bolitas


Como te habrás dado cuenta, estos tableros son un poco mágicos, podemos poner en
una celda tantas bolitas como queramos: 2, 4, 12, 50, 1000. ¡No hay ningún límite!

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

¡Muy bien! Tu solución pasó todas las pruebas


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
4

0 1 2

Ejercicio 12: Sacar Bolitas


De la misma forma que hay un "poner bolita" (Poner), tenemos un "sacar
bolita" (Sacar), que quita exactamente una bolita del color dado.

Por ejemplo, el siguiente programa saca dos bolitas de la posición inicial.

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

¡Dame una pista!

1
program {
2
Mover (Sur)
3
Sacar (Rojo)
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

0 1

1
1 1

0 0
1

0 1

Tablero final

0 1

1
1 1

0 0

0 1

¿Y si no hubiera ninguna bolita para sacar?

Ejercicio 13: Cuando no hay bolitas


Cada vez que usamos Sacar, tenemos que tener más cuidado que
con Poner, porque...

¿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

¡Muy bien! Tu solución pasó todas las pruebas

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

Claro, otra vez BOOM.

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!

¡Terminaste Primeros Programas!


¡Felicitaciones, terminaste esta guía! Eso significa que ya sabés de bolitas,
tableros y cabezales, y que podés controlar a éste último con los
comandos
 Poner
 Sacar
 Mover

Y además, sabés como definir un programa (program)

Sin embargo, hay muchas más cosas que podés hacer en el


lenguaje Gobstones con este tablero. En las próximas guías seguiremos
aprendiendo más comandos y nuevas herramientas de programación.

Y lo más importante: modularizar a nuestros programas usando


procedimientos y funciones. ¡Acompañanos!

Ejercicio 1: Calentando motores


¡Veamos un primer ejemplo!

El siguiente programa coloca una bolita roja en la posición inicial y una


negra al este.

program {
Poner(Rojo)
Mover(Este)
Poner(Negro)
}

Probá escribir y ejecutar este programa. Te mostraremos el resultado al ejecutarlo


en un tablero de 2x2, y en otro de 3x2, ambos con el cabezal inicialmente en el
origen.
¡Dame una pista!

1
program {
2
Poner (Rojo)
3
Mover (Este)
4
Poner (Negro)
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

Ahora que combinamos operaciones, la cosa se pone un poco mas


complicada, porque hay que tener más cuidado con el orden.

Por ejemplo, mirá el programa que escribiste:

program {
Poner(Rojo)
Mover(Este)
Poner(Negro)
}

Operacionalmente:

1. pone una roja


2. luego se mueve al este
3. luego pone una negra

Es decir: pone una roja en la posicion inicial, y una negra al este

Y ahora mirá este otro:

program {
Mover(Este)
Poner(Rojo)
Poner(Negro)
}

Operacionalmente:

1. se mueve al este
2. luego pone una roja
3. luego pone una negra

Es decir: pone una roja y una negra al este de la posición inicial.

Moraleja: ¡no hacen lo mismo! Cambiar el orden nos cambió el qué.

Ejercicio 2: Combinando comandos


Creá un programa que ponga dos bolitas en la posición inicial, y otras dos en la celda de al
lado hacia el Este. Todas las bolitas deben ser rojas.
Acá te dejamos un ejemplo de cómo debería quedar el tablero:
0 1 2

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

¡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

0 0
2 2

0 1

Ejercicio 3: La fila roja


Creá un programa que a partir de un tablero vacío con el cabezal en el origen, dibuje una
linea de cuatro celdas hacia el Este. Las bolitas deben ser rojas y debe poner una bolita por
celda.
Ademas, el cabezal debe quedar en el extremo final de la línea, como se ve en la
imagen:

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Ejercicio 4: Una escalerita


Usando las herramientas que ya conocés, creá un programa que dibuje una escalera azul
como la que se ve en la imagen. El cabezal empieza en el origen (o sea, en el borde Sur-
Oeste) y debe quedar en el extremo inferior derecho de la escalera.
Mirá la imagen:

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

¡Muy bien! Tu solución pasó todas las pruebas


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

Ah, el cabezal empieza en el origen.


1

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial
0 1 2

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

Ejercicio 6: Y ahora una de más cerquita


Ya lograste dibujar la bandera de Portugal con Gobstones. Ahora
probemos hacer una bandera de Latinoamérica. ¿Te animás a dibujar la
de Argentina?

Aunque como en Gobstones no hay amarillo, nos vamos a tomar el


atrevimiento de cambiarlo por rojo (perdón Belgrano, no nos queda
otra ).

Con el cabezal en el origen, tu tarea es dibujar esta pseudo-bandera argentina:


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

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

No quedó muy lindo el programa, ¿no?

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

Ejercicio 7: Limpiando el jardín


¡Necesitamos podar este jardín!

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.

Con el cabezal en el origen, creá un programa que se encargue de "podar" el tablero de la


imagen: sacar todas las bolitas verdes. Al finalizar, el cabezal debe terminar donde empezó.
1

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

¡Terminaste Práctica Primeros Programas!


Todo muy lindo esto de Poner, Mover y Sacar, pero seguro que ya estás
empezando a pensar que te estamos estafando.

¿No era que la programación se trataba de crear cosas y usar la


imaginación?
¿Cómo es esto posible si sólo puedo usar unos pocos comandos que pensó
alguien más?

¡No desesperes! En la siguiente guía vamos a dejar un poco de lado


las primitivas para pasar a algo más interesante.

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.

Como te imaginarás, con estas 3 cosas ya podés resolver muchos


problemas: dibujar banderas de países , escribir tu nombre , hacer un
plano de tu casa , etc, etc. Pero más temprano que tarde esas
herramientas no te van a alcanzar, y tu programa se va a volver tan
complejo que no va a ser fácil entenderlo.

¿No nos creés? ¡Acompañanos!

Ejercicios

 1. ¿De qué se trata?


 2. Un programa un poco largo
 3. Las cosas por su nombre
 4. Enseñándole tareas a la computadora
 5. Procedimientos en acción
 6. Escribiendo procedimientos
 7. Procedimiento, ¡te invoco!
 8. Una definición, "infinitos" usos
 9. Procedimientos dentro de otros
 10. Dibujamos con imaginación
 11. De punta a punta
 12. Rojo al borde
 13. Adornando el tablero
 14. Colores, colores, colores
 15. Cuadrado de colores

¡Comenzá esta lección!

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.

Como te imaginarás, con estas 3 cosas ya podés resolver muchos


problemas: dibujar banderas de países , escribir tu nombre , hacer un
plano de tu casa , etc, etc. Pero más temprano que tarde esas
herramientas no te van a alcanzar, y tu programa se va a volver tan
complejo que no va a ser fácil entenderlo.

¿No nos creés? ¡Acompañanos!

Ejercicios

 1. ¿De qué se trata?


 2. Un programa un poco largo
 3. Las cosas por su nombre
 4. Enseñándole tareas a la computadora
 5. Procedimientos en acción
 6. Escribiendo procedimientos
 7. Procedimiento, ¡te invoco!
 8. Una definición, "infinitos" usos
 9. Procedimientos dentro de otros
 10. Dibujamos con imaginación
 11. De punta a punta
 12. Rojo al borde
 13. Adornando el tablero
 14. Colores, colores, colores
 15. Cuadrado de colores

¡Comenzá esta lección!

Ejercicio 2: Un programa un poco largo


Ahora tenés la posibilidad de ver en acción el programa.

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

¡Presioná Continuar para comprobar tu respuesta anterior!


Continuar

¡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

Aunque ahora pudimos probarlo, sigue siendo un poco confuso saber de


qué se trata el programa con solo leerlo ¿no sería mejor si también fuera
fácil de entender para un humano?

Ejercicio 3: Las cosas por su nombre


Mirá esta nueva versión del mismo programa. Aunque todavía hay
elementos de la sintaxis que no conocés, confiamos en que vas a tardar
mucho menos en descubrir qué hace.
Enviá el código, así nos aseguramos de que hace exactamente lo mismo que el
anterior.

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

¡Muy bien! Tu solución pasó todas las pruebas


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

Mucho más fácil de entender, ¿no?

Probablemente te estés preguntando ¿cómo supo la computadora lo que


tenía que hacer DibujarCuadradoNegroDeLado3 ? ¿Qué es eso de procedure?

¡Vamos a averiguarlo!

Ejercicio 4: Enseñándole tareas a la computadora


Como viste en el ejemplo del cuadrado, se puede empezar a diferenciar
dos tipos de comandos dentro de un programa:

 los que vienen definidos por el lenguaje y nos sirven para


expresar operaciones básicas, como Mover, Poner y Sacar. A estos los
llamaremos comandos primitivos, o simplemente primitivas;
 y los que definimos nosotros, que nos sirven para expresar tareas
más complejas. Como el nombre de esta lección sugiere, estos son
los procedimientos.

Cuando definimos un procedimiento estamos "enseñándole" a la


computadora a realizar una tarea nueva, que originalmente no estaba
incluida en el lenguaje.

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

¡Muy bien! Tu solución pasó todas las pruebas


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
3

0 1 2

Ahora que ya probamos cómo funcionan, podemos ver las diferencias


entre las sintaxis de programas y procedimientos.

El procedimiento se define con la palabra procedure seguida por un nombre


y paréntesis (). Luego escribimos entre llaves {} todas las acciones que
incluya. Para ver un procedimiento en acción hay que invocarlo dentro de
un programa, si no sólo será una descripción que nunca se va a ejecutar.

El programa se crea con la palabra program seguida de llaves {}, y adentro


de ellas lo que queremos que haga la computadora. ¡No lleva nombre ni
paréntesis!

Ejercicio 5: Procedimientos en acción


Si bien las palabras que utilizamos para crear programas (program) y definir
procedimientos (procedure) se escriben parecido son cosas muy distintas.

Cuando creamos un programa nuevo le estamos diciendo a la


computadora lo que queremos que suceda luego de tocar Enviar.

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.

Veamos cómo creamos un nuevo procedimiento llamado


PonerVerdeYAzul.

procedure PonerVerdeYAzul() {
Poner(Verde)
Poner(Azul)
}

La computadora solo va a seguir las instrucciones dentro de un


procedimiento cuando sea invocado dentro de un program. ¿Cómo lo
invocamos? Escribimos su nombre seguido por paréntesis ().
program {
PonerVerdeYAzul()
}

Completá el código para que además de definir el


procedimiento PonerNegroYRojo luego lo invoque en el program.

1
procedure PonerNegroYRojo() {
2
Poner(Negro)
3
Poner(Rojo)
4
}
5
program {
6
PonerNegroYRojo()
7
}
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
1

0 0
1

0 1

A la hora de definir e invocar procedimientos tenemos que prestar


mucha atención a la sintaxis para no perder de vista el objetivo del
problema por un error de escritura.

Ejercicio 6: Escribiendo procedimientos


Llegó el momento de programar desde cero. ¡No te preocupes! Como recién
estamos empezando, repasemos lo que aprendimos.

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:

 empezamos con la palabra reservada procedure;


 elegimos un nombre que lo describa y lo escribimos con mayúscula
seguido de paréntesis ();
 encerramos las acciones que queremos que haga entre llaves {}.

Entonces, un procedimiento que se mueve cuatro celdas al Norte se va a


definir así:

procedure Mover4AlNorte() {
Mover(Norte)
Mover(Norte)
Mover(Norte)
Mover(Norte)
}

Y si lo queremos utilizar, tenemos que invocarlo dentro


del program escribiendo su nombre tal cual y sin olvidar los
paréntesis() ¡Prestá atención a la sintaxis!

program {
Mover4AlNorte()
}

¡Ahora te toca a vos!


Definí un procedimiento Poner3Verdes que ponga 3 bolitas verdes en la celda actual
e invocalo en el program.

1
procedure Poner3Verdes(){
2
Poner (Verde)
3
Poner (Verde)
4
Poner (Verde)
5
}
6
program {
7
Poner3Verdes ()
8
}
9

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

0 0
3

0 1

Resumiendo, en lo que a un procedimiento respecta, se pueden distinguir


dos momentos:

 la definición, que es cuando ponemos procedure Poner3Verdes() y el


bloque de código que especifica qué hace.
 el uso o invocación, que es cuando escribimos Poner3Verdes() en
alguna parte de program (o de otro procedimiento).

Ejercicio 7: Procedimiento, ¡te invoco!


Algo MUY importante es que un procedimiento se define una sola vez y
luego se puede usar todas las veces que necesitemos, como cualquier
otro comando.

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.

Para facilitarte las cosas, a veces te ofreceremos partes del problema


resuelto, para que sólo tengas que enfocarte en lo que falta resolver. ¿Y
dónde están? Mirá el editor y fijate si encontrás la pestaña Biblioteca . Lo
que aparece en la Biblioteca no hace falta que lo escribas en el código, ¡si
está ahí podés invocarlo directamente!

¡Vamos a probarlo! Queremos poner 3 bolitas verdes en dos celdas consecutivas


como muestra el tablero:
0 1 2

1 1

0 0
3 3

0 1 2

Creá un programa que lo haga invocando el procedimiento Poner3Verdes. Recordá


que ya te lo damos definido ¡no tenés que volver a escribirlo!

 Solución
 Biblioteca

1
program {
2
Poner3Verdes ()
3
Mover (Este)
4
Poner3Verdes ()
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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.

Ejercicio 8: Una definición, "infinitos" usos


Otro procedimiento que ya usamos antes es Poner3Rojas, que pone tres
bolitas rojas en una celda. Te ahorramos el trabajo de escribirlo, si lo
buscás vas a ver que está definido en la Biblioteca. ¡Ahora podés utilizarlo
tantas veces como quieras!

Creá un programa que ponga 9 bolitas rojas en la celda actual invocando el


procedimiento Poner3Rojas todas las veces que sea necesario.
¡Dame una pista!

 Solución
 Biblioteca

1
program {
2
Poner3Rojas ()
3
Poner3Rojas ()
4
Poner3Rojas()
5
}
6

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

0 0
9

0 1

No te olvides de revisar las herramientas que nos ofrece la Biblioteca para


saber cuáles podemos aprovechar cuando resolvamos nuestro problema.

Ejercicio 9: Procedimientos dentro de otros


Cuando creamos procedimientos agrupamos varias acciones en una tarea
que podemos reconocer y nombrar. Eso hace nuestros programas más
claros, legibles y nos ahorra repeticiones innecesarias.

Ya vimos que un procedimiento puede ser invocado tantas veces como


queramos dentro de un programa , pero como su objetivo es agrupar los
pasos de una tarea para usarla cuando haga falta, también lo podemos
invocar dentro de otros procedimientos. ¡Vamos a probarlo!

Definí el procedimiento Poner9Rojas que, utilizando Poner3Rojas, ponga nueve bolitas


rojas en una celda. Una vez definido, invocá el nuevo procedimiento en un program.
¡Dame una pista!

 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

Resultados de las pruebas:


 Tablero inicial

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

Bueno, ya sabemos cómo crear procedimientos, pero ¿por qué


querríamos hacerlos?

Algunas posibles respuestas:


 para simplificar código, escribiendo una sola vez y en un solo
lugar cosas que vamos a hacer muchas veces;
 para escribir menos, por qué querríamos hacer cosas de más;
 para que el propósito de nuestro programa sea más entendible
para los humanos, como vimos en el ejemplo
de DibujarCuadradoNegroDeLado3. Para esto es fundamental pensar
buenos nombres, que no sean muy largos
(DibujarCuadradoNegroDeLado3FormadoPor9BolistasDeArribaAAbajo), ni
demasiado cortos (DibCuaNeg), y sobre todo que dejen en claro qué
hace nuestro procedimiento;
 para comunicar la estrategia que pensamos para resolver
nuestro problema;
 y como consecuencia de todo esto: para poder escribir programas
más poderosos.

Ejercicio 10: Dibujamos con imaginación


Vamos a usar un poco la imaginación y vamos a hacer un procedimiento
que dibuje una "punta" negra en la esquina inferior izquierda de esta
forma:

0 1 2

2 2

1
1 1

1 1
0 0

0 1 2

Definí el procedimiento DibujarPuntaNegra e invocalo dentro de un program. El cabezal


comienza en el origen y debe terminar en el extremo inferior derecho de la punta.

Ejercicio 11: De punta a punta


En el ejercicio anterior ya dibujamos una punta, ahora vamos a pensar
cómo aprovechar el procedimiento que hicimos para crear un tablero
como este:
0 1 2 3

1
3 3

1 1
2 2

1
1 1

1 1
0 0

0 1 2 3

Definí el procedimiento DibujarDosPuntas e invocalo dentro un program. Acordate de


utilizar DibujarPuntaNegra.
¡Dame una pista!

Recordá que se pueden invocar procedimientos dentro de


procedimientos, así que vas a tener que usar DibujarPuntaNegra dentro de la
definición de DibujarDosPuntas.

Prestale atención a la ubicación del cabezal antes y después de


invocar DibujarPuntaNegra.

 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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Para resolver este problema lo que hicimos fue separarlo en partes,


identificando las tareas más pequeñas que ya teníamos resueltas.

Los procedimientos son muy útiles para esto, se ocupan de resolver


una subtarea y nos permiten repetirla o combinarla para solucionar un
problema mayor que la incluya.

Ejercicio 12: Rojo al borde


Ya vimos que los comandos que vienen definidos por el lenguaje se
llaman primitivas. Hay una primitiva que no usaste hasta ahora que
queremos presentarte.

Imaginate que no sabés ni dónde está el cabezal ni qué tamaño tiene el


tablero pero querés llegar a una esquina: La primitiva Mover no te va a ser
de mucha ayuda.

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.

¿Cómo? Mirá el resultado del siguiente programa:

program {
IrAlBorde(Este)
}

Inicial
Inicial

0 1 2 3

1 1

0 0

0 1 2 3

¡Vamos a aprovecharlo!

Definí el procedimiento RojoAlBorde que ponga una bolita roja en la esquina


superior izquierda del tablero e invocalo en el program.
¡Dame una pista!

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

Resultados de las pruebas:

 Tablero de 2x3 con el cabezal abajo a la izquierda


Tablero inicial

0 1

2 2

1 1

0 0

0 1

Tablero final

0 1

2 2
1

1 1

0 0

0 1

 Tablero de 3x3 con el cabezal en el medio


Tablero inicial

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!

IrAlBorde es una primitiva muy útil para cuando no conocemos las


condiciones de nuestro tablero.

Ejercicio 13: Adornando el tablero


Para resolver un problema nos conviene comprender bien de qué se trata
para elegir una estrategia. Es el momento de empezar a hacerlo
aprovechando los procedimientos.

Uno de los objetivos al usar procedimientos es identificar y nombrar las


subtareas que conforman un problema y combinar sus soluciones para
poder resolverlo. Veamos un ejemplo:

Queremos decorar con guirnaldas las dos esquinas superiores


de cualquier tablero como muestra la imagen.

0 1 2 3

2 2
3 3 3 3

1 1

0 0

0 1 2 3

Pensemos una estrategia distinguiendo subtareas:

Cada guirnalda se compone de 3 bolitas rojas y 3 bolitas verdes. Ya


resolvimos cómo hacerlo en otros ejercicios , hacer una guirnalda solo
requerirá combinar esas soluciones. Y ponerla donde corresponda, claro.

¿Y que más? el procedimiento que decore el tablero debería poder


aprovechar la creación de una guirnalda para usarla varias veces en las
posiciones que querramos decorar. Nos vendría muy bien alguna
primitiva que nos ayude a llegar a los bordes.

¡Manos a la obra!

Definí dos procedimientos: el procedimiento PonerGuirnalda que coloque 3 bolitas


rojas y 3 bolitas verdes en una celda y el procedimiento DecorarTablero que lo utilice y
ponga una guirnalda en cada esquina superior. Invocá DecorarTablero en el program.
Tené en cuenta que no sabemos la posición inicial donde se encontrará el cabezal.
¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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!

Ejercicio 14: Colores, colores, colores


Vamos a darle un poco más de color a todo esto haciendo líneas multicolores como esta:

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 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

Ejercicio 15: Cuadrado de colores


Vamos a crear un procedimiento que nos permita dibujar un tablero como este:

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

Definí un procedimiento DibujarCuadradoColorido que dibuje un cuadrado de 4×4 celdas en el


que cada celda tenga una bolita de cada color e invocalo en el program. El cabezal debe
quedar en la celda inicial.
¡Dame una pista!

En la Biblioteca tenés el procedimiento DibujarLineaColorida que hiciste en el ejercicio


anterior, ¡no tenés que volver a definirlo!
 Solución
 Biblioteca

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial
0 1 2 3

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.

Esta poderosa herramienta nos va a permitir reutilizar más código, ya


que al usar un procedimiento podremos descomponer un problema en
subproblemas más pequeños y manejables.

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

¿Notás qué es lo que se repite? Sí, estamos haciendo 5 veces lo mismo:


poner una bolita azul. Sin dudas, sería mucho más interesante que la
computadora hiciera eso por nosotros... ¡o si no te estaríamos mintiendo
con lo de automatizar!

En esta guía vamos a aprender cómo decirle a la computadora que repita


varias veces lo mismo, y también algunos trucos más.

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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?

Evidentemente tiene que haber una forma mejor de hacerlo, si no eso de


"automatizar tareas repetitivas" sería una mentira. Y bueno, de hecho la
hay: ¡vayamos al siguiente ejercicio!

Ejercicio 2: La computadora repite por nosotros


Como te adelantamos en el ejercicio anterior, en Gobstones existe una
forma de decir "quiero que estos comandos se repitan esta cantidad de
veces".

Entonces, cuando es necesario repetir un comando


(como Mover, Poner, DibujarLineaNegra, etc) un cierto número de veces, en
lugar de copiar y pegar como veníamos haciendo hasta ahora, podemos
utilizar la sentencia repeat.

Sabiendo esto, así es como quedaría MoverOeste10 usando repeat:

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Ahora sí se empieza a poner interesante esto de la programación.

Ejercicio 3: MoverOeste5 usando repeat


Llegó tu turno de nuevo: definí un procedimiento MoverOeste5 que se mueva 5 veces
al Oeste.
Obvio, esta vez tenés que usar repeat.

¡Dame una pista!

1
procedure MoverOeste5() {
2
repeat(5) {
3
Mover (Oeste)
4
}
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Como ya descubriste, el comando repeat consta básicamente de dos


elementos:

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.

Y un bloque de código, que va encerrado entre llaves ({}) y especifica


qué comandos se quieren repetir. Es MUY importante que no te los
olvides, porque sino la computadora no va a saber qué es lo que quisiste
repetir (y fallará).

Ejercicio 4: No todo es repetir


Los ejemplos que hiciste en los ejercicios anteriores se solucionaban simplemente
repitiendo cosas. Pero no todo es repetir, también podemos poner comandos
tanto antes como después del repeat, al igual que veníamos haciendo hasta ahora.
Por ejemplo, este es un programa que se mueve al Sur, luego pone 4 bolitas de
color Rojo y por último vuelve a moverse al Norte:

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:

Definí el procedimiento Poner3AlNoreste(), que ponga 3 bolitas negras en la primera celda al


Noreste del cabezal.
Inicial Final

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

¡Dame una pista!

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

¡Muy bien! Tu solución pasó todas las pruebas


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

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

Ejercicio 5: También vale después


Definí el procedimiento PonerAzulLejos, que coloque una bolita Azul 4 celdas hacia el
Este:
0 1 2 3 4

1 1

0 0

0 1 2 3 4

0 1 2 3 4

1
1 1

0 0

0 1 2 3 4

¡Dame una pista!

1
procedure PonerAzulLejos(){
2
repeat(4){
3
Mover(Este)
4
}
5
Poner(Azul)
6
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


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

0 0

0 1 2 3 4

Como ya experimentaste, pueden ponerse comandos tanto antes como


después del repeat. En definitiva... ¡es sólo un comando más!

Ejercicio 6: Repitiendo varios comandos


Hasta el momento los ejemplos que vimos sólo repetían un comando, pero como
mencionamos al comenzar es posible repetir cualquier secuencia de comandos - en
definitiva lo que se repite es un bloque y, como ya sabíamos, en un bloque puede haber
tantos comandos como se nos ocurra.

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.

Definí una versión superadora de DibujarLineaNegra6, esta vez usando repeat.


¡Dame una pista!

procedure DibujarLineaNegra6() {
2

repeat(6) {
3

Poner(Negro)
4

Mover(Este)
5

}
6

}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial
0 1 2 3 4 5 6

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

Ejercicio 7: ¿Dónde está el error?


Esta solución para LineaRoja4 no resuelve el problema como
esperábamos, mirá:

Tablero inicial Lo que hace Lo que esperábamos

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

¿Nos ayudás a corregirla? Te dejamos el código en el editor.


¡Dame una pista!
1
procedure LineaRoja4() {
2
repeat(4) {
3
Poner(Rojo)
4
Mover(Norte)
5
}
6
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

¡Bien, corregiste el error! No fue tan fácil de encontrar, ¿no? Ahora ya


sabemos que el orden dentro de un repeat también importa, y mucho.

Ejercicio 8: Diagonal con una bolita


Definí un procedimiento Diagonal4Azul que dibuje una diagonal de longitud 4 hacia el
Noreste, donde cada celda tenga una bolita azul. El cabezal debe quedar donde muestra la
imagen.
0 1 2 3 4

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

¡Muy bien! Tu solución pasó todas las pruebas


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

1
3 3

1
2 2
1
1 1

1
0 0

0 1 2 3 4

Ejercicio 9: Diagonal "pesada"


Ahora vamos a hacer lo mismo, pero en versión "pesada".

¿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

Definí un procedimiento DiagonalPesada4Azul que resuelva el problema.


¡Dame una pista!

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

Y, como realmente queremos que aprendas a dividir tu problema en


subtareas, es importante que en tu solución no anides estructuras de
repetición.
1
procedure BolasAzules() {
2
repeat(21){
3
Poner(Azul)
4
}
5
}
6
procedure DiagonalPesada4Azul() {
7
repeat(4){
8
BolasAzules()
9
Mover(Norte)
10
Mover(Este)
11
}
12
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Con el cabezal en el origen


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

21
3 3

21
2 2

21
1 1

21
0 0

0 1 2 3 4

 Con el cabezal desplazado


Tablero inicial

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

Muy bien. Aunque el repeat es poderoso y nos ayuda a escribir menos


código, sigue siendo igual de importante la división en subtareas.

¡No vale olvidarse de lo aprendido hasta ahora!

Ejercicio 10: El caso borde


Muchas veces cuando usamos un repeat nos encontramos con que el
último caso es levemente distinto a los anteriores, situación que solemos
llamar caso borde. Pero mejor, veamos un ejemplo.

El procedimiento LineaNegra4Este que te presentamos dibuja una línea


negra hacia el Este dejando el cabezal fuera de la línea, una celda hacia
el Este.

procedure LineaNegra4Este() {
repeat(4) {
Poner(Negro)
Mover(Este)
}
}

Si ahora queremos hacer que deje el cabezal en la última celda de la línea,


tenemos dos opciones:

 Mover el cabezal al Oeste luego de dibujar la línea. Un truco


medio feo, porque para funcionar necesita que haya al menos 5
espacios al Este de la posición inicial, cuando nuestra línea sólo
ocupará 4.
 Tratar el último caso de manera especial. Esta opción es más
interesante y más fiel a lo que queremos hacer: la última vez no
queremos que el cabezal se mueva, simplemente nos basta con
poner la bolita negra.

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!

Algunos ejercicios atrás comprobaste que se pueden poner cosas


tanto antes como después de un repeat. Podés usar esa misma idea para
tratar el último caso de manera especial, sacándolo del repeat.

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Con lugares de sobra


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
0 0

0 1 2 3 4

 Con el espacio justo


Tablero inicial

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

Siempre que tengas problemas como este vas a poder solucionarlos de la


misma manera: procesando el último caso por separado.

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

Por convención, vamos a preferir la forma que procesa distinto al último


caso, aunque a menudo ambas sean equivalentes (es decir, produzcan el
mismo resultado).

Ejercicio 11: De lado a lado, dibujamos un cuadrado


En el ejercicio anterior definimos el procedimiento LineaNegra4Este. Ahora vamos a
utilizarlo para dibujar un cuadrado negro igualito a los de los tableros de ejemplo:

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 Con lugares de sobra

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

 Con el espacio justo

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

¡Terminaste Repetición Simple!


En esta guía aprendiste algo muy importante: cómo hacer que la
computadora repita tareas, usando el comando repeat.

Con esta nueva herramienta ya podés empezar a construir programas


mucho más interesantes: recorrer un tablero de dimensiones conocidas,
poner o sacar muchas bolitas, parametrizar el dibujo de un cuadrado, etc.

¡Animate a pensar otros ejemplos!

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.

Ahora vamos a ver como podemos hacerlos más genéricos utilizando


parámetros.

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

Ejercicio 1: Pensando en subtareas


¡Queremos dibujar un nuevo cuadrado!

0 1 2

1 1 1
2 2

1 1 1
1 1

1 1 1
0 0

0 1 2

Dividiendo cada parte del problema en procedimientos más pequeños,


podemos plantear la siguiente estrategia: construir el cuadrado como
tres líneas de tres bolitas una encima de la otra. ¿A qué nos referimos con
una línea de tres bolitas? A esto:

0 1 2

2 2

1 1

1 1 1
0 0

0 1 2

¡Arranquemos por ahí!

Definí el procedimiento DibujarLineaNegra3 que, como su nombre lo indica, dibuje una


línea poniendo 3 bolitas negras consecutivas hacia el Este y dejando el cabezal
donde comenzó. Invocalo en un program.
En la Biblioteca vas a encontrar el procedimiento VolverAtras. ¡Eso significa que
podés invocarlo sin tener que definirlo!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de 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

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

¡Perfecto! Ya tenemos nuestra línea, ya vamos a poder hacer un cuadrado


negro.

Ejercicio 2: Dibujando un cuadrado con subtareas


¡Ya podemos dibujar nuestro cuadrado! El cual debería verse así:

0 1 2

1 1 1
2 2

1 1 1
1 1

1 1 1
0 0

0 1 2

El cabezal comienza en el origen, es decir, en el casillero de abajo a la


izquierda:

0 1 2

2 2

1 1

0 0

0 1 2

Definí el procedimiento DibujarCuadradoNegroDeLado3 que


invocando DibujarLineaNegra3 dibuje un cuadrado negro sobre el tablero. Invocalo en
un program.
¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de 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

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

¡Muy bien! Ya tenemos un cuadrado negro, pero también queremos


cuadrados de otros colores . Solucionemos esto haciendo nuevos
procedimientos.
Ejercicio 3: Color esperanza
Ya sabemos como dibujar una línea negra con 3 bolitas . Usemos esa
lógica para dibujar una línea verde.

Definí el procedimiento DibujarLineaVerde3 e invocalo en el program.


¡Dame una pista!

 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

Resultados de 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

¡Excelente! Pero todavía nos faltan dos colores más . Ya te imaginarás lo


que hay que hacer.

Ejercicio 4: Los que faltan


Solo nos faltan dos colores: Rojo y Azul .

Definí los procedimientos DibujarLineaRoja3 y DibujarLineaAzul3.

 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

¡Muy bien! Tu solución pasó todas las pruebas


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

¡Muy bien! Peeero se volvió medio repetitiva la tarea de dibujar 4


procedimientos casi iguales ¿no? Sólo cambiaba el color, y si a esto le
sumamos que además necesitamos un nuevo procedimiento por cada
cuadrado, ¡la cosa se pone cada vez más aburrida! . ¿Se podrá solucionar
de alguna manera?

Ejercicio 5: Procedimientos con agujeritos


¡Empecemos con algo fácil! Supongamos que tenemos un procedimiento
llamado Poner3Verdes, que pone 3 bolitas verdes en un casillero, y lo
queremos generalizar para que funcione con cualquier color que
queramos (pero uno solo por vez). Lo que necesitamos es agregarle al
procedimiento una especie de agujero...

procedure Poner3(color) {
repeat(3) {
Poner(color)
}
}

...que luego pueda ser completado con el color que queramos:

program {
Poner3(Negro)
Poner3(Rojo)
}

Escribí los códigos anteriores en el editor y fijate qué pasa.

1
procedure Poner3(color){
2
repeat(3){
3
Poner(color)
4
}
5
}
6
program {
7
Poner3(Negro)
8
Poner3(Rojo)
9
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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?

Con un mismo procedimiento pudimos hacer 2 cosas casi iguales; por


un lado pusimos 3 bolitas negras y por el otro 3 bolitas rojas. La
diferencia estuvo en cómo usamos Poner3: la primera vez completamos
el agujero con Negro y la segunda con Rojo.

Ejercicio 6: Llenando los espacios vacíos


Entendamos qué acabamos de hacer.

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

...lo que se ejecuta es:

Poner(Negro)
Poner(Negro)
Poner(Negro)

Y si lo invocamos así...

program {
Poner3(Rojo)
}

lo que se ejecuta es:

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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!

Ya hicimos cuatro procedimientos para dibujar líneas de cada color, pero


si usamos parámetros podría ser sólo uno.

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 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

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

En vez de escribir color podríamos haber escrito c, col o incluso pepe,


porque a la computadora no le importa el nombre que le demos a las
cosas... pero a nosotros sí (y mucho ), así que por eso elegimos usar
nombres que expresen bien lo que queremos decir.

Fijate también que elegimos un nuevo nombre para nuestro nuevo


procedimiento porque ahora sirve para cualquier color. Esto tampoco es
estrictamente necesario para la computadora, pero es super importante
para los humanos que van a leer y escribir el código. Imaginate que si le
pusieramos DibujarLineaNegra3 (o DibujarLineaAzul3) al usarlo para dibujar
una línea roja quedaría DibujarLineaNegra3(Rojo). Si bien va a funcionar, no
se entendería bien qué es lo que hace: ¿una línea negra? ¿una línea roja?
¿una línea negra y roja?.

¡Es importantísimo poner buenos nombres para programar bien!

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.

Invocando DibujarLinea3, definí el procedimiento DibujarCuadradoDeLado3 que recibe


un color y dibuja un cuadrado de 3x3 de ese color.
¡Dame una pista!
 Solución
 Biblioteca

1
procedure DibujarCuadradoDeLado3(color) {
2
repeat(2){
3
DibujarLinea3(color)
4
Mover(Norte)
5
}
6
DibujarLinea3(color)
7
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 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

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

Genial, ¡logramos crear un procedimiento que nos sirve para cualquier


color!

Un procedimiento puede no tener parámetros (como pasa


en VolverAtras o DibujarLineaNegra3) o un parámetro
(como Mover, Poner o DibujarLinea3), pero ¿puede tener más de uno?

Ejercicio 9: Pasando varios parámetros


¿Y si queremos que DibujarLinea3 sirva también para dibujar líneas en
cualquier dirección? Sin dudas tenemos que decirle al procedimiento,
además del color, en qué direccion debe dibujar la línea; y para eso vamos a
necesitar un nuevo parámetro . Por suerte, ¡los procedimientos también
pueden tener más de un parámetro!

¿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:

procedure DibujarLinea3(color, direccion) {


Poner(color)
Mover(direccion)
Poner(color)
Mover(direccion)
Poner(color)
}

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

No te preocupes por la posición final del cabezal.


¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial
0 1 2 3

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

Como habrás notado, al usar los procedimientos debemos darle un valor


a cada uno de sus parámetros respetando el orden en que fueron
definidos.

A estos valores concretos que usamos cuando invocamos a un


procedimiento los llamamos argumentos.

Ejercicio 10: La ley, el orden y el BOOM


Recién te decíamos que el orden en que pasabamos los argumentos era
importante pero nunca te dijimos por qué . ¡Vamos a verlo!

Creá un programa cualquiera que invoque DibujarLinea3, pero esta vez intentá
invocarlo con los argumentos invertidos.
¡Dame una pista!

Con parámetros invertidos nos referimos a que primero pases la dirección


y después el color.
 Solución
 Biblioteca

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

¡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

[11:3]: El parámetro de "Poner" debería ser un color pero es una dirección.

Ok, hizo BOOM , pero ¿qué quiere decir eso de El parámetro de Poner debería
ser un color?

Al pasar los argumentos al revés, donde se esperaba un color llegó una


dirección; entonces cuando intentamos Poner una dirección provocamos la
autodestrucción del cabezal . Poner(Norte) o Poner(Este) no se pueden
ejecutar porque no tienen ningún sentido.

Ejercicio 11: Un argumento para dos parámetros


Ya vimos que pasa cuando pasamos los argumentos desordenados pero
vamos a hacer un experimento más . ¿Qué crees que va a pasar si a un
procedimiento le pasamos menos argumentos de los que necesita?

Creá un programa que invoque a DibujarLinea3 pero pasándole sólo un argumento.

 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

[2:3]: El procedimiento "DibujarLinea3" espera recibir 2 parámetros pero se lo invoca con un


argumento.

¡BOOM de nuevo ! Como te imaginarás, si le pasamos más argumentos


de los que espera pasará lo mismo.

Entonces es importante recordar que al invocar un procedimiento no


debemos:

 pasarle menos o más argumentos de los que necesita;


 pasarle los argumentos en un orden diferente al que espera.

Ejercicio 12: La tercera es la vencida


Para terminar esta lección vamos a definir un procedimiento llamado Triada ¡que recibe
tres parámetros!

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.

Por ejemplo: Triada(Rojo, Azul, Verde) nos da como tablero resultante:

0 1 2

1
0 0
1 1

0 1 2

mientras que Triada(Azul, Verde, Rojo):


0 1 2

1
0 0
1 1

0 1 2

Definí el procedimiento Triada.


¡Dame una pista!

Los nombres de los parámetros elegilos vos, pero mucho cuidado: no pueden repetirse,
tenés que pensar tres nombres diferentes.

procedure Triada(colora, colore, colorete){


2

Poner(colora)
3

Mover(Este)
4

Poner(colore)
5

Mover(Este)
6

Poner(colorete)
7

}
8

Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 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!

En esta lección aprendimos como los parámetros facilitan nuestra tarea


permitiéndonos crear procedimientos más genéricos. Cuidado al invocar
estos procedimientos, ¡acordate que la cantidad de argumentos y su
orden importa! Los nombres también pero para las personas, no para las
computadoras.

Práctica Repetición simple


Ahora que ya sabés cómo repetir tareas, vamos a combinar eso con
procedimientos y parámetros para solucionar problemas más complejos.

Además, vamos a ir introduciendo algunos temas nuevos en el camino...


¡No te los pierdas!
Objetivos

 Vamos a aprender qué son las expresiones más sencillas (¿sabías


que Azul es una expresión?)
 Vamos a empezar a reutilizar el código que ya escribimos. Recordá
lo que dijo un sabio: "Cada vez que alguien repite código, se muere
un gatito"
 Profundizaremos el uso de parámetros.
 Vamos a encontrar patrones que se repiten y aprenderemos a
utilizarlos.
 Comenzaremos a usar bolitas para representar información. Es
decir, vamos a darle un pequeño dominio a nuestros problemas,
usando las bolitas para representar otra cosa: personas, autos,
flores, ¡lo que se te ocurra!

Ejercicios

 1. Entrando en calor... ¡Volviendo!


 2. Una diagonal más ancha
 3. Pongamos... ¡Todo lo que queramos!
 4. Día de la Memoria
 5. Escribir cualquier fecha
 6. Movamos... ¡Todo lo que queramos!
 7. Los números del reloj
 8. Una línea heavy
 9. Guarda con la guarda
 10. Una guarda en L

¡Comenzá esta lección!

Ejercicio 1: Entrando en calor... ¡Volviendo!


En la guía anterior, vimos que se podía usar repeat para hacer algo muchas
veces. Hicimos un ejemplo que se llamaba Diagonal4Azul, que era más o
menos así:

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

¡Muy bien! Tu solución pasó todas las pruebas


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

1
3 3

1
2 2

1
1 1

1
0 0

0 1 2 3 4

¡Bien!

Tenés que acostumbrarte a pensar... ¿No podría usar algún procedimiento


que ya definí antes?
Una gran ventaja de los procedimientos es que, una vez que están
escritos, podés guardártelos para volver a usarlos. Si ahora los necesitás
en algún ejercicio vas a notar que ya los guardamos por vos y te
dejamos la Biblioteca lista para usar, pero en la vida real ese trabajo vas a
tener que hacerlo vos.

Ejercicio 2: Una diagonal más ancha


Sigamos probando tus habilidades para reutilizar...

Ahora, tenés que hacer este dibujo:

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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

Ejercicio 3: Pongamos... ¡Todo lo que queramos!


Ahora que tenemos una idea de reutilización, y practicamos repetición,
vamos a definir un procedimiento que nos va a servir de acá en
adelante.

Necesitamos un procedimiento que nos ayude a poner muchas bolitas. Sí,


podríamos simplemente usar un repeat para lograrlo, pero como es una
tarea re-común que vamos a hacer un montón de veces, vamos a preferir
definir un procedure llamado PonerN. Nuestro procedimiento debe poner la
cantidad de bolitas indicada de un color dado.

Por ejemplo, PonerN(3, Azul) haría esto:

0 1

1 1

3
0 0

0 1

Definí el procedimiento PonerN(cantidad, color).


1
procedure PonerN(cantidad, color){
2
repeat(cantidad){
3
Poner(color)
4
}
5
}
6

Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 Tablero inicial

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

Aunque quizás no veas todavía la utilidad de este procedure que creamos,


te contamos dos aspectos que es importante tener en cuenta al
programar:

 reutilización de código: como poner muchas bolitas es una tarea


común, está bueno tener un procedimiento que lo resuelva: lo
escribimos una vez y lo usamos para siempre;
 declaratividad: cuando tengamos que resolver un problema más
complejo, tener este procedimiento nos va a ayudar a pensar a más
alto nivel, ya que no vamos a tener que preocuparnos
por cómo poner muchas bolitas sino en qué queremos construir
con ellas.

Ejercicio 4: Día de la Memoria


Muchas veces vamos a usar el tablero de Gobstones como memoria, o
sea, para recordar algo importante que vamos a necesitar más adelante.

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

El objetivo, entonces, es definir un procedimiento DiaDeLaMemoria():

 En la celda actual, poné 24 bolitas Azules, que representan el día.


 En la celda inmediatamente al Este, poné 3 bolitas Verdes,
que representan el mes.
 En la celda a continuación, poné 1976 bolitas Negras, representando el año.

0 1 2

24 *
0 0
3

0 1 2

¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

0 1 2

0 0

0 1 2
Tablero final

0 1 2

24 *
0 0
3

0 1 2

¿Sabías que Azul es una expresión literal? ¡También 1976! También


son expresiones literales: Verde, Negro, 3 y 24.

Cuando usamos un procedimiento que tiene parámetros como


PonerN, PonerN(56, Rojo) tenemos que enviarle valores como argumento. ¡Y
las expresiones sirven para eso!

Ejercicio 5: Escribir cualquier fecha


Ahora que ya escribimos una fecha particular, hagamos un procedimiento
que sirva para escribir cualquier fecha.

Definí el procedimiento Fecha(dia, mes, anio), que recibe los tres


valores correspondientes, y escribe la fecha que representan, de esta manera:

 En la celda actual, tantas bolitas azules para representar el día.


 En la celda inmediatamente al Este, tantas bolitas Verdes
para representar el mes.
 En la celda a continuación, tantas bolitas Negras para representar el año.

Por ejemplo, Fecha(12, 8, 1990) produciría algo así:

0 1 2

12 *
0 0
8

0 1 2

¡Dame una pista!

¡Podés resolverlo muy parecido a como lo resolviste en el ejercicio


anterior!

Recorda que el día, mes y año representan la cantidad de bolitas azules,


verdes y negras que hay que poner respectivamente.

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 Tablero inicial

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

Dos cuestiones teóricas para pensar de este ejercicio:

1. Puede parecerte que estás repitiendo código con el ejercicio


anterior. ¡Es cierto! Para arreglarlo, deberías volver al ejercicio
anterior y allí usar el procedimiento Fecha.
2. Acá vemos que hay otro tipo de expresiones: ¡Los parámetros!
Al usar un procedimiento, puedo enviarle tanto otros parámetros
como literales: PonerN(dia, Azul). Recordá en este caso que los
nombes de los parámetros sólo nos sirven a los humanos, para la
máquina sólo importa el orden.

Ejercicio 6: Movamos... ¡Todo lo que queramos!


Definí un procedimiento MoverN(cantidad, direccion) que haga que el cabezal se
desplace la cantidad especificada de veces en la dirección indicada.
Por ejemplo, MoverN(3, Oeste) provocaría:

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!

¡Es muy parecido al PonerN que hicimos hace poco!

procedure PonerN(cantidad,color){
repeat(cantidad){
Poner(color)
}
}

1
procedure MoverN(cantidad, direccion) {
2
repeat(cantidad){
3
Mover(direccion)
4
}
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 Tablero inicial

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)

Ejercicio 7: Los números del reloj


¡Ya sabés Kung Fu!

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

El reloj resultante es así:

0 1 2 3 4

4 4
12

3 3

2 2
9 3

1 1

0 0
6

0 1 2 3 4

¡Dame una pista!

¡Dividí en subtareas!

No vale hacer un procedimiento que sea un choclo, con muchos


comandos uno abajo del otro, tiene que ser legible y cortito.

Pensá como combinar PonerN y MoverN, los cuales podés encontrar en la


siempre útil Biblioteca.

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 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
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

¿Te fijaste? Estamos usando bolitas para representar la hora de un reloj. Al


programar, usamos las abstracciones que tenemos para modelar cosas del
mundo real.

Y como siempre, es muy importante dividir el problema en subtareas. Y


si puedo no repetir código, ¡Aún mejor!

Antes de pasar al siguiente ejercicio preguntate: ¿repetí código?

Ejercicio 8: Una línea heavy


El procedimiento LineaEstePesada(peso, color, longitud) debe dibujar hacia
el Este una línea del color dado, poniendo en cada celda tantas bolitas
como indique el peso. La linea debe ser tan larga como la longitud.

A modo de ejemplo, LineaEstePesada(3, Verde, 5) debería dibujar una línea


verde, ocupando cinco celdas hacia el Este y poniendo tres bolitas en
cada una de ellas:

0 1 2 3 4 5

1 1

0 0
3 3 3 3 3

0 1 2 3 4 5

Definí el procedimiento LineaEstePesada(peso, color, longitud). Tené en cuenta que el


cabezal debe regresar a la posición inicial. Para eso vas a tener que
invocar MoverN.

 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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

¿Viste que se pueden reusar MoverN y PonerN en varios lugares?

¡Son muy útiles!

Ejercicio 9: Guarda con la guarda


Bueno, estamos en tiempo para algún ejercicio integrador...

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

¡Dame una pista!

No te olvides de dividir en subtareas y además de considerar el caso


borde.

¡A no repetir código! Cada azulejo puede resolverse con un


procedimiento...

 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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

¡Bien! Recordaste cómo considerar el caso borde.

Además, en este ejercicio hay que dividir en subtareas para evitar la


repetición de código. Esto es muy importante a la hora de programar.
¡Asegurate que tu solución no repita código!

Ejercicio 10: Una guarda en L


Definí un procedimiento GuardaEnL() que haga una guarda en L como muestra la figura,
pero dejando el cabezal en la posición inicial.
0 1 2

2 2
9 1

1 1
9 1

5 5 5

0 0
9 1 9 1 9 1

0 1 2

La ventaja ahora, es que te regalamos el procedimiento PonerAzulejo. ¡Pero ojo que


necesitás dividir en más subtareas!

¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas


Tablero inicial

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

¡Terminaste Práctica Repetición simple!


¡Muy bien!

En esta guía:

 Reusaste procedimientos definidos anteriormente.


 Usaste repetición.
 Consideraste los casos borde.
 Hiciste un repaso grande de parámetros.
 ¡Evitaste repetir código!
 Empezaste a usar las bolitas para representar varios dominios:
Fechas, Relojes y Guardas.
 Aprendiste que los literales y los parámetros son expresiones que
se pueden pasar por argumento a los procedimientos.

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?

Todo eso y (no) mucho más en esta nueva entrega de "aprendiendo a


programar con bolitas de colores". ¡Arrancamos!

Ejercicios

 1. Muchas formas de decir lo mismo


 2. La suma de las partes
 3. ¿Qué se hace antes?
 4. La carrera del salmón
 5. Dos pasos adelante, un paso atrás
 6. Poner al lado
 7. La línea que vuelve
 8. Dibujando una L
 9. Previo a lo siguiente
 10. Siga la flecha
 11. Copiando bolitas
 12. Sacando bolitas

¡Comenzá esta lección!

Ejercicio 1: Muchas formas de decir lo mismo


Cuando nos comunicamos con alguien más, usamos palabras o frases
para describir una idea. Por ejemplo, todas las
siguientes expresiones hablan de lo mismo, aunque lo hacen de distintas
formas:

 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

Algunas variantes válidas:

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

Ejercicio 2: La suma de las partes


Juguemos un poco más con esto de hacer cuentas.

Definí un procedimiento PonerSuma(x, y) que reciba dos parámetros y ponga la


cantidad de bolitas rojas que surge de sumar x e y.
Ejemplo: PonerSuma(4, 2) debería poner 6 bolitas rojas en la celda actual
(porque 6 es el resultado de sumar 4 y 2).

0 1

1 1

0 0
6

0 1

 Solución
 Biblioteca

1
procedure PonerSuma(x, y) {
2
PonerN(x+y,Rojo)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

Como ya descubriste, podemos escribir expresiones aritméticas (o sea,


cuentas matemáticas) en los mismos lugares donde hasta ahora veníamos
escribiendo números.

Ejercicio 3: ¿Qué se hace antes?


De un conocido diario (no podemos revelar su nombre por temas de
confidencialidad) nos pidieron definir un procedimiento para contar,
aproximadamente, cuánta gente asistió a una determinada movilización.

Contamos con la información de cuántos micros, autos y bicicletas


asistieron y desde allí podemos hacer un cálculo siguiendo estas reglas:

 en cada micro viajan 40 personas;


 en cada auto viajan 4 personas;
 en cada bicicleta viaja 1 persona.

Definí el procedimiento ContarGente(micros, autos, bicicletas) que a partir de la cantida de


micros, autos y bicicletas que recibe como parámetro, haga las cuentas necesarias y
refleje el resultado con bolitas de color verde.
Te dejamos un par de ejemplos que te pueden ayudar:

 ContarGente(1, 1, 1) generaría este tablero:

0 1

1 1
0 0
45

0 1

 ContarGente(1, 2, 3) generaría este tablero:

0 1

1 1

0 0
51

0 1

¡Dame una pista!

 Solución
 Biblioteca

1
procedure ContarGente(micros, autos, bicicletas) {
2
PonerN (micros*40+autos*4+bicicletas*1, Verde)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

En Gobstones, como en la matemática, existe la idea de precedencia de


operadores. En criollo, esto quiere decir que hay ciertas operaciones que
se hacen antes que otras, sin la necesidad de usar paréntesis para ello. En
particular, el orden es: primero las multiplicaciones y divisiones, luego las
sumas y las restas (de nuevo, como en matemática).

Por lo tanto, la expresión (10 * 4) + (8 * 7) es equivalente a 10 * 4 + 8 * 7.

Ejercicio 4: La carrera del salmón


Bueno, basta de números (por un ratito). Ahora vamos a aprender a hacer
"cuentas" con las direcciones.

Para hacer esto, simularemos el movimiento de un salmón: en contra de


la corriente. Nuestro objetivo será definir un
procedimiento MoverComoSalmon(direccion) que reciba una dirección y se
mueva exactamente una vez en la dirección opuesta. Veamos en una
tabla cómo debería comportarse este procedimiento:

 MoverComoSalmon(Norte) se mueve hacia el Sur.


 MoverComoSalmon(Este) se mueve hacia el Oeste.
 MoverComoSalmon(Sur) se mueve hacia el Norte.
 MoverComoSalmon(Oeste) se mueve hacia el Este.

Como la dirección va a ser un parámetro de nuestro procedimiento,


necesitamos una forma de decir "la dirección opuesta a X" para poder
luego usar esto como argumento de Mover. Gobstones nos provee un
mecanismo para hacer esto, la primitiva opuesto(dir). En criollo: opuesto (¡sí,
en minúsculas!) nos dice la dirección contraria a la dir que nosotros le
pasemos.

Sabiendo esto, podríamos definir fácilmente el procedimiento que


queríamos:

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 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

Las expresiones no sólo pueden denotar números, también nos sirven


para realizar transformaciones sobre direcciones. Más sobre esto en los
próximos ejercicios.

Ejercicio 5: Dos pasos adelante, un paso atrás


Tenemos un amigo llamado Carlos, que es bastante desconfiado. En su
vida, eso se manifiesta en muchos aspectos, pero el más notorio es su
forma de caminar: sólo camina hacia el Este y siempre que da dos pasos
hacia adelante automáticamente da un paso hacia atrás.
Por ejemplo, si le pidiéramos que diera 2 pasos, terminaría dando 1; si le
pidiéramos 4, daría 2; y así sucesivamente. En definitiva, lo que termina
pasando es que nuestro amigo da la mitad de los pasos que le pedimos.

Importante: en Gobstones usamos el operador div para dividir; por


ejemplo "4 dividido 2" se escribe 4 div 2.

Definí el procedimiento CaminarDesconfiado(pasos) que simule el caminar de Carlos:


debe recibir la cantidad de pasos que debería dar y recorrer la mitad. Siempre se
mueve al Este.
¡Dame una pista!

 Solución
 Biblioteca

1
procedure CaminarDesconfiado(pasos) {
2
MoverN(pasos div 2, Este)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

Sobre el ejemplo de 4 pasos, no hay dudas: Carlos dio 2 pasos. Ahora,


cuando le pedimos que diera 7, ¿por qué dio 3?

En Gobstones, la división es entera: se ignoran los decimales. De esta


forma, 7 div 2 termina dando 3 en vez de 3.5.

Ejercicio 6: Poner al lado


Para ver si entendiste lo anterior, te toca ahora resolver por tu cuenta.

Queremos definir un procedimiento que nos sirva para poner una


bolita al lado de donde se encuentre el cabezal, dejándolo en la posición
original. Por ejemplo, al invocar PonerAl(Norte, Verde) debería poner una
bolita verde una posición hacia el Norte, sin mover el cabezal (bueno, ya
sabemos que en realidad sí se mueve, pero el punto es que en
el resultado final esto no se tiene que ver).

Inicial Final

0 1
0 1

1 1 1 1
1

0 0
0 0

0 1
0 1

Definí el procedimiento PonerAl(direccion, color).


¡Dame una pista!
1
procedure PonerAl(direccion, color) {
2
Mover(direccion)
3
Poner(color)
4
Mover(opuesto(direccion))
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 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

Tanto opuesto(dir) como otras herramientas que veremos más adelante


forman parte de lo que conocemos como funciones y, como las
expresiones aritméticas que ya vimos, se pueden usar en cualquier lugar
donde hasta ahora poníamos valores o argumentos.

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.

Ejercicio 7: La línea que vuelve


Ahora que sabés usar la función opuesto, podemos finalmente resolver el problema de
definir un procedimiento que dibuje una línea en cualquier dirección y deje el cabezal
en la posición inicial.

La versión que sabíamos hacer hasta ahora era esta:

procedure Linea(direccion, color, longitud) {


repeat(longitud) {
Poner(color)
Mover(direccion)
}
}

Valiéndote de tus nuevos conocimientos sobre expresiones, modificá el


procedimiento Linea para que el cabezal quede en el lugar donde empezó.
¡Dame una pista!

 Solución
 Biblioteca
1

procedure Linea(direccion, color, longitud) {


2

repeat(longitud) {
3

Poner(color)
4

Mover(direccion)
5

}
6

MoverN(longitud, opuesto(direccion))
7

}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 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

Ejercicio 8: Dibujando una L


Nuestro objetivo en este ejercicio será definir un procedimiento capaz de dibujar una
letra L de color Azul, pero con la posibilidad de elegir hacia dónde está orientada. A
continuación, algunos ejemplos de cómo debería comportarse:

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:

Descubrí cuál de las funciones nuevas tenés que invocar y definí el


procedimiento Ele(direccion). No te preocupes por la posición inicial del cabezal, nosotros
nos encargaremos de ubicarlo en el lugar correspondiente para que la L se pueda dibujar.
¡Dame una pista!

 Solución
 Biblioteca

1
procedure Ele(direccion) {
2

Linea(direccion, Azul, 3)
3

Linea(siguiente(direccion),Azul,3)
4

}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 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

Ejercicio 10: Siga la flecha


Ya vimos distintas funciones que a partir de una dirección nos permiten obtener otra
distintas.

Como siempre en programación, lo interesante es combinar nuestras herramientas para


lograr nuevos objetivos . Por ejemplo podemos dibujar flechas en una dirección
determinada de la siguiente forma:

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 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?

Miremos algunos ejemplos:

 Si hay 4 bolitas verdes, hay que poner 4 bolitas rojas.


 Si hay 2 bolitas verdes, hay que poner 2 bolitas rojas.
 Si no hay bolitas verdes, no hay que poner ninguna roja.

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.

Invocando nroBolitas, definí el procedimiento CopiarVerdesEnRojas.


¡Dame una pista!

 Solución
 Biblioteca

1
procedure CopiarVerdesEnRojas() {
2
PonerN(nroBolitas(Verde), Rojo)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:


 Si no hay verdes, no hace nada
Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

 Si hay 2 verdes, pone 2 rojas


Tablero inicial

0 1

1 1

0 0
2

0 1

Tablero final

0 1

1 1

0 0
2 2

0 1

 Si hay 7 verdes, pone 7 rojas


Tablero inicial
0 1

1 1

0 0
7

0 1

Tablero final

0 1

1 1

0 0
7 7

0 1

En este ejercicio, además de aprender una expresión nueva, hiciste algo


que nunca habías hecho hasta ahora: un programa cuyo efecto depende
del estado del tablero inicial.

¿Qué quiere decir esto? Que el código de CopiarVerdesEnRojas() se


comporta diferente dependiendo de cómo estaba el tablero antes de
ejecutarlo.

Ejercicio 12: Sacando bolitas


Siguiendo con esto de contar las bolitas, te toca ahora definir un procedimiento que
sirva para sacar todas las bolitas de un color.

Pensemos las subtareas necesarias:

1. Poder sacar muchas bolitas: ya está resuelto con SacarN.


2. Contar cuántas bolitas hay que sacar: se puede hacer con nroBolitas.
3. Sacar todas las bolitas de un color: hay que combinar las 2 anteriores.

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

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

En el camino, conociste unas cuantas expresiones nuevas:

 Aritméticas: +, -, *, div.
 De direcciones: opuesto, siguiente, previo.
 Númericas: nroBolitas.

Y de yapa, también te adentraste un poquito en el arte de los programas


que hacen cosas distintas según el tablero que haya.

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.

¿Y cómo haremos esto? Utilizando la capacidad de la computadora


para decidir: la alternativa condicional o sentencia if.

Ejercicios

 1. Sacar con miedo


 2. Sacar con miedo, segundo intento
 3. Eliminando la bolita roja
 4. Un ejemplo medio rebuscado
 5. ¿Y sólo sirve para ver si hay bolitas?
 6. Un poquito de matemática
 7. Cómo decirle que no...
 8. Dos caminos distintos
 9. Un tablero de luces

¡Comenzá esta lección!

Ejercicio 1: Sacar con miedo


Vamos a definir un procedimiento que saque una bolita azul "con miedo":
no tiene que producirse un BOOM, aún cuando no haya ninguna bolita en
la celda actual.

Con lo que sabés hasta ahora, probablemente tu primera idea sea hacer
algo como esto:

procedure SacarAzulConMiedo() {
Sacar(Azul)
}

¡Probalo! Copiá el código anterior en el editor y apretá Enviar.

1
procedure SacarAzulConMiedo() {
2
Sacar(Azul)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Cuando hay una bolita azul, la saca


Tablero inicial

0 1

1 1

1
0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

 Cuando no hay ninguna bolita azul, hace BOOM


Tablero inicial

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.

¿Te diste cuenta qué pasó?

Funcionó para el primer tablero porque tenía una bolita azul, pero
hizo BOOM para el segundo porque estaba vacío, claro.

Ejercicio 2: Sacar con miedo, segundo intento


Ahora probá esta segunda versión que agrega una alternativa
condicional. No te preocupes por la sintaxis, ya te lo vamos a explicar.

procedure SacarAzulConMiedo() {
if (hayBolitas(Azul)) {
Sacar(Azul)
}
}

Copiá el código anterior en el editor y apretá Enviar.

1
procedure SacarAzulConMiedo() {
2
if (hayBolitas(Azul)) {
3
Sacar(Azul)
4
}
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Cuando hay una bolita azul, la saca


Tablero inicial

0 1

1 1

1
0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

 Cuando no hay ninguna bolita azul, no hace nada


Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

¡Bien!

Hiciste tu primer procedimiento que decide antes de ejecutar. Seguí con


nosotros para entender de qué se trata esto...
Ejercicio 3: Eliminando la bolita roja
Analicemos el procedimiento del ejercicio anterior:

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 Cuando hay una bolita roja, la saca

Tablero inicial

0 1
1 1

0 0
1

0 1

Tablero final

0 1

1 1

0 0

0 1

 Cuando hay más de una bolita roja, saca una

Tablero inicial

0 1

1 1

0 0
4

0 1

Tablero final

0 1

1 1

0 0
3

0 1

 Cuando no hay ninguna bolita roja, no hace nada

Tablero inicial

0 1

1 1
0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

Ejercicio 4: Un ejemplo medio rebuscado


Vamos a ponerle nombre a las partes del if.

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.

Para ejercitar esto ultimo, te vamos a pedir que definas un


procedimiento CompletarCelda() que, si ya hay alguna bolita negra, complete la celda
poniendo una roja, una azul y una verde.
¡Dame una pista!

procedure CompletarCelda() {
2

if (hayBolitas(Negro)) {
3

Poner(Azul)
4

Poner(Rojo)
5
Poner(Verde)
6

}
7

}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 Cuando hay alguna bolita negra, completa la celda

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

 Cuando no hay ninguna bolita negra, no hace nada

Tablero inicial

0 1

1 1

0 0
1

0 1

Tablero final
0 1

1 1

0 0
1

0 1

Ejercicio 5: ¿Y sólo sirve para ver si hay bolitas?


Claro que no, ¡por suerte!

La condición puede ser cualquier expresión booleana. En criollo: cualquier


cosa que represente una "pregunta" que se pueda responder con sí o no.
En Gobstones el sí se representa con el valor True (Verdadero en
castellano) y el no con el valor False (Falso en castellano).

En los ejercicios anteriores te mostramos una de las expresiones que trae


Gobstones, hayBolitas(color), que recibe un color y retorna True o False.

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.

Por ejemplo, si tenemos este tablero:

0 1

2 2

1 1

0 0

0 1

 puedeMover(Norte) será True.


 puedeMover(Sur) será True.
 puedeMover(Este) será True.
 Pero puedeMover(Oeste) será False

Creá un programa que se mueva al Este sólo si es posible. Recordá


utilizar puedeMover(direccion).
¡Dame una pista!
1
program {
2
if (puedeMover(Este)) {
3
Mover(Este)
4
}
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si hay celdas al Este, se mueve


Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

 Si no hay celdas al Este, no hace nada


Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

¿Y si hubieramos querido movernos hacia el Norte en caso de


que no hubiera celdas al Este?

Ejercicio 6: Un poquito de matemática


Otra cosa que se puede hacer adentro de un if es comparar números, como seguramente
alguna vez hiciste en matemática.

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

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 Si hay menos de 5 bolitas negras, agrega una

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

 Si hay más de 5 bolitas negras, no hace nada

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

Ejercicio 7: Cómo decirle que no...


En todos los problemas que hicimos hasta ahora, siempre preguntamos si
una cierta condición se cumplía: ¿hay alguna bolita roja? ¿me puedo
mover al Este? ¿hay más de 3 bolitas azules?

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?

¿Y cómo se hace en Gobstones? Fácil, se agrega la palabra clave not antes


de la expresión que ya teníamos.

Original Negada

hayBolitas(Rojo) not hayBolitas(Rojo)

puedeMover(Este) not puedeMover(Este)

nroBolitas(Azul) > 3 not nroBolitas(Azul) > 3

Definí un procedimiento AsegurarUnaBolitaVerde() que se asegure que en la celda


actual hay al menos una bolita verde. Esto es: si ya hay bolitas verdes no hay que
hacer nada, pero si no hay tendría que poner una.

1
procedure AsegurarUnaBolitaVerde() {
2
if (not hayBolitas(Verde)) {
3
Poner(Verde)
4
}
5
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si hay bolitas verdes, no hace nada


Tablero inicial

0 1

1 1

0 0
1

0 1

Tablero final

0 1

1 1

0 0
1

0 1

 Si no hay bolitas verdes, agrega una


Tablero inicial

0 1

1 1

0 0
0 1

Tablero final

0 1

1 1

0 0
1

0 1

A lo que acabás de hacer, en lógica se lo llama negación y al anteponer


el not decimos que se está negando una expresión. Cualquier expresión
booleana (o sea, que devuelve True o False) se puede negar.

Ejercicio 8: Dos caminos distintos


En lo cotidiano, se presentan muchas situaciones donde debemos elegir
entre dos acciones diferentes, dependiendo de si se cumple una cierta
condición o no.

 Si la remera está limpia me la pongo, si no la lavo.


 Si tengo aceite para freir las milanesas lo uso, si no le pongo un
poco de manteca.
 Si me puedo mover al Este lo hago, si no me muevo al Norte.

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.

Supongamos que queremos definir un procedimiento que se mueva al


Oeste y, en caso de que no pueda, lo haga hacia el Norte. Haciendo uso
del else, podemos definirlo de la siguiente manera:

procedure MoverComoSea() {
if (puedeMover(Oeste)) {
Mover(Oeste)
} else {
Mover(Norte)
}
}

Escribí ese código en el editor y fijate cómo resuelve el problema.


1
procedure MoverComoSea() {
2
if (puedeMover(Oeste)) {
3
Mover(Oeste)
4
} else {
5
Mover(Norte)
6
}
7
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si hay celdas al Oeste, se mueve


Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1
0 0

0 1

 Si no hay celdas al Oeste, se mueve al Norte


Tablero inicial

0 1

1 1

0 0

0 1

Tablero final

0 1

1 1

0 0

0 1

¡Espectacular!

Ya conocés la herramienta que usan todas las aplicaciones que conociste


en tu vida para decidir qué hacer, el viejo y querido if / if...else.

Ejercicio 9: Un tablero de luces


Como ejemplo final, imaginemos que nuestro tablero está lleno de luces
que están prendidas o apagadas. Vamos a decir que las celdas con una
bolita verde están prendidas y las celdas con una bolita negra están
apagadas.

Definí un procedimiento PrenderOApagarLuz() que se encargue de prender las luces


que estén apagadas o apagar las luces encendidas, según corresponda. Tené en
cuenta que en cada celda solo puede haber bolitas de color verde o negro.
¡Dame una pista!
1
procedure PrenderOApagarLuz() {
2
if (hayBolitas(Verde)) {
3
Sacar(Verde)
4
Poner(Negro)
5
} else {
6
Sacar(Negro)
7
Poner(Verde)
8
}
9
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si la celda está apagada, la prende


Tablero inicial

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

 Si la celda está prendida, la apaga


Tablero inicial

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

¡Terminaste Alternativa Condicional!


Ahora conocés una de las herramientas más poderosas que tiene la
computación: la alternativa condicional. Aunque parezca algo sencillo,
esto es lo que permite que los programas puedan reaccionar diferente
ante distintos estímulos, dando lugar así a que las computadoras
puedan tomar decisiones.

Algunos ejemplos de esto:

 en las redes sociales, probablemente exista un if que determine si


podés ver el perfil de alguien o no;
 cuando te tomás un colectivo y pagás con la SUBE (o tarjetas
similares), la máquina decide si podés viajar o no dependiendo de
si te alcanza el saldo.

Te dejamos como ejercicio pensar (y por qué no intentar escribirlas) qué


partes de los sistemas con los que interactuás todos los días parecerían
estar resueltas con un if.

Funciones
Cuando introdujimos la noción de procedimientos, dijimos que:

 son una forma de darle nombre a un grupo de comandos,


logrando así que nuestros programas fueran más entendibles;
 nos posiblitan la división en subtareas: para resolver un problema
grande, basta con dividirlo en problemas más chicos y luego
combinarlos;
 nos ayudan a no repetir código, no volver a escribir lo mismo
muchas veces.

Al trabajar con expresiones complejas, rápidamente surge la necesidad de


contar con un mecanismo similar, por los motivos que acabamos de
esbozar.

¿Querés saber cuál es ese mecanismo? ¡Empecemos!

Ejercicios

 1. Y esto, ¿con qué se come?


 2. La importancia de nombrar las cosas
 3. MoverSegunBolitas, versión 2
 4. todasExcepto
 5. Una función de otro tipo
 6. En libertad
 7. Cualquier bolita nos deja bien
 8. Siempre al borde...
 9. Las compañeras ideales
 10. Lo ideal también se puede romper
 11. ¿Hay bolitas lejos?
 12. Estoy rodeado de viejas bolitas
 13. Sin límites

Ejercicio 1: Y esto, ¿con qué se come?


Tomate unos pocos minutos y tratá de entender qué hace este
procedimiento:

procedure MoverSegunBolitas() {
if (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde) > 10) {
Mover(Este)
} else {
Mover(Norte)
}
}

Cuando lo logres interpretar (o te canses ), presioná Enviar y mirá el resultado.

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si hay más de 10 bolitas, se mueve al Este


Tablero inicial

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

 Si hay menos de 10 bolitas, se mueve al Norte


Tablero inicial

0 1

1 1

3 2
0 0

0 1

Tablero final

0 1
1 1

3 2
0 0

0 1

Costó entender qué hace sin ejecutarlo, ¿no?

Eso es señal de que nos está faltando dividir en subtareas...

Ejercicio 2: La importancia de nombrar las cosas


Como vimos, el problema de lo anterior era la falta de división en
subtareas: la expresión que cuenta la cantidad de bolitas que hay en la
celda es demasiado compleja, y cuesta entender a simple vista que hace
eso.

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.

La buena noticia es que Gobstones nos permite hacer esto, y la


herramienta para ello es definir una función, que se escribe así:

function nroBolitasTotal() {
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
}

Pegá el código anterior en el editor y observá el resultado.

1
function nroBolitasTotal() {
2
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas

Resultados de 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

Algunas aclaraciones sobre las funciones:

 son un caso particular de las expresiones, y por lo tanto siguen las


mismas reglas que ellas: se escriben con la primera letra
minúscula y siempre denotan algún valor (en este caso, un
número);
 en la última línea de su definición siempre va un return, seguido de
una expresión entre paréntesis: el valor que la función va a
retornar.

Ejercicio 3: MoverSegunBolitas, versión 2


Ahora que ya logramos mover la cuenta de las bolitas a una subtarea,
podemos mejorar el procedimiento que habíamos hecho antes.

Modificá la primera versión de MoverSegunBolitas para que use la


función nroBolitasTotal() en vez de la expresión larga.
 Solución
 Biblioteca

1
procedure MoverSegunBolitas() {
2
if (nroBolitasTotal() > 10) {
3
Mover(Este)
4
} else {
5
Mover(Norte)
6
}
7
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 Si hay más de 10 bolitas, se mueve al Este


Tablero inicial

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

 Si hay menos de 10 bolitas, se mueve al Norte


Tablero inicial

0 1

1 1

3 2
0 0

0 1

Tablero final

0 1

1 1

3 2
0 0

0 1

Las funciones son una herramienta importantísima, que nos ayuda a


escribir programas de mayor calidad.

Sólo mirando el código de esta nueva versión del procedimiento


podemos entender de qué va nuestro problema, lo que reduce la
distancia entre el problema real y la estrategia que elegimos para
resolverlo.

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

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

Y volvemos así a lo más lindo de la programación: la posibilidad


de construir nuestras propias herramientas parándonos sobre cosas
que hicimos antes, logrando que lo que hacemos sea cada vez más
poderoso.

Ejercicio 5: Una función de otro tipo


Como ya sabés, las expresiones no sólo sirven para operar con números.
Vamos a definir ahora una función que retorne un
valor booleano (True / False).

Lo que queremos averiguar es si el color Rojo es dominante dentro de una


celda. Veamos algunos ejemplos.

En este casillero:

4 3

0 0
2 1

rojoEsDominante() retorna False (hay 2 bolitas rojas contra 8 de otros


colores). Pero en este otro:

4 3

0 0
9 1

rojoEsDominante() retorna True (hay 9 bolitas rojas contra 8 de otros colores)


Definí la función rojoEsDominante() que nos diga si la cantidad de bolitas rojas es
mayor que la suma de las bolitas de los otros colores. En
la Biblioteca está todasExcepto(color) lista para ser invocada.
¡Dame una pista!

 Solución
 Biblioteca

1
function rojoEsDominante() {
2
return (nroBolitas(Rojo) > todasExcepto(Rojo))
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 rojoEsDominante() -> False


Tablero inicial

0 1

1 1

3 2

0 0
4 3

0 1

 rojoEsDominante() -> True


Tablero inicial

0 1
1 1

3 2

0 0
10 3

0 1

Las funciones pueden retornar distintos tipos: un color, una dirección, un


número o un booleano.

Básicamente, lo que diferencia a un tipo de otro son las operaciones que


se pueden hacer con sus elementos: tiene sentido sumar números, pero
no colores ni direcciones; tiene sentido usar Poner con un color, pero no
con un booleano. Muchas veces, pensar en el tipo de una función es un
primer indicador útil de si lo que estamos haciendo está bien.

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

 ... ¿un color? No.


 ... ¿un número? Tampoco.
 ... ¿una dirección? Podría, pero no. Fijate que lo que pide es "saber
si puede moverse" y no hacia dónde.
 ... ¿un booleano? ¡Sí! Cómo nos dimos cuenta: lo que está pidiendo
tiene pinta de pregunta que se responde con sí o no, y eso es
exactamente lo que podemos representar con un valor
booleano: Verdadero o Falso.

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

Por ejemplo, si quisieramos saber si un casillero tiene más de 5 bolitas y


el Rojo es el color dominante podríamos escribir:
function esUnCasilleroCargadoConRojoDominante() {
return (nroBolitasTotal() > 5 && rojoEsDominante())
}

Definí la función esLibreCostados() que indique si el cabezal puede moverse tanto al


Este como al Oeste.
¡Dame una pista!

1
function esLibreCostados() {
2
return (puedeMover(Este) && puedeMover(Oeste))
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 esLibreCostados() -> False


Tablero inicial

0 1 2

1 1

0 0

0 1 2

 esLibreCostados() -> True


Tablero inicial

0 1 2

1 1
0 0

0 1 2

Ejercicio 7: Cualquier bolita nos deja bien


Definí la función hayAlgunaBolita() que responda a la pregunta ¿hay alguna bolita en
la celda actual?
Otra vez una pregunta, por lo tanto hay que retornar un booleano.
Además, podemos ver que acá también hay que hacer más de una
pregunta, en particular cuatro: una por cada una de los colores.

A diferencia del ejercicio anterior, lo que queremos saber es si alguna de


ellas es verdadera, por lo tanto hay que usar otro operador:
la disyunción, que se escribe || y retorna verdadero si al menos alguna de
las dos preguntas es verdadera.

De nuevo, si sabés algo de lógica, esta operación suele representarse con


el símbolo ∨.

¡Dame una pista!

1
function hayAlgunaBolita() {
2
return (hayBolitas(Azul) || hayBolitas(Verde) || hayBolitas(Negro) || hayBolitas(Rojo) )
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 hayAlgunaBolita() -> False


Tablero inicial
0 1

1 1

0 0

0 1

 hayAlgunaBolita() -> True


Tablero inicial

0 1

1 1

0 0
1 3

0 1

 hayAlgunaBolita() -> True


Tablero inicial

0 1

1 1

8
0 0

0 1

 hayAlgunaBolita() -> True


Tablero inicial

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.

Ejercicio 8: Siempre al borde...


Te recordamos los operadores lógicos que vimos hasta ahora:

 Negación: "da vuelta" una expresión booleana - ejemplo: not


hayBolitas(Rojo).
 Conjunción: determina si se cumplen ambas condiciones -
ejemplo: puedeMover(Norte) && puedeMover(Sur).
 Disyunción: determina si se cumple alguna de las condiciones -
ejemplo: esInteligente() || tieneBuenaOnda().

Con la ayuda de esa tablita, definí la función estoyEnUnBorde() que determine si el


cabezal está parado en algún borde.
¡Dame una pista!

1
function estoyEnUnBorde() {
2
return (not puedeMover(Norte) || not puedeMover(Este) || not puedeMover(Sur) || not
puedeMover(Oeste))
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 estoyEnUnBorde() -> True


Tablero inicial

0 1 2

2 2
1 1

0 0

0 1 2

 estoyEnUnBorde() -> True


Tablero inicial

0 1 2

2 2

1 1

0 0

0 1 2

 estoyEnUnBorde() -> False


Tablero inicial

0 1 2

2 2

1 1

0 0

0 1 2

Como en la aritmética, en la lógica también existe el concepto


de precedencia y ciertas operaciones se resuelven antes que otras:
primero la negación (not), después la conjunción (&&) y por último la
disyunción (||).

Por esta razón, la expresión not puedeMover(Norte) || not puedeMover(Este) || not


puedeMover(Sur) || not puedeMover(Oeste) se puede escribir sin tener que poner
paréntesis en el medio.
Ejercicio 9: Las compañeras ideales
Vamos a ver ahora funciones que hacen cosas antes de retornar un
resultado. Para ejemplificar esto, vamos a querer que definas una función
que nos diga si hay una bolita de un color específico, pero en la celda de
al lado.

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.

¡Dame una pista!

1
function hayBolitasAl(direccion, color) {
2
Mover(direccion)
3
return (hayBolitas(color))
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 hayBolitasAl() -> True


Tablero inicial

0 1 2

2 2

1 1
1

0 0
1

0 1 2

 hayBolitasAl() -> False


Tablero inicial

0 1 2

2 2

1 1
1

0 0
1

0 1 2

 hayBolitasAl() -> True


Tablero inicial

0 1 2

2 2

1 1
1

0 0
1

0 1 2

¿Viste qué pasó? El cabezal "no se movió" y sin embargo la función


devolvió el resultado correcto.

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

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

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

Pensándolo así, podemos decir que las funciones deshacen sus


efectos una vez que terminan, pero para poder devolver un resultado
necesitan que sus acciones puedan ejecutarse.

Ejercicio 11: ¿Hay bolitas lejos?


Ejercitemos un poco más esto de las funciones con procesamiento.

Te toca programar una nueva versión de hayBolitasAl que mire si hay


bolitas a cierta distancia de la celda actual. A esta función la vamos a
llamar hayBolitasLejosAl y recibirá tres parámetros: una dirección hacia
donde deberá moverse, un color por el cual preguntar y
una distancia que será la cantidad de veces que habrá que moverse.

Por ejemplo: hayBolitasLejosAl(Norte, Verde, 4) indica si hay alguna bolita


Verde cuatro celdas al Norte de la posición actual.

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

Definí la función hayBolitasLejosAl(direccion, color, distancia).


¡Dame una pista!

 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

Resultados de las pruebas:

 hayBolitasLejosAl() -> True


Tablero inicial

0 1 2

2 2
1

1 1

0 0

0 1 2

 hayBolitasLejosAl() -> True


Tablero inicial

0 1 2 3 4

1 1

0 0
1

0 1 2 3 4

 hayBolitasLejosAl() -> False


Tablero inicial

0 1 2 3 4

1 1

1
0 0

0 1 2 3 4

Se puede realizar cualquier tipo de acción antes de retornar un valor, y


nada de lo que hagamos tendrá efecto real sobre el tablero.
Interesante esto de las funciones, ¿no?

Ejercicio 12: Estoy rodeado de viejas bolitas


Valiéndote de hayBolitasAl, definí la función estoyRodeadoDe(color) que indica si el
cabezal está rodeado de bolitas de ese color.
Decimos que el cabezal "está rodeado" si hay bolitas de ese color en las cuatro
direcciones: Norte, Este, Sur y Oeste.
¡Dame una pista!

 Solución
 Biblioteca

1
function estoyRodeadoDe(color) {
2
return (hayBolitasAl(Norte, color) && hayBolitasAl(Este, color) && hayBolitasAl(Sur, color) &&
3
hayBolitasAl(Oeste, color))
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Resultados de las pruebas:

 estoyRodeadoDe() -> True


Tablero inicial

0 1 2

2 2
1

1 1
1 1

0 0
1

0 1 2

 estoyRodeadoDe() -> True


Tablero inicial

0 1 2

1
2 2

1 1
1 1

1
0 0

0 1 2

 estoyRodeadoDe() -> False


Tablero inicial

0 1 2

2 2
1

1 1
1 1

0 0

0 1 2

 estoyRodeadoDe() -> False


Tablero inicial

0 1 2

2 2
1
1 1
1 1

0 0

0 1 2

 estoyRodeadoDe() -> False


Tablero inicial

0 1 2

2 2

1
1 1

1
0 0

0 1 2

 estoyRodeadoDe() -> False


Tablero inicial

0 1 2

1
2 2

1
1 1

1
0 0

0 1 2

Por si todavía no nos creías: a pesar de que el cabezal se movió cuatro


veces por cada prueba, al finalizar la función vemos que siempre quedó
en la posición inicial.
Ejercicio 13: Sin límites
Para cerrar, vamos a definir la función hayLimite(), que determina si hay algún tipo de
límite a la hora de mover el cabezal.

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.

Usando estoyEnUnBorde y estoyRodeadoDe, definí hayLimite.

 Solución
 Biblioteca

function hayLimite() {
2

return (estoyEnUnBorde() || estoyRodeadoDe(Rojo))


3

}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas


Resultados de las pruebas:

 hayLimite() -> True

Tablero inicial

0 1 2

2 2
1

1 1
1 1

0 0
1

0 1 2

 hayLimite() -> True


Tablero inicial

0 1 2

2 2

1 1

0 0

0 1 2

 hayLimite() -> False

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:

 conociste las funciones, que son una buena forma de nombrar


expresiones compuestas;
 también vimos que se pueden usar funciones para calcular cosas
que necesitan salir de la celda actual y que el efecto
desaparece una vez que la función se ejecuta;
 ejercitamos los conectivos lógicos || y &&.

¡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. Funciones y tipos de datos

 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

2. Práctica Funciones y Tipos de Datos

 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

 1. ¡Que el último apague la luz!


 2. Negar no cuesta nada
 3. Los peripatéticos
 4. La verdad detrás de la conjunción
 5. ¡Juguemos al T.E.G.!
 6. Y ahora... ¿quién podrá ayudarnos?
 7. Claroscuro
 8. La verdad es que no hay una verdad
 9. ¡Hola! Mi nombre es Xor
 10. Precedencia
 11. Un ejercicio sin precedentes
 12. ¿Puedo subir?

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

 1. Los primeros registros


 2. Tu propio monumento
 3. Accediendo al campo
 4. Temperatura de planeta
 5. Moviendo archivos
 6. Registros de dos milenios
 7. Postres complejos
 8. Listas de registros
 9. 60 dulces minutos
 10. Hay un registro en mi registro
 11. ¡Azúcar!

7. Recorridos

 1. Las ganancias semestrales


 2. ¿Y el resto de las ganancias?
 3. Todas las ganancias, la ganancia
 4. Nos visita un viejo amigo
 5. Cuentas claras
 6. La ganancia promedio
 7. Quién gana, quién pierde
 8. Soy el mapa, soy el mapa
 9. A filtrar, a filtrar cada cosa en su lugar
 10. Un promedio más positivo
 11. Esto es lo máximo
 12. Como mínimo
 13. Los mejores meses del año

Apéndice

¿Querés saber más? Consultá el apéndice de este capítulo


Funciones y tipos de datos
¡Hola! Quizás no te diste cuenta pero ya tenés las bases de la
programación: ya sabés declarar funciones y procedimientos, tomar
decisiones empleando la estructura de control if, hacer tareas múltiples
veces.

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?

Para responder esta pregunta, primero nos adentraremos en el mundo de


JavaScript, un lenguaje muy popular que no tiene tablero, pero en el que
de todas formas podremos aplicar todo lo visto hasta ahora y descubrir
nuevas ideas y formas de resolver problemas

¡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

Ejercicio 1: Introducción a JavaScript


¿Ya te cansaste de jugar con bolitas de colores? Tenemos una buena
noticia. En este capítulo vamos a aprender programación imperativa de
la mano de uno de los lenguajes de programación más utilizados de la
industria del software.

JavaScript, usualmente abreviado Js, es muy parecido a Gobstones en


su sintaxis. Es decir, en la forma en que se escribe . Pero es mucho más
poderoso y está presente en casi todas las páginas que solés visitar.

Ya aprendimos a utilizar números y booleanos, en este capítulo también


vamos a usar palabras y conjuntos para trabajar con muchos datos a la
vez .

¿Ya te preparaste para salir del tablero?

¡Acompañanos!

Ejercicio 2: Funciones, definición


Gobstones y JavaScript tienen mucho en común. Por ejemplo, en ambos
lenguajes podemos definir funciones y usarlas muchas veces.

Sin embargo, como siempre que aprendas un lenguaje nuevo, te vas a


topar con un pequeño detalle: tiene una sintaxis diferente . La buena
noticia es que el cambio no será tan terrible como suena, así que veamos
nuestra primera función JavaScript:

function doble(numero) {
return 2 * numero;
}

Diferente, pero no tanto. Si la comparás con su equivalente Gobstones...

function doble(numero) {
return (2* numero)
}

...notarás que los paréntesis en el return no son necesarios, y que la última


línea la terminamos con ;.

Veamos si se va entendiendo: definí ahora la función mitad, que tome un número


por parámetro y retorne su mitad. Tené en cuenta que el operador de división en
JavaScript es /.
¡Dame una pista!

 Solución
 Consola

1
function mitad(numero) {
2
return numero / 2;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Perfecto, ¿viste que no era tan terrible?

Si no le pusiste ; al final de la sentencia habrás visto que funciona igual.


De todas formas ponelo, ya que de esa manera evitamos posibles
problemas.

Siempre que aprendamos un lenguaje nuevo vamos a tener que aprender


una nueva sintaxis. Sin embargo y por fortuna, si tenés los conceptos
claros, no es nada del otro mundo .

Aprendamos ahora a usar estas funciones.

Ejercicio 3: Funciones, uso


¿Y esto con qué se come? Digo, ehm.... ¿cómo se usan estas funciones?
¿Cómo hago para pasarles argumentos y obtener resultados?

Basta con poner el nombre de la función y, entre paréntesis, sus


argumentos. ¡Es igual que en Gobstones!

doble(3)

Y además podemos usarlas dentro de otras funciones. Por ejemplo:

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

Veamos si se entiende; definí las siguientes funciones:

 anterior: toma un número y devuelve ese número menos uno


 triple: devuelve el triple de un número
 anteriorDelTriple, que combina las dos funciones anteriores: multiplica a un
número por 3 y le resta 1

 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

¡Muy bien! Tu solución pasó todas las pruebas

Quizás ahora estés pensando: si no tengo un tablero, ¿cómo sé si mi


función hace lo que debe? Acompañanos...

Ejercicio 4: Probando funciones


Quizás ya lo notaste pero, junto al editor, ahora aparece una pestaña
nueva: la consola.

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.

La podés reconocer fácilmente porque arranca con un chirimbolito que se


llama prompt.

Para entender mejor cómo funciona, te invitamos a explorarla.

Probá en la consola las siguientes expresiones:

 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

>

Ejercicio 5: Haciendo cuentas


Además de los operadores matemáticos +, -, / y *, existen muchas otras
funciones matemáticas comunes, algunas de las cuales ya vienen con
JavaScript y están listas para ser usadas.

Sin embargo, la sintaxis de estas funciones matemáticas


es apenitas diferente de lo que veníamos haciendo hasta ahora: hay que
prefijarlas con Math.. Por ejemplo, la función que nos sirve para redondear
un número es [Link]:

function cuantoSaleAproximadamente(precio, impuestos) {


return [Link](precio * impuestos);
}

Probá en la consola las siguientes expresiones:

 [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:

// el saldo es $100, el monto a extraer, $30


> extraer(100, 30)
70 //quedan $70 ($100 - $30 = $70)

Pero como no queremos quedarnos en negativo, si el monto a extraer es


mayor al saldo, nuestro saldo debe quedar en cero.

> extraer(100, 120)


0 //Ups, quisimos sacar más plata de la que teníamos.
//Nos quedamos con $0

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 .

En otras palabras (¡preparate!, esto te puede volar la


cabeza ) extraer devuelve el máximo entre la resta saldo - monto y 0.

¿Te animás a completar la solución que está en el editor?


¡Dame una pista!

 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

¡Bien hecho! Ahora andá y probalo en la consola

Como ves, la función [Link] nos sirvió para implementar un tope


inferior. De forma análoga, la función [Link] nos puede servir para
implementar un tope superior.

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 .

Ejercicio 7: Libros de la buena memoria


¡Veamos más operadores! Dani ama el primer día de cada mes , y por eso
definió esta función...

function esDiaFavorito(diaDelMes) {
return diaDelMes === 1 ;
}

...y la usa así (y la dejó en la biblioteca para que la pruebes):

> esDiaFavorito(13)
false
> esDiaFavorito(1)
true

Como ves, en JavaScript contamos con operadores


como ===, >=, >, <,<= que nos dicen si dos valores son iguales, mayores-o-
iguales, mayores, etc. Los vamos a usar bastante .

¡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

Definí y probá en la consola la función leGustaLeer.

 Solución
 Consola
1
function leGustaLeer(libros) {
2
return libros > 20
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

¡Bien hecho!

Capaz pasó desapercibido, pero leGustaLeer devuelve true o false, es decir, es


una función que devuelve booleanos. Eso significa que en JavaScript, no
sólo hay números sino que también..... hay booleanos .

Ejercicio 8: Booleanos
Ahora miremos a los booleanos con un poco más de detalle:

 Se pueden negar, mediante el operador !: !hayComida


 Se puede hacer la conjunción lógica entre dos booleanos (and,
también conocido en español como y lógico), mediante el
operador &&: hayComida && hayBebida
 Se puede hacer la disyunción lógica entre dos booleanos (or,
también conocido en español como o lógico), mediante el
operador ||: unaExpresion || otraExpresion

Veamos si se entiende; definí las siguientes funciones:

 estaEntre, que tome tres números y diga si el primero es mayor al segundo y


menor al tercero.
 estaFueraDeRango: que tome tres números y diga si el primero es menor al
segundo o mayor al tercero

Ejemplos:

> estaEntre(3, 1, 10)


true
> estaEntre(90, 1, 10)
false
> estaEntre(10, 1, 10)
false
> estaFueraDeRango(17, 1, 10)
true

 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

¡Muy bien! Tu solución pasó todas las pruebas

¡Bien hecho!

Ya fueron suficientes booleanos y cuentas por ahora, ¿no? Exploremos


algo más interesante: los strings.

Ejercicio 9: Palabras, sólo palabras


Muchas veces queremos escribir programas que trabajen con texto :
queremos saber cuántas palabras hay en un libro, o convertir minúsculas
a mayúsculas, o saber en qué parte de un texto está otro.

Para este tipo de problemas tenemos los strings, también


llamados cadenas de caracteres:
 "Ahora la bebé tiene que dormir en la cuna"
 'El hierro nos ayuda a jugar'
 "¡Hola Miguel!"

Como se observa, todos los strings están encerrados entre comillas


simples o dobles. ¡Da igual usar unas u otras! Pero sé consistente: por
ejemplo, si abriste comilla doble, tenés que cerrar comilla doble. Además,
un string puede estar formado por (casi) cualquier carácter: letras,
números, símbolos, espacios, etc.

¿Y qué podemos hacer con los strings? Por ejemplo, compararlos, como a
cualquier otro valor:

> "hola" === "Hola"


false

> "todo el mundo" === "todo el mundo"


true

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

¡Dame una pista!

 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

Ejercicio 10: Operando strings


¿Y qué podemos hacer con los strings, además de compararlos? ¡Varias
cosas! Por ejemplo, podemos preguntarles cuál es su cantidad de letras:

> longitud("biblioteca")
10
> longitud("babel")
5

O también podemos concatenarlos, es decir, obtener uno nuevo que


junta dos strings:

> "aa" + "bb"


"aabb"
> "sus anaqueles " + "registran todas las combinaciones"
"sus anaqueles registran todas las combinaciones"

O podemos preguntarles si uno comienza con otro:

> comienzaCon("una página", "una")


true
> comienzaCon("la biblioteca", "todos los fuegos")
false

Veamos si queda claro: definí la función longitudNombreCompleto, que tome un nombre


y un apellido, y retorne su longitud total, contando un espacio extra para separar a
ambos:

> longitudNombreCompleto("Cosme", "Fulanito")


14

 Solución
 Biblioteca
 Consola

1
function longitudNombreCompleto(nombre, apellido) {
2
return longitud(nombre) + 1 + longitud(apellido);
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 11: ¡GRITAR!


Una conocida banda, para agregar gritos varios a su canción, nos pidió
definir la función gritar, que toma un string y lo devuelve en mayúsculas y
entre signos de exclamación.

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

Ejercicio 12: ¿Y qué tal si...?


Ninguna introducción al lenguaje JavaScript estaría completa sin mostrar
al menos una estructura de control que ya conocemos: la alternativa
condicional. Veamos un ejemplo:

//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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 13: ¿De qué signo sos?


Ya utilizamos la alternativa condicional para realizar una acción específica
cuando se cumple una condición y para cuando debemos elegir entre dos
acciones diferentes (según se cumpla o no).

Pero... ¿Si necesitamos más de dos alternativas? Veamos un ejemplo:

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

¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 14: El retorno del booleano


Para cerrar, ahora que ya vimos cómo escribir la alternativa condicional,
es momento de un pequeño recordatorio: si usás adecuadamente las
expresiones booleanas, ¡no es necesario utilizar esta estructura de control!

Supongamos que queremos desarrollar una función esMayorDeEdad, que


nos diga si alguien tiene 18 años o más. Una tentación es escribir lo
siguiente:

function esMayorDeEdad(edad) {
if (edad >= 18) {
return true;
} else {
return false;
}
}

Sin embargo, este if es totalmente innecesario, dado que la


expresión edad >= 18 ya es booleana:

function esMayorDeEdad(edad) {
return edad >= 18;
}

Mucho más simple, ¿no?

Para Ema un número es de la suerte si:

 es positivo, y
 es menor a 100, y
 no es el 15.

Definí la función esNumeroDeLaSuerte que dado un número diga si cumple la lógica


anterior. ¡No vale usar if!

 Solución
 Biblioteca
 Consola

1
function esNumeroDeLaSuerte(numero) {
2
return (numero >= 0) && (numero < 100) && (numero !== 15)
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

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.

Recordá: ¡menos código, más felicidad!

Ejercicio 15: Los premios


El jurado de un torneo nos pidió la función medallaSegunPuesto que retorne
la medalla que le corresponde a los primeros puestos, según la siguiente
lógica:
 primer puesto: le corresponde "oro"
 segundo puesto: le corresponde "plata"
 tercer puesto: le corresponde "bronce"
 otros puestos: le corresponde "nada"

Ejemplo:

> medallaSegunPuesto(1)
"oro"
> medallaSegunPuesto(5)
"nada"

Definí, y probá en la consola, la función medallaSegunPuesto

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 16: Tipos de datos


Como acabamos de ver, en JavaScript existen números, booleanos y
strings:

Tipo de dato Representa Ejemplo Operaciones

Números cantidades 4947 +, -, *, %, <, etc

Boolean valores de verdad true &&, !, etc

Strings texto "hola" longitud, comienzaCon, etc

Además, existen operaciones que sirven para todos los tipos de datos, por
ejemplo:

 ===: nos dice si dos cosas son iguales


 !==: nos dice si dos cosas son diferentes

Es importante usar las operaciones correctas con los tipos de datos


correctos, por ejemplo, no tiene sentido sumar dos booleanos o hacer
operaciones booleanas con los números. Si usas operaciones que no
corresponden, cosas muy raras y malas pueden pasar.

Probá en la consola las siguientes cosas:

 5 + 6 (ok, los números se pueden sumar)


 5 === 6 (ok, todas las cosas se pueden comparar)
 8 > 6 (ok, los números se pueden ordenar)
 !true (ok, los booleanos se pueden negar)
 false / true (no está bien, ¡los booleanos no se pueden dividir!)
 Consola
 Biblioteca

>5 + 6

=> 11

> 6 === 6

=> true

>8 > 6

=> true

> !true

=> false

> false / true

=> 0

>

Ejercicio 17: Datos de todo tipo


Uff, ¡vimos un montón de cosas! Aprendimos sobre la sintaxis de las
funciones en JavaScript, los tipos de datos y sus operaciones, e incluso
conocimos uno nuevo: los strings.

¡Para finalizar veamos algunos ejemplos!

 4 + 4 vale 8.
 "4" + "4" vale "44".
 "on" + "ce" vale "once".
 true && false vale false.
 5 >= 6 vale false.

¡Terminaste Funciones y tipos de datos!


¡Excelente!

Eso significa que ya estás entrando en calor en un nuevo lenguaje:


pudiste aplicar alternativas condicionales, funciones y expresiones. Y por
si fuera poco, aprendiste en el camino algunas herramientas nuevas: los
strings.

¿Querés seguir aprendiendo? ¡Acompañanos a la siguiente lección!

Siguiente Lección: Práctica Funciones y Tipos de Datos

Práctica Funciones y Tipos de Datos


Antes de continuar, ¡practiquemos un poco sobre lo que acabamos de
aprender!

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!

Ejercicio 1: Comprando Hardware


Queremos comprar una computadora nueva , y nos gustaría saber cuánto
nos va a salir. Sabemos que:

 Los monitores cuestan $60 por cada pulgada


 La memoria cuesta $200 por cada GB
 El precio base estimado del resto de los componentes es de $1000

Definí la función cuantoCuesta que tome el número de pulgadas del monitor y la


cantidad de memoria, y calcule el costo estimado de nuestra computadora.

> cuantoCuesta(25, 8)
4100

 Solución
 Biblioteca
 Consola

1
function cuantoCuesta(pulgada, gb) {
2
return 60 * pulgada + 200 * gb + 1000;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 2: ¿Me conviene?


Ahora que sabemos cuantoCuesta una computadora, queremos saber si una
computadora me conviene. Esto ocurre cuando:

 sale menos de $6000, y


 tiene al menos un monitor de 32 pulgadas, y
 tiene al menos 8GB de memoria

Definí la función meConviene, que nuevamente tome el número de pulgadas y


cantidad de memoria y nos diga si nos conviene comprarla :

> meConviene(25, 8)
false // porque el monitor es demasiado chico
> meConviene(42, 12)
true // cumple las tres condiciones

En la Biblioteca ya está definida la función cuantoCuesta lista para ser invocada.


¡Dame una pista!

 Solución
 Biblioteca
 Consola
1
function meConviene(pulgadas, gb) {
2
return cuantoCuesta(pulgadas, gb) < 6000 && pulgadas >= 32 && gb >= 8;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 3: Triangulos
¡Hora de hacer un poco de geometría! Queremos saber algunas cosas
sobre un triángulo:

 perimetroTriangulo: dado los tres lados de un triángulo, queremos


saber cuánto mide su perímetro.
 areaTriangulo: dada la base y altura de un triángulo, queremos saber
cuál es su área.

Definí las funciones perimetroTriangulo y areaTriangulo


¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 4: Cuadrados
Y ahora es el turno de los cuadrados; queremos saber

 perimetroCuadrado: dado un lado, queremos saber cuánto mide su


perímetro.
 areaCuadrado: dado un lado, queremos saber cuál es su area

Definí las funciones perimetroCuadrado y areaCuadrado


¡Dame una pista!

 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

Ejercicio 5: ¿Está afinado?


Cuando presionamos una tecla de un piano, éste produce un sonido que
tiene una cierta frecuencia. Y cuando presionamos el la central del piano,
si está afinado, vamos a escuchar una nota cuya frecuencia es 440Hz.

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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 6: ¿Está cerca?


Ahora queremos saber si el la central del piano está cerca de estar
afinado. Esto ocurre cuando está entre 437Hz y 443Hz, pero NO es
exactamente 440Hz. Por ejemplo:

> 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

Definí la función estaCerca

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

Para eso, tenemos que juntar su nombre, su apellido, y su título


(dr., dra., lic., etc) y armar un único string.

Definí la función escribirCartelito, que tome un título, un nombre y un apellido y forme


un único string. Por ejemplo:

> escribirCartelito("Dra.", "Ana", "Pérez")


"Dra. Ana Pérez"

¡Dame una pista!

 Solución
 Biblioteca
 Consola
1
function escribirCartelito(titulo, nombre, apellido) {
2
return titulo + " " + nombre + " " + apellido;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 8: Más Cartelitos


Ah, ¡pero no tan rápido! Algunas veces en nuestro cartelito sólo
queremos el título y el apellido, sin el nombre. Por eso ahora nos toca
mejorar nuestra función escribirCartelito de forma que tenga 4 parámetros:

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.

Modificá la función escribirCartelito, de forma que se comporte como se describe


arriba. Ejemplo:

// 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 9: Cartelitos óptimos


Ahora que ya podemos escribir nuestros cartelitos identificatorios
grandes y chicos, queremos una nueva función que nos dé el cartelito de
tamaño óptimo:

 si nombre y apellido tienen, en total, más de 15 letras, queremos un


cartelito corto;
 de lo contrario, queremos un cartelito largo.

Definí la función escribirCartelitoOptimo que tome un título, un nombre y un apellido, y


utilizando escribirCartelito genere un cartelito corto o largo, según las reglas
anteriores. Ejemplo:

> escribirCartelitoOptimo("Ing.", "Carla", "Toledo")


"Ing. Carla Toledo"
> escribirCartelitoOptimo("Dr.", "Estanislao", "Schwarzschild")
"Dr. Schwarzschild"

Te dejamos en la biblioteca la función escribirCartelito definida. ¡Usala cuando


necesites!
¡Dame una pista!
 Solución
 Biblioteca
 Consola

1
function escribirCartelitoOptimo(titulo, nombre, apellido) {
2
return escribirCartelito(titulo, nombre, apellido, (longitud(nombre + apellido) > 15));
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 10: Cara o ceca


Hay veces en las que tenemos difíciles decisiones que tomar en nuestras
vidas (como por ejemplo, si comer pizzas o empanadas ), y no tenemos
más remedio que dejarlas libradas a la suerte.

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:

> decisionConMoneda("cara", "pizzas", "empanadas")


"pizzas"

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 11: ¡Envido!


Queremos saber el valor de las cartas de truco cuando jugamos al envido.
Sabemos que:

 todas las cartas del 1 al 7, inclusive, valen su numeración


 las cartas del 10 al 12, inclusive, valen 0
 no se juega con 8s ni con 9s

Definí una función valorEnvido, que tome un número de carta y retorne su valor de
envido.

> valorEnvido(12)
0
> valorEnvido(3)
3

¡Dame una pista!

 Solución
 Biblioteca
 Consola
1
function valorEnvido(carta) {
2
if (carta > 7) {
3
return 0;
4
} else {
5
return carta;
6
}
7
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 12: ¡Quiero retruco!


Bueno, ehm, no, pará, primero queremos calcular cuántos puntos de
envido suma un jugador. Sabemos que:

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

Utilizando la función valorEnvido (que ya definimos por vos), definí la


función puntosDeEnvidoTotales que tome los valores y palos de dos cartas y diga
cuánto envido suman en total. Ejemplo:

> puntosDeEnvidoTotales(1, "espadas", 4, "espadas")


25
> puntosDeEnvidoTotales(2, "copas", 3, "bastos")
3

¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 13: ¡Quiero vale cuatro!


Cuando se juega al truco, los equipos oponentes alternativamente
pueden subir la apuesta. Por ejemplo, si un jugador canta truco, otro
jugador puede cantarle retruco. Obviamente, los puntos que están en
juego son cada vez mayores:

Canto Puntos en juego

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

¡Muy bien! Tu solución pasó todas las pruebas


¡Terminaste Práctica Funciones y Tipos de Datos!
¡Muy bien!

En esta lección practicaste los temas abarcados en la primera lección con


ejercicios un poco más desafiantes.

¡Seguinos para aprender nuevos conceptos de la programación


imperativa!

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?

No. En JavaScript, lamentamos informarte, no hay tablero .

Pero tampoco es tan grave: en JavaScript no hay tablero, ¡porque no lo


necesitás! Suceden dos cosas:

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!

> funcionMisteriosa (5, 8)

=> "wooooowwwwwwww!"

> funcionMisteriosa (1, 2)

=> "woww!"

> funcionMisteriosa (10, 15)

=> "woooooooooowwwwwwwwwwwwwww!"

>

Ejercicio 2: Impresión por pantalla


Ahora que ya te convencimos de que no necesitamos al tablero, vamos a
mostrarte que sí hay algo parecido en JavaScript : la impresión por
pantalla. Veamos un ejemplo:

function funcionEgocentrica() {
imprimir("soy una función que imprime por pantalla");
imprimir("y estoy por devolver el valor 5");
return 5;
}

Probá funcionEgocentrica en la consola.


> funcionEgocentrica

=> <function>

> funcionEgocentrica()

soy una función que imprime por pantalla


y estoy por devolver el valor 5
=> 5

> funcionEgocentrica()

soy una función que imprime por pantalla


y estoy por devolver el valor 5
soy una función que imprime por pantalla
y estoy por devolver el valor 5
=> 5

>

Siguiente Ejercicio: Martin Fierro

Ejercicio 3: Martin Fierro


¿Qué acabamos de hacer con esto? Al igual que Poner(bolita), imprimir es
una funcionalidad que siempre está disponible. Si llamamos a la función
anterior, veremos que, además de devolver el valor 5, imprime dos líneas:

soy una función que imprime por pantalla


y estoy por devolver el valor 5

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.

Veamos si va quedando claro, definí la function versosMartinFierro que imprima por


pantalla los primeros versos del Martín Fierro:

Aquí me pongo a cantar


Al compás de la vigüela;
Que el hombre que lo desvela
Una pena extraordinaria

Esta function debe retornar 0


¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

¡Bien hecho!

Sin embargo, ¿tiene sentido que versosMartinFierro devuelva 0? ¿Usamos


para algo este resultado?

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?

La respuesta, ¡en el siguiente ejercicio!

Ejercicio 4: ¿Y los procedimientos?


En el ejercicio anterior, construiste una function que se ejecutaba con el
sólo fin de imprimir por pantalla. Y por ello, tuvimos que devolver un
valor cualquiera. ¿No te huele mal?
Además, hagamos memoria: cuando queremos reutilizar código,
podíamos declarar:

 funciones, que siempre retornan algo y no producen ningún efecto


 procedimientos, que no retornan nada, y producen efectos

Entonces versosMartinFierro, no es una función... ¡sino un procedimiento!


¿Cómo se declaran procedimientos 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");
}

Envía esta nueva versión de versosMartinFierro

 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

Esto puede ser un poco perturbador : JavaScript no diferencia funciones


de procedimientos: todos pueden tener efectos y todos pueden o no
tener retorno.

Vos sos responsable de escribir una function que tenga sentido y se


comporte o bien como un procedimiento (sin retorno y con efecto) o bien
como una función (con retorno y sin efecto).

Si empezás a mezclar funciones con retornos y efecto, funcionará, pero tu


código se volverá de a poco más difícil de entender. Esto nos va a pasar
mucho en JavaScript: que puedas hacer algo no significa que debas
hacerlo .

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ó?

La respuesta es tan simple como sorprendente: en JavaScript todo lo que


escribamos fuera de una function será, implícitamente, dicho punto de
entrada. Por ejemplo, si queremos un programa que imprime por pantalla
el clásico "Hola, mundo!", lo podremos escribir así:

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());

Copiá y enviá este programa

 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

¡Muy bien! Tu solución pasó todas las pruebas

¿Ooooups, y el resultado? ¿Dónde está lo que imprimimos por pantalla?


¿Es que nuestro programa no anduvo?

No, para nada, es que simplemente no te estamos mostrando lo que sale


por pantalla .

¿Por qué? ¿Porque somos malvados? Bueno, quizás en parte , pero


tenemos además una buena razón: cuando escribís programas reales, es
muy, muy frecuente que no sea fácil ver lo que el imprimir imprime, por
decenas de motivos. Entonces, como rara vez vas poder ver a tiempo lo
que se imprime en la pantalla, terminan siendo una técnica poco útil.

Moraleja: en los ejercicios que quedan, no uses imprimir salvo que te lo


pidamos explícitamente.

¡Nos vemos en el próximo ejercicio!

Ejercicio 6: Coerciones
Volvamos un momento al código anterior. ¿Notás algo extraño en esta
expresión?

"La primera tirada dio " + primeraTirada

Utilizamos el operador + de una forma diferente, operando un string y un


número, y lo que hizo fue concatenar al string con la representación
textual del número. Es decir que:

 si operamos dos números con +, se suman


 si operamos dos strings con +, se concatenan
 si operamos un string y un número +, se convierte implícitamente el
número a string, y luego se concatenan, al igual que antes

En JavaScript, estas conversiones implícitas, también llamadas coerciones,


ocurren mucho.

¡Quizás incluso más de lo que nos gustaría!

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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 7: El círculo de la vida


En programación buscamos que resolver nuestros problemas usando…
programas . Y entre los problemas que casi nadie quiere resolver están los
matemáticos. Sobre todo aquellos que aparecen números como pi con
infinitos decimales imposibles de recordar.

Considerando al número pi igual a 3.14159265358979 (no es infinito pero lo


suficientemente preciso para nuestros cáculos):
Definí las funciones perimetroCirculo y areaCirculo que reciben el radio de un círculo y a
partir del mismo nos retornan su perímetro y su área.
¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Excelente, la precisión de nuestros cálculos es innegable , pero tuvimos


que escribir un número larguísimo. Pensemos que pi aparece en un
montón de fórmulas matemáticas. ¿Es necesario escribir este número
cada vez?¿No podemos hacer algo más cómodo?

Ejercicio 8: PIenso que así es más fácil


Por suerte existe una herramienta que va a simplificar nuestra tarea de
ahora en adelante: las variables.

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"

...estamos asignándole el valor "enero" a la variable primerMes. En criollo,


estamos dándole ese valor a la variable.

Cambiá los lugares donde aparece 3.14159265358979 por la variable pi en las


funciones que tenemos definidas.

 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

¡Muy bien! Tu solución pasó todas las pruebas

¡Excelente! Gracias a la variable pi no tuvimos que escribir el número cada


vez que teníamos que usarlo y ¡nuestro programa quedó mucho más
entendible!

Siguiente Ejercicio: Esto no tiene valor


Ejercicio 9: Esto no tiene valor
Ya que vas entendiendo cómo se asignan las variables, te traemos algo
para pensar: ¿qué pasa si intento usar una variable a la que nunca le
asigné un valor?

Tenemos esta función definida:

function sumaSinSentido() {
return numero + 8;
}

Probala en la consola y fijate qué sucede.

> sumaSinSentido(2)

return numero + 8;
^

ReferenceError: numero is not defined

> sumaSinSentido(2)

return numero + 8;
^

ReferenceError: numero is not defined

>

Siguiente Ejercicio: Variables globales

Ejercicio 10: Variables globales


Entonces, ¿es necesario darle valor a nuestras variables antes de usarlas?

¡Sí! Cuando declarás una variable tenés que darle un valor inicial, lo cual
se conoce como inicializar la variable.

¡Y sorpresa! Podemos declarar variables tanto directamente en el


programa, como dentro de una function:

function cuentaExtravagante(unNumero) {
let elDoble = unNumero * 2;
if (elDoble > 10) {
return elDoble;
} else {
return 0;
}
}

Las variables declaradas dentro de una function, conocidas como variables


locales, no presentan mayor misterio. Sin embargo, hay que tener un
particular cuidado: sólo se pueden utilizar desde dentro de la function en
cuestión. Si quiero referenciarla desde un programa:

let elCuadruple = elDoble * 4;

Kaboom, ¡se romperá!

Sin embargo, las variables declaradas directamente en el programa,


conocidas como variables globales, pueden ser utilizadas desde
cualquier function. Por ejemplo:

let pesoMaximoEquipajeEnGramos = 5000;

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:

 pesoPromedioPersonaEnKilogramos, la cual ya está declarada,


 cargaMaximaEnKilogramos que vas a tener que declarar.

 Solución
 Consola

1
let cargaMaximaEnKilogramos = 300;
2
function ascensorSobrecargado(cantidadpersonas) {
3
return cantidadpersonas * pesoPromedioPersonaEnKilogramos >= cargaMaximaEnKilogramos;
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 11: La buena fortuna


Las variables no serían tan interesantes si no se pudieran modificar.
Afortunadamente, JavaScript nos da nuevamente el gusto y nos lo
permite:

function pasarUnDiaNormal() {
diasSinAccidentesConVelociraptores = diasSinAccidentesConVelociraptores + 1
}

function tenerAccidenteConVelociraptores() {
diasSinAccidentesConVelociraptores = 0;
}

¡Ahora vamos a hacer algo de dinero !


Definí el procedimiento aumentarFortuna que duplique el valor de la variable
global pesosEnMiBilletera. No declares la variable, ya lo hicimos por vos (con una
cantidad secreta de dinero) .
¡Dame una pista!

 Solución
 Consola

1
function aumentarFortuna() {
2
pesosEnMiBilletera = pesosEnMiBilletera * 2
3
}
Enviar
¡Muy bien! Tu solución pasó todas las pruebas

Actualizaciones como duplicar, triplicar, incrementar en uno o en una


cierta cantidad son tan comunes que JavaScript presenta algunos atajos:

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;

¡Usalos cuando quieras!

Ejercicio 12: ¿Y esto cuánto vale?


Vimos que una variable solo puede tener un valor, entonces cada vez que
le asignamos uno nuevo, perdemos el anterior. Entonces, dada la función:

function cuentaExtravagante() {
let numero = 8;
numero *= 2;
numero += 4;
return numero;
}

Si la invocaramos ¿qué crees que retornaría?

Veamos el paso a paso:

 inicialmente la variable numero vale 8;


 al hacer numero *= 2 la variable pasa a tener su valor multiplicado por
2, es decir, 16;
 al hacer numero += 4 le sumamos 4 a 16 y lo guardamos en número,
por ende la función cuentaExtravagante retorna 20.

¡Terminaste Variables y procedimientos!


¡Perfecto!

A lo largo de esta lección hiciste muchas cosas nuevas:

 imprimiste por pantalla;


 conociste los procedimientos en el lenguaje JavaScript, que si bien
se definen igual que las funciones son bien distintos;
 utilizaste los dos tipos de variables, locales y globales, y aprendiste
sus diferencias.

¡Veamos que depara la siguiente lección!


Lógica booleana
Como ya viste a lo largo de varios ejercicios, cuando programamos
trabajamos con booleanos que representan valores de verdad. Podemos
operar con ellos mediante lo que denominamos operadores lógicos,
como la conjunción y la disyunción. ¡Vamos a aprender un poco más
sobre ellos!

Ejercicios

 1. ¡Que el último apague la luz!


 2. Negar no cuesta nada
 3. Los peripatéticos
 4. La verdad detrás de la conjunción
 5. ¡Juguemos al T.E.G.!
 6. Y ahora... ¿quién podrá ayudarnos?
 7. Claroscuro
 8. La verdad es que no hay una verdad
 9. ¡Hola! Mi nombre es Xor
 10. Precedencia
 11. Un ejercicio sin precedentes
 12. ¿Puedo subir?

Ejercicio 1: ¡Que el último apague la luz!


Empecemos por algo sencillo, ¿te acordás del operador ! ? Se lo
denomina negación, not o complemento lógico y sirve para negar un
valor booleano.

Si tengo el booleano representado por tieneHambre, el complemento


será !tieneHambre.

¿Y esto para qué sirve? Por ejemplo, para modelar casos de alternancia
como prender y apagar una luz :

let lamparaPrendida = true;

function apretarInterruptor() {
lamparaPrendida = !lamparaPrendida;
}

¡Ahora te toca a vos!


Definí el procedimiento usarCierre para que podamos abrir y cerrar el cierre de una
mochila.

 Solución
 Consola

1
let mochilaAbierta = true;
2
function usarCierre() {
3
mochilaAbierta = !mochilaAbierta;
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 2: Negar no cuesta nada


Por el momento no parece una idea muy interesante, pero nos puede
servir para reutilizar la lógica de una función que ya tenemos definida.

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

¡Ahora te toca a vos! Definí esMayorDeEdad, que recibe una edad, y


luego esMenorDeEdad a partir de ella.

 Solución
 Consola
1
function esMayorDeEdad(edad) {
2
return edad >= 18;
3
}
4
function esMenorDeEdad(edad) {
5
return !esMayorDeEdad(edad);
6
}
7

Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Cada una de las funciones representa un estado de dos posibles: ser


mayor o ser menor de edad. No se puede ser ambos al mismo tiempo y
tampoco se puede evitar pertenecer a alguno de los dos grupos. Es decir,
¡siempre sos uno u otro!

Por eso decimos que son complementarios y que juntos forman


el conjunto universal.

Ejercicio 3: Los peripatéticos


Otro de los operadores con el que ya te encontraste es la conjunción
lógica (también llamada y lógico, o and por su nombre en inglés), que
sólo retorna verdadero cuando todas las expresiones que opera son
verdaderas.

Podemos encadenar varias de ellas mediante el operador && y alcanza


con que sólo una de ellas sea falsa para que toda la expresión resulte
falsa.

Por ejemplo, si cuento con la función:

function esCantanteProlifico (cdsEditados, recitalesRealizados, graboAlgunDVD) {


return cdsEditados >= 10 && recitalesRealizados > 250 && graboAlgunDVD;
}

y tenemos un cantante que no grabó un DVD, entonces no se lo


considera prolífico, incluso aunque haya editado más de 10 CDs y dado
más de 250 recitales.

Definí una función esPeripatetico que tome la profesión de una persona, su


nacionalidad y la cantidad de kilómetros que camina por día. Alguien es
peripatético cuando es un filósofo griego y le gusta pasear (camina más de 2
kilómetros por día). Ejemplo:

> esPeripatetico("filósofo", "griego", 5)


true
> esPeripatetico("profesor", "uruguayo", 1)
false

 Solución
 Consola

1
function esPeripatetico(profesion, nacionalidad, kilometros) {
2
return profesion === "filósofo" && nacionalidad === "griego" && kilometros > 2;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 4: La verdad detrás de la conjunción


En la lógica booleana, se puede definir el comportamiento de un
operador con una tabla de verdad donde A y B son las expresiones o
valores de verdad a ser operados y el símbolo ^ representa la conjunción.
Cada celda tiene una V si representa verdadero o F si representa falso.

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

Como indicamos, la casa consume poca energía (A^B) cuando


tanto A como B son verdaderos. Esto se puede representar mediante la
siguiente tabla de verdad:

A B A^B

V V V

V F F

F V F

F F F

En el mundo de la lógica estas expresiones se llaman proposiciones. Pero…


¿qué cosas pueden ser una proposición? Sólo hace falta que porten un
valor de verdad, es decir, cualquier expresión booleana puede ser una
proposición.

¿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

>

Ejercicio 5: ¡Juguemos al T.E.G.!


¿Y si basta con que una de varias condiciones se cumpla para afirmar que
una expresión es verdadera? Podemos utilizar otro de los operadores que
ya conocés, ¡la disyunción lógica!

Recordá que se lo representa con el símbolo || y también se lo conoce


como el operador or.

En el famoso juego T.E.G., un jugador puede ganar de dos formas:


cumpliendo su objetivo secreto o alcanzando el objetivo general de
conquistar 30 países.

function gano(cumplioObjetivoSecreto, cantidadDePaisesConquistados) {


return cumplioObjetivoSecreto || cantidadDePaisesConquistados >= 30;
}

Probá en la consola las siguientes expresiones:

 > gano(true, 25)


 > gano(false, 30)
 > gano(false, 20)
 > gano(true, 31)

¿Te animás a construir la tabla de verdad de la disyunción lógica?

> gano(true, 25)

=> true

> gano(false, 30)

=> true

> gano(false, 20)

=> false

> gano(true, 31)

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

Sabemos que el banco está cerrado cuando:

 Es feriado, o
 Es fin de semana, o
 No estamos dentro del horario bancario.

La función dentroDeHorarioBancario ya la definimos por vos: recibe un


horario (una hora en punto que puede ir desde las 0 hasta las 23) y nos
dice si está comprendido en la franja de atención del banco.

Definí las funciones esFinDeSemana y estaCerrado. Tené en cuenta que los días se
reciben en minúscula:

> estaCerrado(false, "sábado", 10)


true //Porque es fin de semana

> estaCerrado(true, "lunes", 10)


true //Porque es feriado

> estaCerrado(false, "martes", 20)


true //Porque no está dentro del horario bancario

> estaCerrado(false, "jueves", 11)


false

 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

¡Muy bien! Tu solución pasó todas las pruebas

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.

Para empezar ya contamos con la función esTonoClaro que toma un color


por parámetro y retorna si es claro.

> 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 8: La verdad es que no hay una verdad


Ahora pensemos cómo sería la tabla de verdad que representa el
comportamiento de la función que acabás de hacer.

La proposición es esTonoClaro, y el valor de verdad que porte dependerá


de cada color que esté evaluando.

El booleano final resultará de operar estos colores mediante tieneContraste:

la letra tiene tono claro el fondo tiene tono claro tiene contraste

true true false

true false true

false true true

false false false

Probá tu función tieneContraste con los siguientes valores y comprobá si se comporta


como la tabla:

 > tieneContraste("amarillo", "beige")


 > tieneContraste("azul", "violeta")
 > tieneContraste("blanco", "negro")

> tieneContraste("amarillo", "beige")

=> false

> tieneContraste("azul", "violeta")

=> false

> tienContraste("blanco", "negro")

tienContraste("blanco", "negro");
^

ReferenceError: tienContraste is not defined


>

Ejercicio 9: ¡Hola! Mi nombre es Xor


Ahora cambiemos las proposiciones la letra tiene tono claro y el fondo tiene tono
claro por proposiciones genéricas A y B. Además, representemos la
operación que realiza tiene contraste con el símbolo ⊻. Lo que obtenemos
es... ¡una nueva tabla!

A B A⊻B

V V F

V F V

F V V

F F F

Este comportamiento existe como un operador dentro de la lógica y se lo


denomina xor o disyunción lógica excluyente.

A diferencia del and, or y not, el xor no suele estar definido en los


lenguajes. Sin embargo, ahora que sabés cómo funciona, si alguna vez lo
necesitás podés definirlo a mano.

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

Ejercicio 10: Precedencia


Cuando una expresión matemática tiene varios operadores, sabemos que
las multiplicaciones y divisiones se efectuarán antes que las sumas y las
restas:

5 * 3 + 8 / 4 - 3 = 14

Al igual que en matemática, cuando usamos operadores lógicos las


expresiones se evalúan en un orden determinado llamado precedencia.

¿Cuál es ese orden? ¡Hagamos la prueba!

Teniendo definida la siguiente función, según la cual las tarjetas de débito


ofrecen una única cuota, y las de crédito, seis:

function pagaConTarjeta(seCobraInteres, tarjeta, efectivoDisponible) {


return !seCobraInteres && cuotas(tarjeta) >= 3 || efectivoDisponible < 100;
}

Probala en la consola con los valores:

 > pagaConTarjeta(true, "crédito", 320)


 > pagaConTarjeta(false, "crédito", 80)
 > pagaConTarjeta(true, "débito", 215)
 > pagaConTarjeta(true, "débito", 32)

> pagaConTarjeta(true, "credito", 320)

=> false

> pagaConTarjeta(false, "credito", 80)

=> true

> pagaConTarjeta(true, "debito", 215)

=> false

> pagaConTarjeta(true, "debito", 32)

=> true

>
Siguiente Ejercicio: Un ejercicio sin precedentes

Ejercicio 11: Un ejercicio sin precedentes


Si prestaste atención a la función anterior, habrás notado que la
operación con mayor precedencia es la negación !, seguida de la
conjunción && y por último la disyunción ||. ¿Pero qué pasa si quiero
alterar el orden en que se resuelven?

Al igual que en matemática, podemos usar paréntesis para agrupar las


operaciones que queremos que se realicen primero.

Delfi se puede concentrar cuando programa y toma infusiones, pero no


cualquier infusión. Tiene que ser mate a exactamente 80ºC o té que esté a
por lo menos 95ºC.

Definí la función sePuedeConcentrar que recibe una bebida, su temperatura y un


booleano que nos dice si Delfi está programando:

> sePuedeConcentrar('té', 100, true)


true

> sePuedeConcentrar('mate', 70, true)


false

> sePuedeConcentrar('té', 95, false)


false

¡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

¡Muy bien! Tu solución pasó todas las pruebas

¿Y si delegamos? Podríamos separar la lógica de la siguiente manera:

function sePuedeConcentrar(infusion, temperatura, estaProgramando) {


return infusionATemperaturaCorrecta(infusion, temperatura) && estaProgramando;
}

Al delegar correctamente, hay veces en las que no es necesario alterar el


orden de precedencia, ¡otro punto a favor de la delegación!

Ejercicio 12: ¿Puedo subir?


En un parque de diversiones de la ciudad instalaron una nueva montaña
rusa y nos pidieron ayuda para que le digamos a las personas si pueden
subirse o no antes de hacer la fila. Los requisitos para subir a la atracción
son:

 Alcanzar la altura mínima de 1.5m (o 1.2m si está acompañada por


una persona adulta)
 No tener ninguna afección cardíaca

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:

> puedeSubirse(1.7, false, true)


false // no puede subirse
// porque aunque tiene mas de 1.5m,
// tiene una afección cardíaca

 Solución
 Consola

1
function puedeSubirse(altura, acompañadaAdulto, afeccionCardiaca){
2
return ((altura >= 1.5) || (altura >= 1.2 && acompañadaAdulto)) && !afeccionCardiaca
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

¡Terminaste Lógica booleana!


¡Felicitaciones!

En esta guía aprendiste tres tipos de operadores lógicos: conjunción &&,


que es verdadero si todas sus proposiciones son verdaderas; disyunción ||,
que es verdadero si alguna de sus proposiciones es verdadera; y xor, que
es verdadero si sólo una de sus proposiciones es verdadera.

Además, aprendiste acerca de la precedencia de estos operadores, y


cómo los paréntesis pueden ayudarnos a alterar esa precedencia según
nuestras necesidades.

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.

¡Llegó entonces el momento de aprender a tratar conjuntos de cosas!


Presentamos a... ¡las listas!

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

¡Comenzá esta lección!


Ejercicio 1: Series favoritas
Supongamos que queremos representar al conjunto de nuestras series
favoritas. ¿Cómo podríamos hacerlo?

let seriesFavoritasDeAna = ["Game of Thrones", "Breaking Bad", "House of Cards"];


let seriesFavoritasDeHector = ["En Terapia", "Recordando el Show de Alejandro Molina"]

Como ves, para representar a un conjunto de strings, colocamos todos


esos strings que nos interesan, entre corchetes ([ y ]) separados por
comas. Fácil, ¿no?

Probá en la consola las siguientes consultas:

 seriesFavoritasDeAna
 seriesFavoritasDeHector
 ["hola","mundo!"]
 ["hola","hola"]

Biblioteca:

/**/

function longitud(unString) /* ... */

// Retorna cuan largo es un string

//

// Por ejemplo:

//

// > longitud("hola")

// 4

function convertirEnMayuscula(unString) /* ... */

// Convierte una palabra en mayúsculas

//

// Por ejemplo:

//
// > convertirEnMayuscula("hola")

// "HOLA"

function comienzaCon(unString, otroString) /* ... */

// Retorna un booleano que nos dice si unString empieza con otroString

//

// Por ejemplo:

//

// > comienzaCon("hola todo el mundo", "hola todo")

// true

/**/

/**/

function imprimir(unString) /* ... */

// Imprime por pantalla unString

//

// Por ejemplo:

//

// > imprimir("¡estoy imprimiendo!")

// ¡estoy imprimiendo!

function tirarDado() /* ... */

// Retorna un número al azar entre 1 y 6


//

// Por ejemplo:

//

// > tirarDado()

// 5

// > tirarDado()

// 1

// > tirarDado()

// 2

/**/

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

function longitud(unStringOLista) /* ... */

// Retorna el largo de un string o una lista

//

// Por ejemplo:
//

// > longitud("hola")

// 4

// > longitud([5, 6, 3])

// 3

function agregar(unaLista, unElemento) /* ... */

// Inserta unElemento al final de unaLista.

// Este es un procedimiento que no retorna nada pero modifica a unaLista:

//

// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]

// > agregar(cancionesFavoritas, "Seminare")

// > cancionesFavoritas

// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */

// Quita unElemento de unaLista. En caso de que no esté, no hace nada.

// Este es un procedimiento que no retorna nada pero modifica a unaLista:

//

// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]

// > remover(listaDeCompras, "pan")

// > listaDeCompras

// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.

// Si el elemento no está en la lista, retorna -1

//

// > let premios = ["dani", "agus", "juli", "fran"]

// > posicion(premios, "dani")

// 0

// > posicion(premios, "juli")

// 2

// > posicion(premios, "feli")

// -1

let seriesFavoritasDeAna = ["Game of Thrones", "Breaking Bad", "House of Cards"];

let seriesFavoritasDeHector = ["En Terapia", "Recordando el Show de Alejandro Molina"];

Consola:

ReferenceError: seriesFavoritasdDeAna is not defined


> seriesFavoritasDeAna
=> ["Game of Thrones","Breaking Bad","House of Cards"]
> seriesFavoritasDeHector
=> ["En Terapia","Recordando el Show de Alejandro Molina"]
> ["hola","hola"]
=> ["hola","hola"]
> ["hola","mundo!"]
=> ["hola","mundo!"]
>
Ejercicio 2: Y esto, es una lista
Lo que acabamos de ver es cómo modelar fácilmente conjuntos de cosas.
Mediante el uso de [], en JavaScript contamos con una manera simple de
agrupar esos elementos en listas.

¿Acaso hay una cantidad máxima de elementos? ¡No, no hay límite! Las
listas pueden tener cualquier cantidad de elementos.

Y no sólo eso, sino que además, el orden es importante. Por ejemplo, no


es lo mismo ["hola", "mundo"] que ["mundo", "hola"]: ambos tienen los mismos
elementos, pero en posiciones diferentes.
Probá en la consola las siguientes consultas:

 listasIguales(["hola", "mundo"], ["mundo", "hola"])


 listasIguales(["hola", "mundo"], ["hola", "mundo"])
 listasIguales(["hola", "mundo"], ["hola", "todo", "el", "mundo"])
 listasIguales(["hola"], ["hola", "mundo"])
 ["hola", "mundo"] === ["mundo", "hola"]
 personas
 ["mara", "julian"] === personas
 personas === personas

¿Qué conclusiones podés sacar?

 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

var personas = ["mara", "julian"];

 Consola
 Biblioteca

> listasIguales(["hola", "mundo"], ["mundo", "hola"])


=> false
> listasIguales(["hola", "mundo"], ["hola", "mundo"])
=> true
> listasIguales(["hola", "mundo"], ["hola", "todo", "el", "mundo"])
=> false
> listasIguales(["hola"], ["hola", "mundo"])
=> false
> ["hola", "mundo"] === ["mundo", "hola"]
=> false
> personas
=> ["mara","julian"]
> ["mara", "julian"] === personas
=> false
> personas === personas
=> true
>

Ejercicio 3: Juegos de azar


Pero, pero, ¿sólo podemos crear listas de strings? ¿Y si quiero, por
ejemplo, representar los números de la lotería que salieron la semana
pasada? ¿O las tiradas sucesivas de un dado? ¿O si salió cara o ceca en
tiradas sucesivas de una moneda?

let numerosDeLoteria = [2, 11, 17, 32, 36, 39];


let tiradasDelDado = [1, 6, 6, 2, 2, 4];
let salioCara = [false, false, true, false];

Como ves, también podemos representar conjuntos de números o


booleanos, de igual forma: escribiéndolos entre corchetes y separados
por comas. Podemos tener listas de números, de strings, de booleanos,
etc. ¡Incluso podríamos tener listas de listas!
Veamos si queda claro. Probá en la consola las siguientes consultas:

 numerosDeLoteria
 salioCara
 [[1, 2, 3], [4, 5, 6]]
 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

let numerosDeLoteria = [2, 11, 17, 32, 36, 39];


let tiradasDelDado = [1, 6, 6, 2, 2, 4];
let salioCara = [false, false, true, false];

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

Y no sólo eso, sino que además pueden contener cualquier cantidad de


elementos: uno, dos, quince, cientos.

¿Podremos entonces tener listas vacías, es decir, que no tengan


elementos? ¡Por supuesto!

let unaListaVacia = []

Probá escribir en la consola unaListaVacia

 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

let unaListaVacia = [];

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?

Empecemos por lo fácil: saber cuántos elementos hay en la lista. Esto lo


podemos hacer utilizando la función longitud, de forma similar a lo que
hacíamos con los strings.

Realizá las siguientes consultas en la consola:

 longitud([])
 longitud(numerosDeLoteria)
 longitud([4, 3])
 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

var numerosDeLoteria = [2, 11, 17, 32, 36, 39];

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:

let pertenencias = ["espada", "escudo", "antorcha"];


//longitud(pertenencias) devuelve 3;

agregar(pertenencias, "amuleto mágico");


//ahora longitud(pertenencias) devuelve 4

Como vemos, agregar suma un elemento a la lista, lo cual hace que su


tamaño aumente. ¿Pero en qué parte de la lista lo agrega? ¿Al principio?
¿Al final? ¿En el medio?

Averigualo vos: inspeccioná en la consola qué elementos contiene pertenencias,


agregale una "ballesta" y volvé a inspeccionar pertenencias.
Además existe un procedimiento remover, que recibe la lista y un elemento por
parámetro. Investigá en la consola qué hace.

 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true
/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]
function remover(unaLista, unElemento) /* ... */
// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

var pertenencias = ["espada", "escudo", "antorcha"];

> 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 !

Definí el procedimiento trasladar, que tome dos listas y un elemento de la


primera. trasladar debe sacar el elemento de la primera lista y agregarlo en la
segunda.
Ejemplo:

let unaLista = [1, 2, 3];


let otraLista = [4, 5];

trasladar(unaLista, otraLista, 2);

unaLista //debería ser [1, 3]


otraLista //debería ser [4, 5, 2]

¡Dame una pista!

 Solución
 Biblioteca
 Consola

1
function trasladar(lista1, lista2, elemento){
2
remover(lista1, elemento);
3
agregar(lista2, elemento);
4
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

¡Felicitaciones!

Hasta ahora anduvimos agregando, quitando y consultando longitudes.


¿Qué más podemos hacer con las listas? ¡Seguinos!

Ejercicio 8: ¿Y dónde está?


Otra cosa que queremos hacer con las listas es saber en qué posición se
encuentra un elemento. Para ello utilizamos la función posicion de la
siguiente manera:

posicion(["a", "la", "grande", "le", "puse", "cuca"], "grande"); //devuelve 2

let diasLaborales = ["lunes", "martes", "miercoles", "jueves", "viernes"]


posicion(diasLaborales, "lunes"); //devuelve 0

Como ves, lo curioso de esta función es que pareciera devolver siempre


uno menos de lo esperado. Por ejemplo, la palabra "grande" aparece
tercera, no segunda; y "lunes" es el primer día laboral, no el cero. ¿Es que
los creadores de JavaScript se equivocaron?

¡No! Se trata de que en JavaScript, al igual que en muchos lenguajes, las


posiciones de las listas arrancan en 0: el primer elemento está en la
posición 0, el segundo en la 1, el tercero en la 2, y así.
¿Y qué sucede si le pasás como argumento a posicion un elemento que no tiene?
¡Averigualo!
Probá lo siguiente:

posicion(diasLaborales, "osvaldo")
/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/
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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

var diasLaborales = ["lunes", "martes", "miercoles", "jueves", "viernes"]

Consola:

> posicion(diasLaborales, "osvaldo")


=> -1
>
Ejercicio 9: Contiene
¡Ahora te toca a vos!

Definí la función contiene que nos diga si una lista contiene un cierto elemento.

> contiene([1, 6, 7, 6], 7)


true
> contiene([1, 6, 7, 6], 6)
true
> contiene([], 7)
false
> contiene([8, 5], 7)
false

¡Dame una pista!

 Solución
 Biblioteca
 Consola

1
function contiene(lista, numero) {
2
return posicion(lista, numero) >= 0;
3
}
Enviar

¡Muy bien! Tu solución pasó todas las pruebas

¡Bien hecho!

Si venís prestando atención a los ejemplos de consulta, habrás notado


que las listas también pueden tener elementos duplicados: [1, 2, 1], ["hola",
"hola"], etc.

Por tanto, posicion en realidad devuelve la posición de la primera


aparición del elemento en la lista. Por ejemplo:
> posicion(["qué", "es", "eso", "eso", "es", "queso"], "es")
1 //devuelve 1 porque si bien "es" también está en la posición 4, aparece primero en la posición 1.

Ejercicio 10: Enésimo elemento


Así como existe una función para averiguar en qué posición está un
elemento, también puede ocurrir que queramos saber lo contrario: qué
elemento está en una cierta posición.

Para averiguarlo podemos usar el operador de indexación, escribiendo


después de la colección y entre corchetes [] la posición que queremos
para averiguar:

> mesesDelAnio[0]
"enero"
> ["ese", "perro", "tiene", "la", "cola", "peluda"][1]
"perro"

¡Ojo! El número que le pases, formalmente llamado índice, debe ser


menor a la longitud de la lista, o cosas malas pueden suceder.

Probalo en la consola: ¿qué sucede si le pedís el elemento 0 a una lista vacía? ¿O si


le pedís el elemento 48 a una lista de 2 elementos?

 Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

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.

Así que la advertencia es: ¡no te pases de índice!

Teniendo esto en cuenta, va un desafío: definí nuevamente la


función medallaSegunPuesto, pero esta vez usando como máximo un único if. Quizás
las listas te pueden ser útiles acá .
Te recordamos qué hace la función: tiene que devolver la medalla que le
corresponde a los primeros puestos de una competencia.

> medallaSegunPuesto(1)
"oro"
> medallaSegunPuesto(2)
"plata"
> medallaSegunPuesto(3)
"bronce"
> medallaSegunPuesto(4)
"nada"
> medallaSegunPuesto(5)
"nada"

¡Dame una pista!

 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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 12: No te olvides de saludar


Vamos a conocer una manera de recorrer los elementos de una lista con
un nuevo amigo: el for.
Imaginémonos que tenemos una lista con los precios de los productos
que compramos en el supermercado y queremos restar cada uno de ellos
a plataEnBilletera . Usando for podemos hacerlo así:

for(let precio of [10, 100, 87 ]) {


plataEnBilletera = plataEnBilletera - precio
}

donde plataEnBilletera es una variable que se va modificando a medida que


recorremos los precios.

Si teníamos $500 en nuestra billetera, después del for nos van a quedar
$303 porque:

 Al principio plataEnBilletera era 500 y el primer precio de la lista es 10.


Luego de hacer 500 - 10, plataEnBilletera es 490.
 A los 490 que quedaron en nuestra billetera, le restamos el
segundo precio de la lista: 100. Ahora plataEnBilletera es 390.
 El último precio a restar es 87, por lo que, al hacer 390 - 87, la
variable plataEnBilletera terminará siendo 303.

Completá el procedimiento saludar que recibe una lista de personas e imprime un


saludo con "hola" para cada una de ellas.

> saludar(["Don Pepito", "Don Jose"])


hola Don Pepito
hola Don Jose

> saludar(["Elena", "Hector", "Tita"])


hola Elena
hola Hector
hola Tita

¡Dame una pista!

 Consola

>

Biblioteca:

/**/
function longitud(unString) /* ... */
// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

Solucion

let personas = ["Cintia", "Matias", "Julieta"]

function saludar(personas) {

for(let persona of personas) {


imprimir ("hola" + " " + persona);

¡Terminaste Listas!
¡Felicitaciones!

Acabas de conocer una estructura de datos que te permite agruparlos: ¡la


lista!

También aprendiste qué datos puede tener dentro, cómo agregarle o


sacarle elementos, conocer sus posiciones, obtener su longitud y los
elementos por posición.

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.

Te presentamos una estructura que nos va a ayudar en esa tarea: los


registros.

Ejercicios

 1. Los primeros registros


 2. Tu propio monumento
 3. Accediendo al campo
 4. Temperatura de planeta
 5. Moviendo archivos
 6. Registros de dos milenios
 7. Postres complejos
 8. Listas de registros
 9. 60 dulces minutos
 10. Hay un registro en mi registro
 11. ¡Azúcar!
Ejercicio 1: Los primeros registros
Una historiadora está recopilando información acerca de distintos
monumentos a lo largo y ancho del mundo . En principio solo quiso saber
el nombre, ubicación, y año de construcción de cada monumento.

Para eso almacenó cada dato en una variable:

nombreEstatuaDeLaLibertad = "Estatua de la Libertad";


locacionEstatuaDeLaLibertad = "Nueva York";
anioDeConstruccionEstatuaDeLaLibertad = "1886";
nombreCristoRedentor = "Cristo Redentor";
locacionCristoRedentor = "Rio De Janeiro";
anioDeConstruccionCristoRedentor = "1931";

Ahí es cuando se dio cuenta que no era conveniente : si bien la


información entre las variables estaba relacionada, la estaba almacenando
por separado. Entonces pensó: ¿no existirá alguna forma de representar
las distintas características o propiedades de una misma cosa de forma
agrupada?

Luego de investigar un poco, encontró una mejor manera para guardar la


información de los monumentos. Probá en la consola escribiendo:

estatuaDeLaLibertad
cristoRedentor
torreEiffel
tajMahal
coliseo

 Biblioteca

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true
/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]
function remover(unaLista, unElemento) /* ... */
// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

=> {nombre:"Cristo Redentor",locacion:"Rio de Janeiro,


Brasil",anioDeConstruccion:1931}
> torreEiffel
=> {nombre:"Torre Eiffel",locacion:"París,
Francia",anioDeConstruccion:1889}
> tajMahal
=> {nombre:"Taj Mahal",locacion:"Agra,
India",anioDeConstruccion:1653}
> coliseo
=> {nombre:"Coliseo",locacion:"Roma, Italia",anioDeConstruccion:80}
>
Ejercicio 2: Tu propio monumento
Los monumentos que probaste en el ejercicio anterior están
representados como registros, y cada una de sus características (nombre,
locación, año de construcción) son campos del registro. Por cierto,
¡podemos crear registros de cualquier cosa, con los campos que
querramos!

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.

¡Es tu momento del monumento! Guardá en las


variables torreAzadi y monumentoNacionalALaBandera registros de esos monumentos,
oriundos de las ciudades de Teherán, Irán y Rosario, Argentina respectivamente. ¿Te
animás a investigar en qué año se terminaron de construir para completar ese
campo?
Biblioteca:
/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solucion:

let torreAzadi = { nombre: "Torre Azadi", locacion:"Teherán, Irán", anioDeConstruccion:1971 };

let monumentoNacionalALaBandera = { nombre: "Monumento Nacional A La Bandera",


locacion:"Rosario, Argentina", anioDeConstruccion:1957 };

¡Muy bien! Tu solución pasó todas las pruebas

¡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!

En un registro vamos a guardar información relacionada a una única cosa


(por ejemplo un monumento o una persona), pero los tipos de los
campos pueden cambiar. Por ejemplo, el nombre y la ubicación de un
monumento son strings, pero su año de construcción es un número.

Ejercicio 3: Accediendo al campo


Cuando consultaste los registros existentes, se veía algo parecido a lo
siguiente:

> tajMahal
{ nombre: "Taj Mahal", locacion: "Agra, India", anioDeConstruccion: 1653 }

Esa consulta era porque estábamos viendo al registro tajMahal completo,


incluyendo todos sus campos. ¡Pero también se puede consultar por un
campo particular! Mirá :

> [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

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

Siguiente Ejercicio: Temperatura de planeta


Consola:

=> {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!

Definí una función temperaturaDePlaneta que reciba como argumento un registro de


planeta y retorne un string que indique su nombre y su temperatura promedio.
¡Tiene que funcionar para cualquier planeta! Por ejemplo:

> 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"

¡Dame una pista!


Biblioteca:

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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
function longitud(unStringOLista) /* ... */
// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

Solucion:

function temperaturaDePlaneta (planeta) {

return [Link] + " tiene una temperatura promedio de " +


[Link] + " grados";

}
¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 5: Moviendo archivos


Por el momento estuvimos creando y consultando registros. ¿No sería
interesante poder... modificarlos?

La sintaxis para modificar campos de registros es muy similar a lo que


hacemos para cambiar los valores de las variables. Por ejemplo, para
cambiar la temperatura de un planeta:

[Link] = -140;

Ahora imaginá que tenemos un registro para representar un archivo, del


que sabemos su ruta (dónde está guardado) y su fecha de creación. Si
queremos cambiar su ruta podemos hacer...

> leeme
{ ruta: "C:\[Link]", creacion: "23/09/2004" }

> moverArchivo(leeme, "C:\documentos\[Link]")

Luego el registro leeme tendrá modificada su ruta:

> leeme
{ ruta: "C:\documentos\[Link]", creacion: "23/09/2004" }

¡Es tu turno! Definí el procedimiento moverArchivo, que recibe un registro y una


nueva ruta y modifica el archivo con la nueva ruta.
Biblioteca:

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true
/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]
function remover(unaLista, unElemento) /* ... */
// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solucion

function moverArchivo(archivo, nuevaruta) {

[Link] = nuevaruta

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 6: Registros de dos milenios


En el ejercicio anterior modificamos la ruta del registro, pero no
utilizamos su fecha de creación. ¡Usémosla! Queremos saber si un archivo
es del milenio pasado, lo que ocurre cuando su año es anterior a 2000.

Definí la función esDelMilenioPasado, que recibe un archivo y retorna un booleano.

> esDelMilenioPasado({ ruta: "D:\[Link]", creacion: "14/09/1989" })


true

¡Dame una pista!

Bibliotecaq

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"
function comienzaCon(unString, otroString) /* ... */
// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3
function agregar(unaLista, unElemento) /* ... */
// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

// Nos dice el año de una fecha


function anio(fecha) /* ... */

Solucion

function esDelMilenioPasado(archivo) {

return anio([Link]) < "2000";

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 7: Postres complejos


Unos ejercicios atrás te contamos la diferencia entre listas y registros.
¡Pero eso no significa que no podamos usar ambas estructuras a la vez!

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:

let flanCasero = { ingredientes: ["huevos", "leche", "azúcar", "vainilla"], tiempoDeCoccion: 50 }


let cheesecake = { ingredientes: ["frambuesas", "queso crema"], tiempoDeCoccion: 80 }
let lemonPie = { ingredientes: ["jugo de limón", "almidón de maíz", "leche", "huevos"], tiempoDeCoccio
n: 65 }

Definí la función masDificilDeCocinar, que recibe dos registros de postres como


argumentos y retorna el que tiene más ingredientes de los dos.

Biblioteca:
> masDificilDeCocinar(flanCasero, cheesecake)
{ ingredientes: ["huevos", "leche", "azúcar", "vainilla"], tiempoDeCoccion: 50 }
/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solucion:

function masDificilDeCocinar(postre1, postre2) {

if (longitud([Link]) > longitud([Link])) {

return postre1;

} else {
return postre2;

Ejercicio 8: Listas de registros


En el ejercicio anterior te mostramos que un registro puede tener una lista
entre sus campos. ¿Y al revés? ¿Podemos tener una lista de registros?

¡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 [].

Probá en la consola las listas postresFavoritos y monumentosDeAmerica. Hay un postre que


no mostramos antes, ¿te das cuenta cuál es solamente leyendo sus ingredientes?
Biblioteca:

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

Ejercicio 8: Listas de registros


En el ejercicio anterior te mostramos que un registro puede tener una lista
entre sus campos. ¿Y al revés? ¿Podemos tener una lista de registros?

¡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 [].

Probá en la consola las listas postresFavoritos y monumentosDeAmerica. Hay un postre que


no mostramos antes, ¿te das cuenta cuál es solamente leyendo sus ingredientes?

Biblioteca:
/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

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}]

Ejercicio 9: 60 dulces minutos


A veces no sólo queremos comer algo rico, sino que queremos comerlo lo
antes posible.

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:

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]
function remover(unaLista, unElemento) /* ... */
// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solucion:

function agregarAPostresRapidos(postresRapidos, postre) {

if ([Link] <= 60) {

agregar(postresRapidos, postre);

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 10: Hay un registro en mi registro


¿Te acordás cuando vimos que una lista podía estar compuesta por otras
listas? ¡Con los registros aplica la misma idea! Si tenemos alguna
estructura de datos compleja, puede ocurrir que no alcance con
representarla únicamente mediante strings, números, booleanos y listas,
sino que necesitemos otro registro dentro.

¡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

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

/**/

Siguiente Ejercicio: ¡Azúcar!


Consola:

> [Link]
=> ["galletitas","dulce de leche","crema"]
>
Ejercicio 11: ¡Azúcar!
Para terminar, trabajemos una vez más con los menúes.

Definí un procedimiento endulzarMenu, que recibe un registro menú y le


agrega azúcar a los ingredientes de su postre. Si ya tiene azúcar, no importa... ¡le
agrega más!
¡Dame una pista!

Biblioteca:

/**/

function convertirEnMayuscula(unString) /* ... */


// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!
function tirarDado() /* ... */
// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solcion

function endulzarMenu(menuDelDia) {

agregar([Link], "azúcar")

¡Muy bien! Tu solución pasó todas las pruebas

¡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

 1. Las ganancias semestrales


 2. ¿Y el resto de las ganancias?
 3. Todas las ganancias, la ganancia
 4. Nos visita un viejo amigo
 5. Cuentas claras
 6. La ganancia promedio
 7. Quién gana, quién pierde
 8. Soy el mapa, soy el mapa
 9. A filtrar, a filtrar cada cosa en su lugar
 10. Un promedio más positivo
 11. Esto es lo máximo
 12. Como mínimo
 13. Los mejores meses del año

¡Comenzá esta lección!

Ejercicio 1: Las ganancias semestrales


Ana, contadora de una conocida empresa , tiene registros para
representar los balances de cada mes y una lista para guardarlos. Por
ejemplo, para el último semestre del año pasado registró los siguientes:

//En julio ganó $50, en agosto perdió $12, etc


let balancesUltimoSemestre = [
{ mes: "julio", ganancia: 50 },
{ mes: "agosto", ganancia: -12 },
{ mes: "septiembre", ganancia: 1000 },
{ mes: "octubre", ganancia: 300 },
{ mes: "noviembre", ganancia: 200 },
{ mes: "diciembre", ganancia: 0 }
];

Y nos acaba de preguntar: "¿puedo saber la ganancia de todo un


semestre?"

"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:

//En enero la empresa ganó $80, en febrero, $453, en marzo $1000


let balancesPrimerTrimestre = [
{ mes: "enero", ganancia: 80 },
{ mes: "febrero", ganancia: 453 },
{ mes: "marzo", ganancia: 1000 }
];

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 :

1. Es muy repetitiva y tediosa de escribir. ¡Tenemos que hacer muchas


sumas a mano!
2. No es genérica, como bien dice su nombre, sólo sirve para sumar
las ganancias de 6 balances:

 si la lista tiene más de seis balances, sólo suma los primeros;


 si tiene menos, no funciona (¿te acordás cuando te dijimos que si te
ibas de índice cosas malas podían ocurrir? )

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!

¡Relajá! Ya tenemos nuestra versión; probala con las siguientes consultas:

> 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([])

Después seguinos para contarte cómo la hicimos.


> gananciaTotal([
{ mes: "enero", ganancia: 2 },
{ mes: "febrero", ganancia: 3 }
])
=> 5
> 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 }
])
=> 21
> gananciaTotal([])
=> 0
>
Ejercicio 3: Todas las ganancias, la ganancia
Ahora que sabemos la función que necesitamos (gananciaTotal), razonemos
cómo hacerla...

Vamos de a poquito : si la lista no tuviera elementos, ¿cuánto debería ser


la sumatoria? ¡0!

function gananciaTotal0(balancesDeUnPeriodo) {
let sumatoria = 0;
return sumatoria;
}

¿Y si tuviera exactamente 1 elemento? Sería... 0.... ¿más ese elemento?


¡Exacto!

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;
}

¿Empezás a ver un patrón? Tratá de escribir gananciaTotal4 que funcione para 4


elementos.
Solucion

function gananciaTotal4(balancesDeUnPeriodo) {

let sumatoria = 0;

sumatoria = sumatoria + balancesDeUnPeriodo[0].ganancia;

sumatoria = sumatoria + balancesDeUnPeriodo[1].ganancia;

sumatoria = sumatoria + balancesDeUnPeriodo[2].ganancia;

sumatoria = sumatoria + balancesDeUnPeriodo[3].ganancia;

return sumatoria;

¡Muy bien! Tu solución pasó todas las pruebas

¡Bien hecho!

¿Y si la lista tuviera cualquier cantidad de elementos? Si seguimos


repitiendo este patrón, veremos que una sumatoria de una lista siempre
arranca igual, con let sumatoria = 0, y termina igual, devolviendo la variable
local sumatoria (return sumatoria).

function gananciaTotalN(unPeriodo) {
let sumatoria = 0; // esto siempre está
//... etc
return sumatoria; //esto siempre está
}

Lo que cambia son las acumulaciones (sumatoria = sumatoria + ...);


necesitamos una por cada elemento de la lista. Dicho de otra forma,
tenemos que visitar cada elemento del mismo, sin importar cuántos
tenga. Pero, ¿cómo hacerlo? ¿No te suena conocida esta idea de repetir
algo muchas veces?

Siguiente Ejercicio: Nos visita un viejo amigo

Ejercicio 4: Nos visita un viejo amigo


Lo que tenemos que hacer, entonces, es repetir la operación de acumular
varias veces, una por cada elemento de la lista. ¡Digamos
hola (nuevamente) al for...of!

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.

¿Aún no te convenciste? Nuevamente, probá las siguientes expresiones en la


consola:

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

Completá la función cantidadDeBalancesPositivos. Si prestás atención, notarás que tiene


una estructura similar al problema anterior.
¡Dame una pista!

Solucion

function cantidadDeBalancesPositivos(balancesDeUnPeriodo) {
let cantidad = 0;

for (let balance of balancesDeUnPeriodo) {

if ([Link] > 0) {

cantidad = cantidad + 1;

return cantidad;

¡Muy bien! Tu solución pasó todas las pruebas

cantidad es lo que en programación se conoce como contador, una variable


que se incrementa cada vez que hacemos algo dentro de un for...of o solo
aquellas veces que se cumpla una condición (como en este caso ).

Ejercicio 6: La ganancia promedio


Pasemos al siguiente requerimiento de Ana. Ya podemos calcular una
sumatoria de ganancias y también crear contadores, ahora vamos a
calcular promedios.

Ana quisiera saber dado un conjunto cualquiera de balances cuál es


su gananciaPromedio.

> gananciaPromedio([
{ mes: "marzo", ganancia: 8 },
{ mes: "agosto", ganancia: 10 }
])
9

¡Dame una pista!

Solucion

function gananciaPromedio(balances) {

return gananciaTotal(balances) / longitud(balances)

¡Muy bien! Tu solución pasó todas las pruebas

¡Perfecto! Vamos a complicar un poco las cosas.

Siguiente Ejercicio: Quién gana, quién pierde


Ejercicio 7: Quién gana, quién pierde
Viendo que podemos hacer todo lo que nos pide, Ana quiere saber la
ganancia promedio de los balances positivos.

Definí las funciones:

 gananciaPositiva, que es la suma de las ganancias de los balances positivos


 promedioGananciasPositivas invocando gananciaPositiva y cantidadDeBalancesPositivos.

¡Dame una pista!


Bilbioteca

function cantidadDeBalancesPositivos(balancesDeUnPeriodo) {
let cantidad = 0;
for (let balance of balancesDeUnPeriodo) {
if ([Link] > 0) {
cantidad = cantidad + 1;
}
}
return cantidad;
}

Solucion

function gananciaPositiva(balancesDeUnPeriodo) { let sumatoria = 0; for (let balance of


balancesDeUnPeriodo) { if([Link] > 0){ sumatoria = sumatoria + [Link]; }
} return sumatoria; } function promedioGananciasPositivas(balancesDeUnPeriodo) { return
gananciaPositiva(balancesDeUnPeriodo) /
cantidadDeBalancesPositivos(balancesDeUnPeriodo); }

¡Muy bien! Tu solución pasó todas las pruebas

Como podés ver todos los promedios se basan en el mismo principio .


Sumar una cantidad determinada elementos y dividir el resultado por esa
cantidad. Si quisiéramos realizar una función promedio genérica sería algo
así:

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?

Ejercicio 8: Soy el mapa, soy el mapa


Lamentablemente no se puede usar la función promedio con nuestra lista
de registros . Lo que necesitamos es una lista que tenga solo las
ganancias de cada balance. Para ello debemos transformar, o mapear,
cada elemento de la lista.

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) {

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;
}

*/

¡Muy bien! Tu solución pasó todas las pruebas

¡Excelente! Ahora ya sabemos cómo transformar cada elemento de una


lista para obtener una lista nueva . De esta manera podemos
usar promedio con nuestra lista de balances. Pero, ¿se puede utilizar la
función promedio solo para los balances positivos?

Ejercicio 9: A filtrar, a filtrar cada cosa en su lugar


Con la programación se puede hacer cualquier cosa, o casi . Ya hicimos
una función para poder saber la cantidad de balances positivos
(cantidadDeBalancesPositivos), ahora vamos a ver cómo podemos hacer para
saber cuáles son esos balances.

Completá la función balancesPositivos que toma los balances de un período y devuelve


una lista con aquellos cuya ganancia fue mayor a cero.
¡Dame una pista!

Solución

function balancesPositivos(balancesDeUnPeriodo) { let balances = []; for (let balance of


balancesDeUnPeriodo) { if ([Link] > 0) { agregar(balances, balance); } } return
balances; }

¡Muy bien! Tu solución pasó todas las pruebas

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

Ejercicio 10: Un promedio más positivo


Ahora que tenemos la función ganancias y balancesPositivos podemos utilizar
la función promedio genérica para saber cuál es el promedio de ganancia
de los balances positivos.

Definí la función gananciasDeBalancesPositivos y luego usala junto a promedio para


definir promedioDeBalancesPositivos.
¡Dame una pista!

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;
}

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

Solución

function gananciasDeBalancesPositivos(balancesDeUnPeriodo) {

return ganancias(balancesPositivos(balancesDeUnPeriodo)) ;

function promedioDeBalancesPositivos(balancesDeUnPeriodo) {

return promedio(gananciasDeBalancesPositivos(balancesDeUnPeriodo));

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 11: Esto es lo máximo


Vamos a conocer una nueva función, maximo, que nos permite conocer
cuál es el mayor valor en una lista de números. Por ejemplo:

> maximo([5, 8, 10, 42, 87, 776])


776

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

¡Dame una pista!

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 maximo(numeros) /* ... */


// Retorná el número más grande de una lista de números:
//
// > maximo([4, 8, 87, 3])
// 87

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

Solución

function maximaGanancia(balancesDeUnPeriodo) { return


maximo(ganancias(balancesDeUnPeriodo)); }

¡Muy bien! Tu solución pasó todas las pruebas

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?

Ejercicio 12: Como mínimo


Suponemos que adivinaste el nombre. En caso que no, es minimo.

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

function minimo(numeros) /* ... */


// Retorna el menor valor dentro de una lista de números:
//
// > minimo([5, 7, 8, 9, 3])
// => 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

Solución

function minimaGananciaPositiva(balance) {

return minimo(gananciasDeBalancesPositivos(balance));

¡Muy bien! Tu solución pasó todas las pruebas

¡Muy bien! Solo queda un ejercicio por delante.


Ejercicio 13: Los mejores meses del año
¡Vamos a terminar esta lección con todo!

Para eso vamos a hacer las siguientes funciones:

 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"]

Definí las funciones meses, afortunados, mesesAfortunados.


¡Dame una pista!

Biblioteca

/**/

function longitud(unString) /* ... */


// Retorna cuan largo es un string
//
// Por ejemplo:
//
// > longitud("hola")
// 4
function convertirEnMayuscula(unString) /* ... */
// Convierte una palabra en mayúsculas
//
// Por ejemplo:
//
// > convertirEnMayuscula("hola")
// "HOLA"

function comienzaCon(unString, otroString) /* ... */


// Retorna un booleano que nos dice si unString empieza con otroString
//
// Por ejemplo:
//
// > comienzaCon("hola todo el mundo", "hola todo")
// true

/**/

/**/

function imprimir(unString) /* ... */


// Imprime por pantalla unString
//
// Por ejemplo:
//
// > imprimir("¡estoy imprimiendo!")
// ¡estoy imprimiendo!

function tirarDado() /* ... */


// Retorna un número al azar entre 1 y 6
//
// Por ejemplo:
//
// > tirarDado()
// 5
// > tirarDado()
// 1
// > tirarDado()
// 2

/**/

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

function longitud(unStringOLista) /* ... */


// Retorna el largo de un string o una lista
//
// Por ejemplo:
//
// > longitud("hola")
// 4
// > longitud([5, 6, 3])
// 3

function agregar(unaLista, unElemento) /* ... */


// Inserta unElemento al final de unaLista.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]
// > agregar(cancionesFavoritas, "Seminare")
// > cancionesFavoritas
// ["La colina de la vida", "Zamba por vos", "Seminare"]

function remover(unaLista, unElemento) /* ... */


// Quita unElemento de unaLista. En caso de que no esté, no hace nada.
// Este es un procedimiento que no retorna nada pero modifica a unaLista:
//
// > let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]
// > remover(listaDeCompras, "pan")
// > listaDeCompras
// ["leche", "arroz", "aceite", "yerba"]

function posicion(unaLista, unElemento) /* ... */


// Retorna la posición en que se encuentra unElemento en unaLista.
// Si el elemento no está en la lista, retorna -1
//
// > let premios = ["dani", "agus", "juli", "fran"]
// > posicion(premios, "dani")
// 0
// > posicion(premios, "juli")
// 2
// > posicion(premios, "feli")
// -1

Solución

function meses(gananciasDeUnPeriodo){

let mes=[]

for(let periodo of gananciasDeUnPeriodo){

agregar(mes,[Link])

return mes;

}
function afortunados (gananciasDeUnPeriodo){

let afortunado=[]

for(let balance of gananciasDeUnPeriodo){

if([Link]>1000){

agregar(afortunado,balance)

return afortunado

function mesesAfortunados (gananciasDeUnPeriodo){

return meses(afortunados(gananciasDeUnPeriodo))

¡Muy bien! Tu solución pasó todas las pruebas

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

¡Muy buen trabajo!

Capítulo 3: Programación con Objetos


El paradigma de objetos, a veces también conocido como orientado a
objetos nos propone solucionar problemas y modelar nuestra realidad
empleando objetos que se comunican entre ellos intercambiando
mensajes. ¡Adentrémonos en el mundo de los objetos y Ruby!

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.

¿Y cómo interactúan estos objetos? ¿Cómo se ven? ¿Cómo hablan entre


ellos?

¡Cuántas preguntas! Vamos por partes: ¡conozcamos a nuestros primeros


objetos!

Ejercicios

 1. Fijando nuestro objetivo


 2. ¡Hola Pepita!
 3. Un mundo de objetos
 4. El derecho a la Identidad
 5. Mensajes, primera parte
 6. Mensajes, segunda parte
 7. No entendí...
 8. Un poco de sintaxis
 9. Interfaz
 10. Hacer versus Devolver
 11. Tu primer programa con objetos
 12. ¿Quién te entiende?
 13. Interfaces compartidas
 14. Argumentos
 15. Más argumentos
 16. Mensajes por todas partes
 17. Recapitulando

¡Comenzá esta lección!

Ejercicio 1: Fijando nuestro objetivo


Anteriormente mencionamos los paradigmas de programación. En este
capítulo vamos a conocer otra forma de pensar el mundo de la
programación.

El paradigma de programación con objetos o programación orientada


a objetos nos propone tratar con… ¡Adiviná! Sí, nos permite trabajar con
objetos.
Estos objetos pueden ser cualquier cosa, material o abstracta . Un objeto
es cualquier entidad que pueda hacer algo por nosotros para resolver un
problema.

Lo importante es que estos objetos viven dentro de un mismo mundo y


cada uno de ellos va a tener distintas responsabilidades. Además, van a
poder comunicarse entre ellos mandándose mensajes.

Para aprender a hacer todo esto, vamos a utilizar un lenguaje llamado


Ruby.

Ejercicio 2: ¡Hola Pepita!


Para empezar en este mundo, conozcamos a Pepita, una golondrina.

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.

¡Probalo! Hacé las siguientes consultas en la consola:

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

En Ruby, podemos comparar por identidad a dos objetos utilizando el


operador == de la siguiente forma:

> Pepita == Norita

¡Intentalo por tu propia cuenta! Ejecutá las siguientes pruebas en la consola:

> Pepita == Norita


> Norita == Pepita
> Norita == Norita
> "hola" == "chau"

¡Dame una pista!


> Pepita == Norita
=> false
> Norita == Pepita
=> false
> Norita == Norita
=> true
> "hola" == "chau"
=> false
>
Ejercicio 5: Mensajes, primera parte
Ya entendimos que en un ambiente hay objetos, y que cada uno de ellos
tiene identidad: sabe que es diferente de otro.

Pero esto no parece ser muy útil. ¿Qué cosas sabrá hacer una golondrina
como Pepita? ¿Sabrá, por ejemplo, cantar!?

Averigualo: enviale un mensaje cantar! y fijate qué pasa...

> [Link]!

¡Dame una pista!

> [Link]!
=> "pri pri pri"
>
Ejercicio 6: Mensajes, segunda parte
Ehhhh, ¿qué acaba de pasar acá?

Para comunicarnos con los objetos, debemos enviarles mensajes. Cuando


un objeto recibe un mensaje, este responde haciendo algo. En este
caso, Pepita produjo el sonido de una golondrina: pri pri pri ...imaginate acá
que escuchamos este sonido... .

¿Qué mas sabrá hacer Pepita? ¿Sabrá, por ejemplo, bailar!?

¡Descubrámoslo! Enviale el mensaje bailar!

> [Link]!

> [Link]!
undefined method `bailar!' for Pepita:Module (NoMethodError)
>
Ejercicio 7: No entendí...
¡Buu, Pepita no sabía bailar!

En el mundo de los objetos, sólo tiene sentido enviarle un mensaje a un


objeto si lo entiende, es decir, si sabe hacer algo como reacción a ese
mensaje. De lo contrario, se lanzará un error un poco feo (y en inglés )
como el siguiente:

undefined method `bailar!' for Pepita:Module

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:

1. [Link] es un envío de mensaje, también


llamado colaboración;
2. energia es el mensaje;
3. energia es el nombre del mensaje (en este caso es igual, pero ya
veremos otros en los que no);
4. Pepita es el objeto receptor del mensaje.

Es importante respetar la sintaxis del envío de mensajes. Por ejemplo, las


siguientes NO son colaboraciones validas, porque no funcionan o no
hacen lo que deben:

> energia
> Pepita energia
> Pepita..energia

¿Eh, no nos creés? ¡Probalas!


> energia
undefined local variable or method `energia' for main:Object
(NameError)
> Pepita energia
undefined local variable or method `energia' for main:Object
(NameError)
> Pepita..energia
undefined local variable or method `energia' for main:Object
(NameError)
>
Ejercicio 9: Interfaz
Como vimos, un objeto puede entender múltiples mensajes; a este
conjunto de mensajes que podemos enviarle lo denominamos interfaz.
Por ejemplo, la interfaz de Pepita es:

 energia: nos dice cuanta energía tiene (un número);


 cantar!: hace que cante;
 comer_lombriz!: hace que coma una lombriz;
 volar_en_circulos!: hace que vuele en circulos.

Lo cual también se puede graficar de la siguiente forma:

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

En realidad, un mensaje podría reaccionar con una combinación de las


formas anteriores: tener un efecto y devolver algo. Pero esto es una muy
mala idea.

¿Y qué hay de los mensajes como comer_lombriz! y volar_en_circulos!? ¿Hicieron algo?


¿Qué clase de efecto produjeron? ¿Devuelve energia siempre lo mismo?
Descubrilo: enviale a Pepita esos tres mensajes varias veces en distinto orden y fijate
si cambia algo
> Pepita.comer_lombriz!
=> nil
> Pepita.volar_en_circulos!
=> nil
> [Link]
=> 110
> Pepita
=> Pepita
>
> [Link]
=> 110
> Pepita.volar_en_circulos!
=> nil
> [Link]
=> 100
> Pepita.comer_lombriz!
=> nil
>
Ejercicio 11: Tu primer programa con objetos
¡Exacto! El efecto que producen los
mensajes comer_lombriz! y volar_en_circulos! es el de alterar la energía
de Pepita. En concreto:

 comer_lombriz! hace que la energia de Pepita aumente en 20 unidades;


 volar_en_circulos! hace que la energia de Pepita disminuya en 10
unidades.

Como convención, a los mensajes con efecto (es decir, que hacen algo)
les pondremos un signo de exclamación ! al final.

Veamos si se entiende: escribí un primer programa que consista en hacer


que Pepita coma y vuele hasta quedarse con 150 unidades de energía. Acordate
que Pepita arranca con la energía en 100.
¡Dame una pista!

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]

¡Muy bien! Tu solución pasó todas las pruebas

Podemos sacar dos conclusiones:

1. Los objetos no reaccionan necesariamente siempre igual a los


mismos mensajes. Podrían hacer cosas diferentes, o en este caso,
devolver objetos distintos.
2. ¡Un programa es simplemente una secuencia de envío de mensajes!

Ejercicio 12: ¿Quién te entiende?


Ya vimos que un objeto puede entender múltiples mensajes, y esos
mensajes conforman su interfaz.

¿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!

¡Muy bien! Tu solución pasó todas las pruebas

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

Ejercicio 13: Interfaces compartidas


Veamos si queda claro, siendo que las interfaces
de Norita, Pepita y Mercedesson las siguientes:
Esto significa que comparten algunos mensajes y otros no. ¿Qué
interfaces comparten entre ellas?

Completá el código en el editor.


Solución

# ¿Qué interfaz comparten Mercedes y Norita?

interfaz_compartida_entre_mercedes_y_norita = %w(

cantar!

# ¿Qué interfaz comparten Pepita y Norita?

interfaz_compartida_entre_pepita_y_norita = %w(

cantar!

comer_lombriz!

volar_en_circulos!

# ¿Qué interfaz comparten Mercedes, Norita y Pepita?

interfaz_compartida_entre_todas = %w(

cantar!

) ¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 14: Argumentos


Para hacer las cosas más interesantes, vamos a necesitar mensajes más
complejos.
Por ejemplo, si queremos que Pepita coma una cierta cantidad de alpiste
que no sea siempre la misma, necesitamos de alguna manera indicar cuál
es esa cantidad. Esto podemos escribirlo de la siguiente forma:

Pepita.comer_alpiste! 40

Allí, 40 es un argumento del mensaje, representa en este caso que vamos


a alimentar a pepita con 40 gramos de alpiste. Un mensaje podría tomar
más de un argumento, separados por coma.

Probá enviar los siguientes mensajes:

> Pepita.volar_hacia! Iruya


> Pepita.comer_alpiste! 39
> Pepita.comer_alpiste! 6, Norita

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

> Pepita.comer_alpiste! 6, Norita


# wrong number of arguments (2 for 1) (ArgumentError)

...el envío del mensaje también fallará.

Dicho de otra forma, un mensaje queda identificado no sólo por su


nombre sino también por la cantidad de parámetros que tiene: no es
lo mismo comer_alpiste! que comer_alpiste! 67 que comer_alpiste! 5, 6, son todos
mensajes distintos. Y en este caso, Pepita sólo entiende el segundo.

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!

Un detalle: en Ruby, a veces, los paréntesis son opcionales. Por eso,


cuando no sean imprescindibles los omitiremos.

Ejercicio 16: Mensajes por todas partes


Es fácil ver que en Pepita.volar_hacia! Barreal el objeto receptor es Pepita, el
mensaje volar_hacia! y el argumento Barreal; pero ¿dónde queda eso de
objeto y mensaje cuando hacemos, por ejemplo, 2 + 3?

Como ya dijimos, todas nuestras interacciones en un ambiente de objetos


ocurren enviando mensajes y las operaciones aritméticas no son la
excepción a esta regla.

En el caso de 2 + 3 podemos hacer el mismo análisis:

 el objeto receptor es 2;
 el mensaje es +;
 el argumento es 3.

Y de hecho, ¡también podemos escribirlo como un envío de mensajes


convencional!

Probá en la consola los siguientes envíos de mensajes:

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

> Mensajes de palabra clave. Su nombre está compuesto por una o


varias palabras, puede terminar con un signo de exclamación ! o de
pregunta ?, y se envía mediante un punto. Además,
 pueden no tomar argumentos, como Rayuela.anio_de_edicion;
 o pueden tomar uno o más argumentos, separados por
coma: [Link]! LosAndes, Mula.

> Operadores. Son todos aquellos cuyo "nombre" se compone de uno o


más símbolos, y se envían simplemente escribiendo dichos símbolos. En
cuanto a los argumentos,

 pueden no tomar ninguno, como la negación !true;


 o pueden tomar uno (y solo uno), como Orson == Garfield o energia +
80.

Como vimos, también se pueden escribir como mensajes de palabra clave


(aunque no parece buena idea escribir 1.== 2 en vez de 1 == 2 ).

Vamos a enviar algunos mensajes para terminar de cerrar la idea. Te toca escribir
un programa que haga que Pepita:

1. Coma 90 gramos de alpiste.


2. Vuele a Iruya.
3. Finalmente, coma tanto alpiste como el 10% de la energía que le haya
quedado.

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)

¡Terminaste Objetos y mensajes!


¡Felicitaciones! Diste tus primeros pasos en el mundo de los objetos. Ya
sabés:

 Que un objeto es la representación de algún aspecto del problema


que queremos resolver.
 Que los objetos tienen identidad y saben diferenciarse de otros
objetos.
 Que interactuamos con los objetos mediante el envío de mensajes.
 Que al conjunto de mensajes que un objeto entiende lo
llamamos interfaz.
 Que si le enviamos un mensaje que no entiende, se produce
un error.

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.

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.

¿Y cómo interactúan estos objetos? ¿Cómo se ven? ¿Cómo hablan entre


ellos?

¡Cuántas preguntas! Vamos por partes: ¡conozcamos a nuestros primeros


objetos!

Ejercicios

 1. Fijando nuestro objetivo


 2. ¡Hola Pepita!
 3. Un mundo de objetos
 4. El derecho a la Identidad
 5. Mensajes, primera parte
 6. Mensajes, segunda parte
 7. No entendí...
 8. Un poco de sintaxis
 9. Interfaz
 10. Hacer versus Devolver
 11. Tu primer programa con objetos
 12. ¿Quién te entiende?
 13. Interfaces compartidas
 14. Argumentos
 15. Más argumentos
 16. Mensajes por todas partes
 17. Recapitulando

¡Felicitaciones! Diste tus primeros pasos en el mundo de los objetos. Ya


sabés:

 Que un objeto es la representación de algún aspecto del problema


que queremos resolver.
 Que los objetos tienen identidad y saben diferenciarse de otros
objetos.
 Que interactuamos con los objetos mediante el envío de mensajes.
 Que al conjunto de mensajes que un objeto entiende lo
llamamos interfaz.
 Que si le enviamos un mensaje que no entiende, se produce
un error.

Pero aún queda mucho más por aprender. ¡Te esperamos en la próxima
lección!

Definiendo objetos: métodos y estado


¡Hola de nuevo!

Ya aprendiste que en un ambiente hay objetos que hacen cosas, y que


nos comunicamos con ellos mediante el envío de mensajes.

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.

¡Aprendamos entonces a crear objetos!

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?

¡Comenzá esta lección!

Ejercicio 1: Creando a Pepita


Inicialmente en el ambiente solo existen objetos simples como números,
strings y booleanos.

Pero como es imposible que quienes diseñan un lenguaje puedan


precargar objetos para solucionar todos nuestros problemas, también nos
dan la posibilidad de crear los nuestros.

En Ruby, si quisiéramos definir a Norita, escribiríamos el siguiente código:

module Norita
end

Sí, así de simple.

¿Te animás a modificar nuestro código para crear a Pepita?


Solución

module Pepita

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Muy bien, Pepita vive!

Como dedujiste, la definición de un objeto se inicia con la palabra


reservada module, luego el nombre del objeto (con la primera letra en
mayúscula) y su fin se indica con un end.

Ejercicio 2: Pepita, ¿me entendés?


En la lección anterior Pepita entendía los
mensajes comer_lombriz!, cantar!, volar_en_circulos! y energia.

Con la definición que construimos recién, ¿podrá responderlos?


Intentá enviarle a Pepita los mensajes habituales y fijate qué sucede.
Biblioteca

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?

Para que un objeto entienda un mensaje debemos "enseñarle" cómo


hacerlo, y para ello es necesario definir un método dentro de ese objeto:

module Pepita
def [Link]!
end
end

Un método es, entonces, la descripción de qué hacer cuando se recibe


un mensaje del mismo nombre.

Dos cosas muy importantes a tener en cuenta :

 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

¡Muy bien! Tu solución pasó todas las pruebas

Perfecto, ahora Pepita entiende casi todos los mismos mensajes que en la
lección anterior. Pero, ¿hacen lo mismo?

Antes de seguir, enviá algunos de los mensajes en la Consola y fijate


qué efecto producen sobre nuestra golondrina.

Ejercicio 4: Perdiendo energía


Acabamos de aprender una de las reglas fundamentales del envío de
mensajes: si a un objeto no le decímos cómo reaccionar ante un mensaje,
y se lo envíamos, no lo entenderá y nuestro programa se romperá. Y la
forma de hacer esto es definiendo un método.

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.

¿Cómo podríamos decir que cuando Pepita vuela, pierde 10 unidades de


energía? ¿Y que inicialmente esta energía es 100? Así:

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]

Puede que los resultados te sorprendan, en breve hablaremos de esto.


> Pepita.volar_en_circulos!
=> 90
> Pepita.volar_en_circulos!
=> 80
> [Link]
undefined method `energia' for Pepita:Module (NoMethodError)
Ejercicio 5: Atributos
Analicemos el código que acabamos de escribir:

module Pepita
@energia = 100

def self.volar_en_circulos!
@energia = @energia - 10
end
end

Decimos que Pepita conoce o tiene un nivel de energía, que es variable, e


inicialmente toma el valor 100. La energía es un atributo de nuestro
objeto, y la forma de asignarle un valor es escribiendo @energia = 100.

Por otro lado, cuando Pepita recibe el mensaje volar_en_circulos!, su energía


disminuye: se realiza una nueva asignación del atributo y pasa a valer lo
que valía antes (o sea, @energia), menos 10.

Como la operación @energia = @energia - 10 es tan común, se puede


escribir @energia -= 10. Como te imaginarás, también se puede hacer con la
suma.

Sabiendo esto:

 cambiá la definición del método volar_en_circulos! para que utilice la expresión


simplificada;
 definí la versión correcta del método comer_lombriz!, que provoca
que Pepita gane 20 puntos de energía;

solución

module Pepita

@energia = 100

def self.volar_en_circulos!

@energia-=10
end

def self.comer_lombriz!

@energia+=20

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Acabamos de aprender un nuevo elemento del paradigma de objetos:


los atributos (los cuales escribiremos anteponiendo @), son objetos que
nos permiten representar una característica de otro objeto. Un objeto
conoce a todos sus atributos por lo que puede enviarles mensajes, tal
como hicimos con @energia.

Entonces, si le pude enviar mensajes a @energia, ¿eso significa que los


números también son objetos?
¡Claro que sí! ¡Todo-todo-todo es un objeto!

Ejercicio 6: Conociendo el país


Hasta ahora los métodos que vimos solo producían un efecto. Si bien solo
pueden devolver una cosa, ¡pueden producir varios efectos!

Solo tenés que poner uno debajo del otro de la siguiente forma:

def self.comprar_libro!
@plata -= 300
@libros += 1
end

Como te dijimos, Pepita podía volar a diferentes ciudades. Y cuando lo


hace, cambia su ciudad actual, además de perder 100 unidades de energía.
Las distintas ciudades vas a poder verlas en la Biblioteca.

Con esto en mente:

 Creá un atributo ciudad en Pepita: la ciudad donde actualmente está nuestra


golondrina.
 Hacé que la ciudad inicial de pepita sea Iruya.
 Definí un método volar_hacia! en Pepita, que tome como argumento otra
ciudad y haga lo necesario.

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

Ejercicio 7: Leyendo el estado


Antes te mostramos que si enviamos el mensaje energia, fallará:

> [Link]
undefined method `energia' for Pepita:Module (NoMethodError)

El motivo es simple: los atributos NO son mensajes.

Entonces, ¿cómo podríamos consultar la energía de Pepita? Definiendo un


método, ¡por supuesto!

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

¿Todas las consultas funcionan? ¿Por qué?


> [Link]
=> 100
> [Link] = 120
undefined method `energia=' for Pepita:Module (NoMethodError)
Did you mean? energia
> energia
undefined local variable or method `energia' for main:Object
(NameError)
>
Ejercicio 8: Cuestión de estado
Los objetos pueden tener múltiples atributos y al conjunto de estos
atributos se lo denomina estado. Por ejemplo, si miramos a Pepita:

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.

El estado es siempre privado, es decir, solo el objeto puede utilizar sus


atributos, lo que explica por qué las siguiente consultas que hicimos antes
fallaban:

> [Link] = 100


> energia

Veamos si se entiende: mirá los objetos en la solapa Biblioteca y escribí el estado


de cada uno.
Biblioteca

module Obera
#...más cosas que ahora no interesan...
end

module Pepita
@energia = 100
@ciudad = Obera

#...más cosas que ahora no interesan...


end

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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 9: ¿Dónde estás?


Queremos saber dónde se encuentra Pepita, para lo cual necesitamos
agregarle un mensaje ciudad que nos permita acceder al atributo del
mismo nombre.

Inspirándote en la definición de energia, definí el método ciudad que retorne la


ubicación de nuestra golondrina.
Solucion

module Pepita

@energia = 100

@ciudad = Obera

def [Link]

@energia

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)

@energia -= 100

@ciudad = destino

end

def [Link]

@ciudad

end

end

¡Muy bien! Tu solución pasó todas las pruebas

A estos métodos que sirven para conocer el valor de un atributo los


llamamos métodos de acceso o simplemente accessors, por su nombre
en inglés.

Ejercicio 10: Volando alto


Volar hacia un cierto punto no es tarea tán fácil: en realidad, Pepita pierde
tanta energía como la mitad de kilómetros que tenga que recorrer.

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.

¿Y si Pepita está en Iruya y quiere volar a Obera? ¡También! La distancia entre


dos ciudades siempre es un valor positivo . Para resolver esto contamos
con el mensaje abs que entienden los números y nos retorna su valor
absoluto:

> [Link]
=> 17

> (-17).abs
=> 17

> (1710 - 1040).abs


=> 670

> (1040 - 1710).abs


=> 670

> (1040 - 1710).abs / 2


=> 335

Sabiendo esto:

 Definí el objeto que representa a BuenosAires.


 Definí en Obera, Iruya y BuenosAires un método kilometro que retorne la altura a
la que se encuentran, según el esquema. ¡Cuidado! No tenés que guardar el
valor en un atributo @kilometro sino simplemente retornar el número que
corresponde.
 Modificá el método volar_hacia! de Pepita para hacer el cálculo de la distancia y
alterar su energía. Para acceder al kilometro inicial de Pepita tenes que
hacer @[Link].

Para que el ejemplo tenga sentido, vamos a hacer que Pepita arranque con
la energía en 1000.

¡Dame una pista!

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)

@energia -= ([Link] - @[Link]).abs / 2

@ciudad = destino

end

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Buen trabajo!

Cuando programamos en este paradigma solemos tener a disposición un


montón de objetos que interactúan entre sí, y por lo tanto aprender
cuándo usarlos y definirlos es una habilidad fundamental, que irás
adquiriendo con la práctica.

Siguiente Ejercicio: Delegar es bueno

Ejercicio 11: Delegar es bueno


En el ejercicio anterior vimos que un objeto (en ese caso, Pepita) le puede
enviar mensajes a otro que conozca (en ese caso, ciudades
como Obera o BuenosAires):

module Pepita
# ...etc...
def self.volar_hacia!(destino)
@energia -= (@[Link] - [Link]).abs / 2
@ciudad = destino
end
end

Esto se conoce como delegar una responsabilidad, o


simplemente, delegar: la responsabilidad de saber en qué kilómetro se
encuentra es de la ciudad, y no de Pepita.

A veces nos va a pasar que un objeto tiene un método muy complejo, y


nos gustaría subdividirlo en problemas más chicos que el mismo
objeto puede resolver. Pero, ¿cómo se envía un objeto mensajes a sí
mismo?

Un objeto puede enviarse un mensaje a sí mismo fácilmente


usando self como receptor del mensaje.

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

Pero esto se puede mejorar un poco más. Delegá el cálculo de la distancia en un


método distancia_a, que tome un destino y devuelva la distancia desde la ciudad
actual hasta el destino.
Biblioteca

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]!

'pri pri pri'

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

¡Muy bien! Tu solución pasó todas las pruebas

La delegación es la forma que tenemos en objetos de dividir en


subtareas: separar un problema grande en problemas más chicos para
que nos resulte más sencillo resolverlo.

A diferencia de lenguajes sin objetos, aquí debemos pensar dos cosas:

1. cómo dividir la subtarea, lo cual nos llevará a delegar ese


comportamiento en varios métodos;
2. qué objeto tendrá la responsabilidad de resolver esa tarea.

Siguiente Ejercicio: ¿Es mi responsabilidad?

Ejercicio 12: ¿Es mi responsabilidad?


Hay un pequeño problema conceptual con la solución anterior: ¿por
qué Pepita, una golondrina, es responsable de calcular la distancia entre
dos ciudades?

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]!

'pri pri pri'

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

¡Muy bien! Tu solución pasó todas las pruebas

¡Terminaste Definiendo objetos: métodos y estado!


Con lo que aprendiste en esta lección, ya podés crear
un programa completo, creando los objetos que te sean necesarios.

Vimos además dos de los conceptos más poderosos del paradigma:


la delegación y la distribución de responsabilidades. Estas herramientas
son el principio básico para la división en subtareas y seguirán
acompañándonos en todas las lecciones.

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

A partir de los conceptos que ya conocés, veremos algunas herramientas


conceptuales que nos ayudarán a contestar algunas preguntas:

 ¿Puede un objeto interactuar con otros sin saber quiénes son?


 Si quiero poder hacer algo con dos objetos distintos ¿necesito que
entiendan exactamente los mismos mensajes?
 ¿Se puede modificar el estado de un objeto "desde afuera"?

Esto, y algunas cosas más sobre aves, entrenamientos y gauchos, en esta


lección. ¡Empecemos!
Ejercicios

 1. ¿Pepita está feliz?


 2. Reencuentro alternativo
 3. Repitamos qué pasa si no
 4. Voy a hacer, pero como yo quiero
 5. Llegó Pepo
 6. ¡A entrenar!
 7. Pachorra todoterreno
 8. Una golondrina diferente
 9. Un entrenamiento más duro
 10. ¿¿Polimor-qué??
 11. Forzando el polimorfismo
 12. Empieza el set
 13. El encapsulamiento
 14. Vamos terminando
 15. ¡Se va la que falta!

¡Comenzá esta lección!

Ejercicio 1: ¿Pepita está feliz?


¿Te acordás de Pepita? Bueno, aunque no lo creas, también cambia de
estados de ánimo. En nuestro modelo de Pepita, vamos a representar
simplemente dos estados posibles: cuando está débil y cuando está feliz.

¿Y cuándo ocurre eso?

 Pepita está débil si su energía es menor que 100.


 Pepita está feliz si su energía es mayor que 1000.

Completá los métodos debil? y feliz? de Pepita.


Como en esta lección no vamos a interactuar con las ciudades, hemos
quitado todo lo relacionado a ellas de Pepita. Esto solo lo hacemos para
que te sea más fácil escribir el código, no lo intentes en casa.

¡Dame una pista!

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]?

[Link] < 100

end

def [Link]?

[Link] >1000

end

end

¡Muy bien! Tu solución pasó todas las pruebas

En Ruby, es una convención que los mensajes que devuelven booleanos


(o sea, verdadero o falso) terminen con un ?.

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.

Ejercicio 2: Reencuentro alternativo


Si llegaste hasta acá, ya deberías saber que en programación existe una
herramienta llamada alternativa condicional.

En Ruby, como en muchos otros lenguajes, esto se escribe con la palabra


reservada if. Por ejemplo:
module Jose
def self.acomodar_habitacion!
[Link]!
if self.tiene_sabanas_sucias?
self.cambiar_sabanas!
end
self.tender_la_cama!
end
end

Sabiendo cómo se escribe la alternativa condicional en Ruby queremos


que Pepita, además de recibir órdenes, tenga sus momentos para poder
hacer lo que quiera.

Obviamente, qué quiere hacer en un momento dado depende de su


estado de ánimo:

 Si está débil, come diez gramos de alpiste, para recuperarse.


 Si no lo está, no hace nada.

Hacé que Pepita entienda el mensaje hacer_lo_que_quiera! que se comporte como


explicamos.
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]?

[Link] < 100


end

def [Link]?

[Link] >1000

end

def self.hacer_lo_que_quiera!

if [Link]?

self.comer_alpiste!(10)

end

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Como acabamos de ver, la alternativa condicional es como en otros


lenguajes. La diferencia radica en su sintaxis, es decir, cómo la escribimos.

Ejercicio 3: Repitamos qué pasa si no


Hay veces que con un if alcanza, pero otras queremos hacer algo si no se
cumple una condición. Como ya te podrás imaginar, donde hay un if
¡cerca anda un else!

module Jardinero
def [Link]!(planta)
if planta.necesita_agua?
[Link] { [Link]! planta }
else
self.sacar_bichos! planta
end
end
end

¿Y ese times qué es?

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]?

[Link] < 100

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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 4: Voy a hacer, pero como yo quiero


Algunas veces vamos a tener condiciones anidadas. En otras palabras,
un if dentro de un if o un else. Como en este ejemplo:

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:

 Si está débil, come diez gramos de alpiste, para recuperarse.


 Si no está debil pero sí feliz, vuela en círculos cinco veces.
 Si no está feliz ni débil, vuela en círculos 3 veces.

Modificá a Pepita para que el método hacer_lo_que_quiera! se comporte como


mencionamos más arriba.
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]?

[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

¡Muy bien! Tu solución pasó todas las pruebas

En Ruby, podemos simplicar la manera de escribir un if dentro


un else con elsif. Por ejemplo este código:

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?

Siguiente Ejercicio: Llegó Pepo

Ejercicio 5: Llegó Pepo


Pepo es un gorrión que también sabe comer, volar y hacer lo que quiera,
pero lo hace de manera diferente a Pepita.

 comer alpiste: el aparato digestivo de Pepo no anda muy bien, por


eso solo puede aprovechar la mitad del alpiste que come. Por
ejemplo, si come 20 gramos de alpiste, su energía solo aumenta en
10.
 volar en círculos: gasta 15 unidades de energía si está pesado y 5
si no lo está. Decimos que está pesado si su energía es mayor a
1100.
 hacer lo que quiera: como siempre tiene hambre, aprovecha y
come 120 gramos de alpiste.

Ah, y al igual que Pepita, su energía comienza en 1000.

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!

if [Link] > 1100

@energia -= 15

else

@energia -= 5

end

end

def self.hacer_lo_que_quiera!

self.comer_alpiste!(120)

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Genial, ya tenemos dos aves con las cuales trabajar y que


además comparten una interfaz: ambas entienden los
mensajes comer_alpiste!(gramos), volar_en_circulos! y hacer_lo_que_quiera!.

Veamos qué podemos hacer con ellas...


Ejercicio 6: ¡A entrenar!
Nuestras aves quieren presentarse a las próximas Olimpíadas, y para eso
necesitan ejercitar un poco.

Para ayudarnos en esta tarea conseguimos a Pachorra, un ex entrenador de


fútbol que ahora se dedica a trabajar con aves. Él diseñó una rutina
especial que consiste en lo siguiente:

 Volar en círculos 10 veces.


 Comer un puñado de 30 gramos de alpiste.
 Volar en círculos 5 veces.
 Como premio, que el ave haga lo que quiera.

Creá a Pachorra, el entrenador de aves, y hacé que cuando reciba el


mensaje entrenar_ave! haga que Pepita realice su rutina (si, solo puede entrar a Pepita ,
pero lo solucionaremos pronto).
Para que no moleste, movimos el código de Pepita a la Biblioteca.

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

Aunque lo que hiciste funciona, es bastante rígido: para


que Pachorra pueda entrenar a otro pájaro hay que modificar
el método entrenar_ave! y cambiar el objeto al que le envía los mensajes.

¡Mejoremos eso entonces!

Ejercicio 7: Pachorra todoterreno


Como imaginabas, Pachorra puede entrenar cualquier tipo de aves, aunque
para que no haya problemas, solo entrena de a una a la vez.

Antes de empezar a entrenar, debe firmar un contrato con el ave. Esto,


por ejemplo, lo haríamos de la siguiente manera:

Pachorra.firmar_contrato! Pepita # ahora el ave de Pachorra es Pepita

Cada vez que firmamos un contrato cambiamos el ave que


entrenará Pachorra, por lo cual es necesario recordar cuál es ya que a ella le
enviaremos mensajes:

Pachorra.entrenar_ave! # acá entrena a Pepita


Pachorra.firmar_contrato! Pepo # ahora el ave de Pachorra es Pepo
Pachorra.entrenar_ave! # ahora entrena a Pepo

Agregale a Pachorra el método firmar_contrato!(ave), de forma tal que cuando le


enviemos el mensaje entrenar_ave! haga entrenar al último ave con el que haya
firmado contrato.
¡Dame una pista!

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

¡Muy bien! Tu solución pasó todas las pruebas

Una forma posible de cambiar el objeto al que le enviamos mensajes


es modificando el valor de un atributo, como estamos haciendo en este
ejemplo.

Ejercicio 8: Una golondrina diferente


¿Te acordás de Norita, la amiga de Pepita? Resulta que ella también quiere
empezar a entrenar, y su código es el siguiente:

module Norita
@energia = 500

def self.volar_en_circulos!
@energia -= 30
end

def self.comer_alpiste!(gramos)
@energia -= gramos
end
end

Pero, ¿podrá entrenar con Pachorra?

Probalo en la consola, enviando los siguientes mensajes:

> Pachorra.firmar_contrato! Norita


> Pachorra.entrenar_ave!

> Pachorra.firmar_contrato! Norita


=> Norita
> Pachorra.entrenar_ave!
undefined method `hacer_lo_que_quiera!' for Norita:Module
(NoMethodError)
>
Ejercicio 9: Un entrenamiento más duro
Analicemos el error:

> Pachorra.entrenar_ave!
undefined method `hacer_lo_que_quiera!' for Norita:Module (NoMethodError)

En criollo, lo que dice ahí es que Norita no entiende el


mensaje hacer_lo_que_quiera!, y por eso Pachorra no la puede entrenar; este
mensaje forma parte de su rutina.

Miremos ahora el método entrenar_ave! de Emilce, una entrenadora un poco


más estricta:

module Emilce
def self.entrenar_ave!
[Link] { @ave.volar_en_circulos! }
@ave.comer_alpiste! 8
end
end

¿Podrá Norita entrenar con Emilce? ¿Y Pepita? ¿Y Pepo?


Probalo en la consola y completá el código con true (verdadero) o false (falso) según
corresponda para cada ave.
¡Dame una pista!

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

¡Muy bien! Tu solución pasó todas las pruebas

Según las rutinas que definen, cada entrenador/a solo puede trabajar con
ciertas aves:

 Pachorra puede entrenar a cualquier ave que


entienda volar_en_circulos!, comer_alpiste!(gramos) y hacer_lo_que_quiera!.
 Emilce puede entrenar a cualquier ave que
entienda volar_en_circulos! y comer_alpiste!(gramos).

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.

Este concepto es fundamental en objetos, y lo conocemos


como polimorfismo. Decimos entonces que dos objetos
son polimórficos cuando pueden responder a un mismo conjunto de
mensajes y hay un tercer objeto que los usa indistintamente. Dicho de
otra forma, dos objetos son polimórficos para un tercer objeto cuando
este puede enviarles los mismos mensajes, sin importar cómo respondan
o qué otros mensajes entiendan.

En nuestro caso:

 Pepita, Norita y Pepo son polimórficas para Emilce.


 Pepita, Norita y Pepo no son polimórficas para Pachorra.
 Pepita y Pepo son polimórficas para Pachorra.

Ejercicio 11: Forzando el polimorfismo


Bueno, ya entendimos que para el caso de Pachorra, Norita no
es polimórfica con las otras aves, pero... ¿podremos hacer algo al
respecto?

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

Modificá a Norita para que pueda entrenar con Pachorra.


module Norita

@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

¡Muy bien! Tu solución pasó todas las pruebas

Aunque parezca que no tiene mucho sentido, es común que trabajando


con objetos necesitemos forzar el polimorfismo y hagamos cosas como
estas.

En este caso le agregamos a Norita un mensaje que no hace nada, con el


único objetivo de que sea polimórfica con sus compañeras aves.

Ejercicio 12: Empieza el set


En los ejercicios anteriores, le habíamos incluido a Pachorra y Emilce un
mensaje firmar_contrato!(ave) que modificaba su estado, es decir, alguno de
sus atributos. A estos mensajes que solo modifican un atributo los
conocemos con el nombre de setters, porque vienen del inglés set que
significa establecer, ajustar, fijar.

Para estos casos, solemos utilizar una convención que se asemeja a la


forma que se modifican los atributos desde el propio objeto, pudiendo
ejecutar el siguiente código desde una consola:

[Link] = Pepita

Esto se logra definiendo el método ave=, todo junto, como se ve a


continuación:

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

¡Muy bien! Tu solución pasó todas las pruebas

Como ya te habíamos contado en una lección anterior, a estos métodos


que solo sirven para acceder o modificar un atributo los
llamamos métodos de acceso o accessors. Repasando, los setters son
aquellos métodos que establecen el valor del atributo. Mientras que
los getters son aquellos que devuelven el valor del atributo.

La convención en Ruby para estos métodos es:

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

Siguiente Ejercicio: El encapsulamiento


Ejercicio 13: El encapsulamiento
Ya aprendiste cómo crear getters y setters para un atributo, pero
¿siempre vamos a querer ambos?

La respuesta es que no, y a medida que desarrolles más programas y


dominios diferentes tendrás que construir tu propio criterio para decidir
cuándo sí y cuándo no.

Por ejemplo, ¿qué pasaría si a Pepita le agregaramos un setter para la


ciudad? Podríamos cambiarla en cualquier momento de nuestro
programa ¡y no perdería energía! Eso va claramente en contra de las
reglas de nuestro dominio, y no queremos que nuestro programa lo
permita.

Te dejamos en la Biblioteca el código que modela a Manuelita, una tortuga viajera.


Algunos de sus atributos pueden ser leidos, otros modificados y otros ambas cosas.
Completá las listas de atributos_con_getter y atributos_con_setter mirando en la definicion
de Manuelita qué tiene programado como setter y que como getter.
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 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

¡Muy bien! Tu solución pasó todas las pruebas

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.

Será tarea tuya (y de tu equipo de trabajo, claro) decidir qué atributos


exponer en cada objeto.

Ejercicio 14: Vamos terminando


Vamos a empezar a repasar todo lo que aprendiste en esta lección, te
vamos a pedir que modeles a nuestro amigo Inodoro, un gaucho solitario
de la pampa argentina. Fiel al estereotipo, Inodoro se la pasa
tomando mate, y siempre lo hace con algún compinche; ya sea Eulogia, su
compañera o Mendieta, su perro parlante.

Tu tarea será completar el código que te ofrecemos, definiendo los


métodos incompletos y agregando los getters y setters necesarios para
que sea posible:

 Consultar cuánta cafeína en sangre tiene Inodoro.


 Consultar al compinche de Inodoro.
 Modificar al compinche de Inodoro.
 Consultar si Eulogia está enojada.
 Consultar cuántas ganas de hablar tiene Mendieta.
 Modificar las ganas de hablar de Mendieta.

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

¡Muy bien! Tu solución pasó todas las pruebas

¡Excelente! Parece que los getters y setters quedaron claros.


Para finalizar esta lección vamos a repasar lo que aprendimos de
polimorfismo.

Ejercicio 15: ¡Se va la que falta!


Para finalizar el repaso vamos a modelar el comportamiento necesario
para que Inodoro pueda tomar mate con cualquiera de sus compinches...
¡Polimórficamente!

 Cuando Inodoro toma mate aumenta en 10 su cafeína en sangre y su


compinche recibe un mate.
 Al recibir un mate, Eulogia se enoja porque Inodoro siempre le da
mates fríos.
 Por su parte, Mendieta se descompone cuando recibe un mate,
porque bueno... es un perro. Esto provoca que no tenga nada de
ganas de hablar (o en otras palabras, que sus ganas_de_hablar se
vuelvan 0).

Definí los métodos tomar_mate!, en Inodoro, y recibir_mate! en Eulogia y Mendieta.


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

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

¡Muy bien! Tu solución pasó todas las pruebas

¡Terminaste Polimorfismo y encapsulamiento!


En esta lección le dimos nombre al polimorfismo una idea con la que ya
venías trabajando, pero sobre la que todavía no habíamos reflexionado.
Este principio fundamental del paradigma de objetos nos permite que
podamos interactuar de igual manera con diferentes objetos, con el único
requisito de que todos ellos entiendan el o los mensajes que necesitamos
enviarles.

Relacionado a esto, hablamos del encapsulamiento que nos permite el


paradigma, haciendo que cada objeto solo exponga lo necesario para
interactuar con él y se reserve para su ámbito privado lo que no sea
necesario compartir.

En el caso de los atributos, esta exposición se logra implementando


un getter (método que nos permite ver su valor) o un setter (método
que nos permite modificar su valor). Y que nuestro código sea entendido
fácilmente por otras personas, elegimos utilizar una convención para
darle nombre a estos métodos.

Siguiente Lección: Referencias

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?

Estas y muchas preguntas más las responderemos a continuación

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 = "hola"


> [Link]
=> "HOLA"

...y esperar el mismo resultado que para el programa anterior.

Veamos si queda claro: agregá al programa anterior una variable saludo_formal,


inicializada con "buen día"
Solucion

saludo = "buen día"

saludo_formal=saludo

¡Muy bien! Tu solución pasó todas las pruebas

¡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?

Sí y no. Veamos por qué...

Siguiente Ejercicio: Las variables son referencias

Ejercicio 2: Las variables son referencias


Hasta ahora venimos insistiendo con que, en la programación en objetos,
le enviamos mensajes a los objetos. ¡Y no mentimos!

Sucede que en realidad las cosas son un poco más complejas: no


conocemos a los objetos directamente, sino a través de etiquetas
llamadas referencias. Entonces cuando tenemos una declaración de
variable como ésta...

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]

...le estamos enviando el mensaje upcase al objeto "hola", a través de la


referencia saludo, que es una variable.

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:

También podemos hacer cosas como "hola".size. Allí no hay ninguna


variable: ¿dónde está la referencia en ese caso? ¡Allá vamos!

Siguiente Ejercicio: Referencias implícitas

Ejercicio 3: Referencias implícitas


Como vemos, los objetos son las "bolitas" y las referencias, las "flechitas".
Pero, ¿cuál es la diferencia entre variable y referencia?

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?:

#¿A qué referencia el envío upcase?


"ni hao".upcase

#¿Y a qué referencia el envío size?


[Link]

¡Simple! Cuando enviamos mensajes a objetos literales como el 2,


el true u "hola", o expresiones, estamos conociendo a esos objetos a través
de referencias implícitas, que son temporales (sólo existen durante ese
envío de mensajes) y anónimas (no tienen un nombre asociado).

"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:

saludoEnChino = "ni hao"

Probá las siguientes consultas en la consola y pensá en dónde hay referencias


implícitas:

 > "ni hao".upcase


 > [Link]?
 > (4 + 8).abs
 > "ni hao".upcase
 => "NI HAO"
 > [Link]?
 => true
 > (4 + 8).abs
 => 12
 >
Ejercicio 4: Múltiples referencias
Supongamos que tenemos el siguiente programa:

otro_saludo = "buen día"


despedida = otro_saludo

Como vemos, estamos asignando otro_saludo a despedida. ¿Qué significa


esto? ¿Acabamos de copiar el objeto "buen día", o más bien le dimos una
nueva etiqueta al mismo objeto? Dicho de otra forma: ¿apuntan ambas
variables al mismo objeto?

¡Averigualo! Declará las variables otro_saludo y despedida como en el ejemplo de más


arriba, y realizá las siguientes consultas utilizando equal?:

 > "buen día".equal? "buen día"


 > [Link]? "buen día"
 > otro_saludo.equal? otro_saludo
 > [Link]? otro_saludo
¡Ahora sacá tus conclusiones viendo que responde en cada caso!
> "buen día".equal? "buen día"
=> false
> [Link]? "buen día"
undefined local variable or method `despedida' for main:Object
(NameError)
> otro_saludo.equal? otro_saludo
undefined local variable or method `otro_saludo' for main:Object
(NameError)
> [Link]? otro_saludo
undefined local variable or method `despedida' for main:Object
(NameError)
>
Ejercicio 5: Identidad, revisada
El mensaje equal? nos dice si dos objetos son el mismo. Veamos qué pasó
con las pruebas del ejercicio anterior:

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:

> otro_saludo.equal? otro_saludo


=> true
> [Link]? otro_saludo
=> true

¿Por qué? ¡Simple! Ambas referencias, otro_saludo y despedida, apuntan al


mismo objeto. La moraleja es que declarar una variable significa agregar
una nueva referencia al objeto existente, en lugar de copiarlo:
Distinto sería si hacemos:

otro_saludo = "buen día"


despedida = "buen día"

Lo cual da como resultado este ambiente:

Veamos otro ejemplo. Si tuvieramos el siguiente código...

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

... podríamos decir que solo hermana_de_tito y hermana_de_ana referencian al


mismo objeto que persona.

Ya entendimos que dos strings con el mismo contenido no


necesariamente son el mismo objeto. Pero esto puede ser poco práctico .
¿Cómo hacemos si realmente queremos saber si dos objetos, pese a no
ser el mismo, tienen el mismo estado?

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?

Pensemos un caso concreto. ¿Hay forma de saber si dos strings


representan la misma secuencia de caracteres más allá de que no sean
el mismo objeto? ¡Por supuesto que la hay! Y no debería sorprendernos
a esta altura que se trate de otro mensaje:

> "hola" == "hola"


=> true
> "hola" == "adiós"
=> false
> "hola".equal? "hola"
=> false

El mensaje == nos permite comparar dos objetos por equivalencia; lo cual


se da típicamente cuando los objetos tienen el mismo estado. Y como
vemos, puede devolver true, aún cuando los dos objetos no sean el mismo.

Por ejemplo, en este caso...

procer = "San Martín"


avenida = "San Martín"
ciudad = "San Martín"

... las 3 referencias distintas apuntan a objetos equivalentes entre sí, pero
no idénticos.

¡Cuidado! A diferencia de la identidad, que todos los objetos la entienden


sin tener que hacer nada especial, la equivalencia es un poco más
complicada.
 Por defecto, si bien todos los objetos también la
entienden, delega en la identidad, así que muchas veces es lo
mismo enviar uno u otro mensaje;
 y para que realmente compare a los objetos por su estado, vos
tenés que implementar este método a mano en cada objeto que
crees. Los siguientes objetos ya la implementan:
o Listas
o Números
o Strings
o Booleanos

Ejercicio 7: Objetos bien conocidos


¿Y qué hay de los objetos que veníamos definiendo hasta ahora? Por
ejemplo a Fito, le aumenta la felicidad cuando come:

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?

¡Adiviná! Esas etiquetas también son referencias . Y son globales, es decir


que cualquier objeto o programa puede utilizarla.
Veamos si va quedando claro. Definí un objeto AbuelaClotilde que entienda un
mensaje alimentar_nieto!, que haga comer! 2 veces a Fito: primero con 2000 calorias, y
luego con 1000 calorías; ¡el postre no podía faltar! .
Solucion

module AbuelaClotilde

def self.alimentar_nieto!

[Link]!(2000)

[Link]!(1000)

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Muchas veces, en lugar de decir que le enviamos un mensaje al objeto


apuntado por la referencia Fito, podemos llegar a decir...

enviar un mensaje a la variable Fito


...o...

enviar un mensaje al objeto Fito


...o simplemente...

enviar un mensaje a Fito


...porque si bien no es del todo correcto, es más breve . Lo importante es
que entiendas que siempre estamos enviando el mensaje al objeto a
través de una referencia.
Siguiente Ejercicio: Atributos y parámetros

Ejercicio 8: Atributos y parámetros


Además de los que ya vimos, hay más tipos de referencias: los atributos.

Por ejemplo, si la golondrina Pepita conoce siempre su ciudad actual...

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

Y en algún momento esta pasa a ser Iruya, el diagrama de objetos será el


siguiente:

Nuevamente, acá vemos otro caso de múltiples referencias: el objeto que


representa a la ciudad de Iruya es globalmente conocido como Iruya, y
también conocido por Pepita como ciudad.

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

#Ya definimos a Pepita por vos.

#Ahora definí su ciudad...

[Link] = Iruya

¡Muy bien! Tu solución pasó todas las pruebas

¿Lo pensaste?

Hay tres referencias a este objeto:

1. La propia referencia Iruya


2. El atributo @ciudad de Pepita
3. una_ciudad: porque los parámetros de los métodos ¡también son
referencias! Sólo que su vida es más corta: viven lo que dure la
evaluación del método en el que se pasan.

Siguiente Ejercicio: Lo 100to

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 ?

No, en absoluto. @energia es una referencia a un objeto, que


inicialmente apunta al objeto 100:

Luego, la operación de asignación cambia ese apuntador, que pasa a


referenciar al 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:

 Pepita e Iruya son objetos bien conocidos;


 @energiay @ciudad son atributos;
 y una_ciudad es un parámetro;

¡Todas son referencias!

Ejercicio 10: Objetos compartidos


¿Te acordás de Fito? Fito también tiene un amigo, Juli. Juli es nieto
de AbueloGervasio. Cuando Juli es feliz Fito es feliz:

module Fito
def [Link]=(un_amigo)
@amigo = un_amigo
end

def self.es_feliz_como_su_amigo?
@[Link] > 105
end
end

Creá un programa que inicialice al amigo de Fito y al nieto de AbueloGervasio de forma


que ambos conozcan al mismo objeto (Juli).
Luego, hacé que el abuelo alimente a su nieto 3 veces. ¿Qué pasará con Fito? ¿Se
pondrá feliz?
SOlucion

#Juli, Fito y AbueloGervasio ya están declarados.

#Inicializalos y enviales mensajes acá...

[Link]=Juli

[Link]=Juli
[Link] {AbueloGervasio.alimentar_nieto!}

¡Muy bien! Tu solución pasó todas las pruebas

En el programa que acabás de crear, que probablemente se vea parecido


a esto...

[Link] = Juli
[Link] = Juli

#Si antes de alimentar al nieto preguntáramos Fito.es_feliz_como_su_amigo?, respondería false

[Link] { AbueloGervasio.alimentar_nieto! }

...Juli es un objeto compartido: tanto el abuelo como su amigo lo


conocen. La consecuencia de esto es que cuando su abuelo le da de
comer le aumenta la felicidad, y su amigo ve los cambios: éste método
que antes devolvía false, ahora devuelve true.

Y esto tiene sentido: si un objeto muta su estado, y lo expone de una u


otra forma a través de mensajes, todos los que lo observen podrán ver el
cambio.

Ejercicio 11: Para cerrar


Antes de terminar nos topamos con un último problema: Jor se encarga
de la cocina en un restaurante de pastas y le encanta picantear! su plato del
día. Sin embargo, Luchi, su ayudante, no comparte ese gusto y por suerte
está ahí para suavizar! las distintas comidas del establecimiento.

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

Definí los objetos necesarios para que podamos hacer lo siguiente:

#Configurar el plato del día de Jor


Jor.plato_del_dia = Fideos
#Que Jor le agregue picante
[Link]!
#Preguntar si está picante
[Link]?
#Que Luchi suavice el plato que reciba como argumento
[Link]! Fideos, 3
#Descartar la salsa
Fideos.descartar_la_salsa!

Solucion

module Jor

def self.plato_del_dia= plato_de_hoy

@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

def self.agregar_ajies! (cantidad)

@ajies += cantidad

end

def self.quitar_ajies! (cantidad)

@ajies -= cantidad

end

def self.descartar_la_salsa!

@ajies = 0

end

end

module Luchi

def [Link]! (plato_del_dia, cantidad)

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

¡Muy bien! Tu solución pasó todas las pruebas

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

Para un objeto pueden existir múltiples nombres: cuando le damos uno


nuevo, no estamos creando una copia del objeto ni modificándolo
realmente, sino que estamos creando una nueva referencia que apunta al
objeto. Así que ¡ojo!, si compartís un objeto con otros, y lo mutás, ¡todos
los que tengan una referencia al mismo verán los cambios!

Finalmente, en objetos, todo lo que se parezca a una variable es una


referencia, y hay de muchos tipos:

 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?

¡Conozcamos a las colecciones!

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

¡Comenzá esta lección!

Ejercicio 1: Entrando en Calor


¡Vamos a crear una biblioteca de videojuegos! Para empezar, tendremos
tres videojuegos, de los cuales sabemos lo siguiente:

 CarlosDuty: es violento. Su dificultad se calcula como 30 -


@cantidad_logros * 0.5. Y si se lo juega por más de 2 horas seguidas, se
le suma un logro a su cantidad. Inicialmente, el juego no tiene
logros.
 TimbaElLeon: no es violento. Su dificultad inicial es 25 y crece un
punto por cada hora que se juegue.
 Metroide: es violento sólo si @nivel_espacial es mayor a 5. Este nivel
arranca en 3 pero se incrementa en 1 cada vez que se lo juega, sin
importar por cuánto tiempo. Además, su dificultad siempre es 100.

Definí estos tres objetos de forma que entiendan los


mensajes dificultad, violento? y jugar!(un_tiempo).

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

¡Muy bien! Tu solución pasó todas las pruebas

¡Ya tenemos creados los objetos para nuestra colección de videojuegos!

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.

¡Esto significa que podemos enviarles los mismos mensajes a cualquiera


de los videojuegos y usarlos indistintamente!

Siguiente Ejercicio: Creando una lista

Ejercicio 2: Creando una lista


Ahora que ya tenemos nuestros videojuegos , vamos a ordenarlos en
algún lugar.

Para ello necesitamos definir un objeto, la Juegoteca, que contenga otros


objetos: nuestros videojuegos. Para ello vamos a usar una lista de objetos:
es un tipo de colección en la cual los elementos pueden repetirse. Es decir,
el mismo objeto puede aparecer más de una vez.

Por ejemplo, la lista de números 2, 3, 3 y 9 se escribe así:

[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

¡Muy bien! Tu solución pasó todas las pruebas

¡Excelente! Ya tenemos creada la Juegoteca con algunos juegos:


¿Pero qué más podemos hacer con las colecciones? Pasemos al siguiente
ejercicio...

Ejercicio 3: Algunos mensajes básicos


¡Tengo una colección! ¿Y ahora qué...?

Todas las colecciones entienden una serie de mensajes que representan


operaciones o consultas básicas sobre la colección.

Por ejemplo, podemos agregar un elemento enviándole push a la


colección o quitarlo enviándole delete:

numeros_de_la_suerte = [6, 7, 42]


numeros_de_la_suerte.push 9
# Agrega el 9 a la lista...
numeros_de_la_suerte.delete 7
# ...y quita el 7.

También podemos saber saber si un elemento está en la colección


usando include?:

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.

Finalmente, podemos saber la cantidad de elementos que tiene


enviando size:

numeros_de_la_suerte.size
# Devuelve 3, porque contiene al 6, 42 y 9

¡Probá enviarle los mensajes push, delete, include? y size a la


colección numeros_de_la_suerte!
¡Dame una pista!

Biblioteca

numeros_de_la_suerte = [6, 42, 9]

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

 no admiten elementos repetidos;


 sus elementos no tienen un orden determinado.

Vamos a ver un ejemplo transforma una lista en un set utilizando to_set:

> numeros_aleatorios = [1,27,8,7,8,27,87,1]


> numeros_aleatorios
=> [1,27,8,7,8,27,87,1]
> numeros_aleatorios.to_set
=> #<Set: {1, 27, 8, 7, 87}>

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.

Sin embargo, los siguientes mensajes...

numeros_de_la_suerte = [6, 7, 42]


numeros_de_la_suerte.first
# Nos retorna el primer elemento de la lista
numeros_de_la_suerte.last
# Nos retorna el último de la lista
numeros_de_la_suerte.index 7
# Nos retorna la posición de un elemento en la lista

... no podemos enviárselos a un set porque sus elementos no están


ordenados.

Pero no te preocupes, todos lo que veamos de ahora en adelante en esta


lección funciona tanto para listas como para sets.
Ejercicio 5: Mejorando la Juegoteca
Primero nos encargamos de los videojuegos, y ahora ya conocés qué
mensajes entienden las listas. ¡Es momento de darle funcionalidad a
la Juegoteca!

Nuestra Juegoteca maneja puntos. Agregá el código necesario para que entienda los
siguientes mensajes:

 puntos: nos dice cuantos puntos tiene la Juegoteca. Inicialmente son 0.


 adquirir_juego!(un_juego): agrega el juego a la Juegoteca, y le suma 150 puntos.
 borrar_juego!(un_juego): quita un juego de la Juegoteca, pero no resta puntos.
 completa?: se cumple si la Juegoteca tiene más de 1000 puntos y más de 5
juegos.
 juego_recomendable?(un_juego): es verdadero para un_juego si no está en
la Juegoteca y es violento?.

module Juegoteca

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

@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]?

@puntos > 1000 && @[Link] > 5

end

def self.juego_recomendable?(un_juego)

!@[Link]?(un_juego) && un_juego.violento?

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Hay una diferencia notable entre los primeros dos mensajes (push y delete)
y los otros dos (include? y size):

1. push y delete, al ser evaluados, modifican la colección. Dicho de otra


forma, producen un efecto sobre la lista en sí: agregan o quitan un
elemento del conjunto.
2. include? y size sólo nos retornan información sobre la colección. Son
métodos sin efecto.

Ahora que ya dominás las listas, es el turno de subir un nivel más...

Siguiente Ejercicio: ¿Bloques? ¿Eso se come?

Ejercicio 6: ¿Bloques? ¿Eso se come?


¡Pausa! Antes de continuar, necesitamos conocer a unos nuevos amigos:
los bloques.

Los bloques son objetos que representan un mensaje o una secuencia de


envíos de mensajes, sin ejecutar, lista para ser evaluada cuando
corresponda. La palabra con la que se definen los bloques en Ruby
es proc. Por ejemplo, en este caso le asignamos un bloque a incrementador:

un_numero = 7
incrementador = proc { un_numero = un_numero + 1 }

Ahora avancemos un pasito: en este segundo ejemplo, al bloque {


otro_numero = otro_numero * 2 } le enviamos el mensaje call, que le indica
que evalúe la secuencia de envíos de mensajes dentro de él.

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 vale 7, porque el bloque incrementador no está aplicado. Por


tanto, no se le suma 1.
 otro_numero vale 10, porque el bloque duplicador se aplica mediante el
envío de mensaje call, que hace que se ejecute el código dentro del
bloque. Por tanto, se duplica su valor.

Ejercicio 7: Bloques con parámetros


Los bloques también pueden recibir argumentos para su aplicación. Por
ejemplo, sumar_a_otros_dos recibe dos argumentos, escritos entre barras
verticales | y separados por comas:

un_numero = 3
sumar_a_otros_dos = proc { |un_sumando, otro_sumando| un_numero = un_numero + un_sumando + otr
o_sumando }

Para aplicar el bloque sumar_a_otros_dos, se le pasan los argumentos


deseados al mensaje call:

> sumar_a_otros_dos.call(1,2)
=> 6

Volvamos a los videojuegos...

En la Biblioteca podés ver el objeto TimbaElLeon. Para resolver este


ejercicio, no nos interesa cómo están definidos los métodos de este
objeto, solo queremos recordar los mensajes que entiende ¡por eso hay
puntos suspensivos!
Asignale a la variable jugar_a_timba un bloque que reciba un único parámetro. El
bloque recibe una cantidad de minutos y debe hacer que se juegue
a TimbaElLeon durante ese tiempo, pero recordá que jugar! espera una cantidad de
horas.
Biblioteca

module TimbaElLeon
@dificultad = 25

def [Link]?
# ...
end

def [Link]
# ...
end

def [Link]!(un_tiempo)
# ...
end
end

Solucion

jugar_a_timba = proc { |tiempo_en_minutos| [Link]!(tiempo_en_minutos/60) }

¡Muy bien! Tu solución pasó todas las pruebas

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.

Ejercicio 8: Filtrando quienes cumplen


¿Qué pasa cuando queremos todos aquellos objetos que cumplan con
una condición determinada en una cierta colección? Por ejemplo, si de
una lista de números queremos los mayores a 3.

Lo que usamos es el mensaje select de las colecciones. select recibe


un bloque con un parámetro que representa un elemento de la colección
y una condición booleana como código, y lo que devuelve es una nueva
colección con los elementos que la cumplen.

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]

Mientras tanto, en nuestra juegoteca...


¡Ahora te toca a vos! Definí el método juegos_violentos que retorna los juegos de
la Juegoteca que cumplan violento?.
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
¡Muy bien! Tu solución pasó todas las pruebas

¿Y qué pasa con la colección original, como algunos_numeros o juegos? ¿Se


modifica al aplicar select?

¡No, para nada! El select no produce efecto.

Ejercicio 9: El que busca encuentra


¿Y si en vez de todos los elementos que cumplan una condición, sólo
queremos uno? ¡Usamos find!

algunos_numeros = [1, 2, 3, 4, 5]
uno_mayor_a_3 = algunos_numeros.find { |un_numero| un_numero > 3 }

Mientras que select devuelve una colección, find devuelve únicamente un


elemento.

> uno_mayor_a_3
=> 4

¿Y si ningún elemento de la colección cumple la condición? Devuelve nil,


que, como aprendiste antes, es un objeto que representa la nada - o en
este caso, que ninguno cumple la condición.

Veamos si se entiende: hacé que


la Juegoteca entienda juego_mas_dificil_que(una_dificultad), que retorna algún juego en
la Juegoteca con más dificultad que la que se pasa como argumento.
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

solución

module Juegoteca

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

def [Link]

@juegos

end

def self.juego_mas_dificil_que(una_dificultad)

juego_mas_dificil = @[Link] { |juego_mas_dificil| juego_mas_dificil.dificultad >


una_dificultad}

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Un dato curioso para tener en cuenta: ¡los mensajes find y detect hacen
exactamente lo mismo!
Siguiente Ejercicio: ¿Alguno cumple? ¿Todos cumplen?

Ejercicio 10: ¿Alguno cumple? ¿Todos cumplen?


Para saber si todos los elementos de una colección cumplen un cierto
criterio podemos usar el mensaje all?, que también recibe un bloque. Por
ejemplo, si tenemos una colección de estudiantes, podemos saber si todo
el grupo aprueba de la siguiente forma:

[Link]? { |un_estudiante| un_estudiante.aprobo? }

De manera muy similar podemos saber si algún elemento de la colección


cumple cierta condición mediante el mensaje any?. Siguiendo el ejemplo
anterior, ahora queremos saber si por lo menos alguien aprobó :

[Link]? { |un_estudiante| un_estudiante.aprobo? }

Definí los siguientes métodos en nuestra Juegoteca:

 mucha_violencia?: se cumple si todos los juegos que posee son violentos.


 muy_dificil?: nos dice si alguno de los juegos tiene más de 25 puntos de
dificultad.

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

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

def [Link]

@juegos

end

def self.mucha_violencia?

@[Link]? { |juego| [Link]? }

end

def self.muy_dificil?

@[Link]? { |juego| [Link] > 25}

end

end
¡Muy bien! Tu solución pasó todas las pruebas

¿Qué tienen de distinto all? y any? respecto aselect y find?

Mientras que select devuelve una colección y find un elemento


o nil, all? y any? siempre devuelven un valor booleano: true o false.

Siguiente Ejercicio: El viejo y querido map

Ejercicio 11: El viejo y querido map


El mensaje map nos permite, a partir de una colección, obtener otra
colección con cada uno de los resultados que retorna un envío de
mensaje a cada elemento.

En otras palabras, la nueva colección tendrá lo que devuelve el mensaje


que se le envíe a cada uno de los elementos. Por ejemplo, si
usamos map para saber los niveles de energía de una colección de
golondrinas:

> [Pepita, Norita].map { |una_golondrina| una_golondrina.energia }


=> [77, 52]

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.

Agregá a la Juegoteca un método llamado dificultad_violenta que retorne una colección


con la dificultad de sus juegos_violentos.
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

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

def [Link]

@juegos

end

def self.juegos_violentos

juegos_violentos = @[Link] { |juegos_violentos| juegos_violentos.violento? }

end

def self.dificultad_violenta

juegos_violentos.map { |juego| [Link] }

end
end

¡Muy bien! Tu solución pasó todas las pruebas

Antes de seguir, un caso particular. Dijimos que map no modifica la


colección original. Pero, ¿qué ocurriría si el mensaje dentro del bloque en
el map sí tiene efecto?

En ese caso se modificaría la colección original, pero sería un mal uso


del map . Lo que nos interesa al mapear es lo que devuelve el mensaje que
enviamos, no provocar un efecto sobre los objetos.

Ejercicio 12: ¿Cuántos cumplen? ¿Cuánto suman?


Volviendo a nuestra colección de estudiantes. Ya preguntamos si todo el
grupo aprobó o si al menos alguien aprobó utilizando all?y any?. ¿Y si
queremos saber cuántos aprobaron? Usamos count:

[Link] { |un_estudiante| un_estudiante.aprobo? }

count nos dice cuántos elementos de una colección cumplen la condición.


Por otro lado, para calcular sumatorias tenemos el mensaje sum. Si
queremos conocer la suma de todas las notas de la colección de
estuidantes, por ejemplo, podemos hacer:

[Link] { |un_estudiante| un_estudiante.nota_en_examen }

Veamos si se entiende: agregá a la Juegoteca el método promedio_de_violencia, cuyo


valor sea la sumatoria de dificultad de los juegos violentos dividida por la cantidad
de juegos violentos de la Juegoteca.
Solucion

module Juegoteca

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

def [Link]

@juegos

end

def self.juegos_violentos

juegos_violentos = @[Link] { |juegos_violentos| juegos_violentos.violento? }

end
def self.promedio_de_violencia

self.juegos_violentos.sum { |juego| [Link] } / self.juegos_violentos.count { |juego|

[Link]? }

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 13: Jugando a todo


Hasta ahora, todos los mensajes que vimos de colecciones (con la
excepción de push y delete) no están pensados para producir efectos sobre
el sistema. ¿Qué ocurre, entonces, cuando queremos hacer algo con cada
elemento? A diferencia del map, no nos interesan los resultados de enviar
el mismo mensaje a cada objeto, sino mandarle un mensaje a cada uno
con la intención de producir un efecto.

Es en este caso que nos resulta de utilidad el mensaje each.

Por ejemplo, si queremos que de una colección de golondrinas, aquellas


con energía mayor a 100 vuelen a Iruya, podríamos
combinar select y each para hacer:

golondrinas
.select { |una_golondrina| una_golondrina.energia > 100 }
.each { |una_golondrina| una_golondrina.volar_hacia! Iruya }

Ya que casi terminamos la guía y aprovechando que tenemos una


colección de videojuegos, lo que queremos es... ¡jugar a todos!

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

@juegos = [CarlosDuty, TimbaElLeon, Metroide]

def [Link]

@juegos

end

def self.jugar_a_todo!

@[Link] { |juego| [Link]!(5) }

end
end

¡Muy bien! Tu solución pasó todas las pruebas

¡Terminaste Colecciones!
¡Felicitaciones! A lo largo de esta guía aprendiste:

 Qué son las colecciones


 Qué mensajes básicos entienden: agregar y quitar elementos
mediante push y delete, preguntar si existe un elemento
usando include?, y saber el tamaño de la colección enviándole size
 Qué son los bloques, cómo se aplican y cómo se les pasan
parámetros
 Mensajes más complejos que utilizan bloques
como select, find, map, all?, any?, count, sum y each. ¡Son un montón!

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.

¿No nos creés? ¡Acompañanos!

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!

Ejercicio 1: Zombi caminante


¡Te damos la bienvenida a la invasión zombi!

Vamos a crear al primero de nuestros zombis: Bouba. Bouba no sabe correr,


porque es un simple caminante , y cuando le pedimos que grite,
responde "¡agrrrg!". Además sabe decirnos su salud, que inicialmente es
100, pero puede cambiar.

¿Cuándo cambia? Al recibir_danio!: cuando lo atacan con ciertos puntos de


daño, su salud disminuye el doble de esa cantidad.

Manos a la obra: creá el objeto Bouba, que debe entender los


mensajes sabe_correr?, gritar, salud y recibir_danio!.
¡Cuidado! La salud de Bouba no puede ser menor que 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)

@salud = [(@salud - puntos*2), 0].max

end

end
¡Muy bien! Tu solución pasó todas las pruebas

¡Bien! La salud de nuestro zombi Bouba disminuye cuando recibe daño.


¡Pero aún no hay nadie que lo pueda atacar! Acompañanos...

Ejercicio 2: Atacando un zombi


Te presentamos a la primera de las sobrevivientes de la invasión, Juliana .
Por ahora su comportamiento es simple: sabe atacar! a un zombi con cierta
cantidad de puntos de daño. Y al hacerlo, el zombi recibe daño.

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.

Veamos si se entiende: definí el objeto Juliana que pueda atacar! a un zombi


haciéndolo recibir_danio!, e inicializá su energía en 1000.
Solucion

module Juliana

@energia = 1000

def [Link]

@energia

end

def [Link]!(zombi, puntos)

zombi.recibir_danio!(puntos)

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Ahora que Juliana sabe atacar!, veamos contra quién más se puede
enfrentar...

Ejercicio 3: Otro zombi caminante


¡Bouba no está solo! Resulta que tiene un amigo, Kiki. Podríamos decir que
los dos son tal para cual: ¡el comportamiento de ambos es exactamente el
mismo! Es decir, no sabe_correr?, grita "¡agrrrg!", recibe daño de la misma
forma...
Definí otro objeto, Kiki, que se comporte de la misma forma que Bouba. ¡Te dejamos
a Bouba para que lo uses como inspiración!
Solucion

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

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

end

¡Muy bien! Tu solución pasó todas las pruebas

¿Qué pasó acá? Tenemos dos objetos de comportamiento idéntico, cuya


única diferencia es la referencia con la que los conocemos: uno es Bouba,
el otro es Kiki. ¡Pero estamos repitiendo lógica en el comportamiento de
ambos objetos!

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)

@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
¡Muy bien! Tu solución pasó todas las pruebas

Al igual que nos pasó con el resto de los mensajes, sin_vida? es


exactamente igual para ambos zombis. ¡Otra vez hubo que escribir todo
dos veces!

Ahora ya es imposible no verlo: todo lo que se modifique en un zombi


también se modifica en el otro. ¿Qué problemas nos trae esto?

 Aunque nos equivoquemos en una cosa, el error se


repite dos veces.
 Si cambiara la forma en la que, por ejemplo, reciben daño,
tendríamos que reescribir recibir_danio dos veces.
 ¿Y si hubiese diez zombis en lugar de dos? ¿Y si hubiese cien?
¡Cuántas veces habría que copiar y pegar!

Veamos una solución posible...

Siguiente Ejercicio: Clases

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

Podemos generalizarlos en una clase Celular:

class Celular
def initialize
@saldo = 25
end

def realizar_llamada!
@saldo -= 5
end

def cargar_saldo!(pesos)
@saldo += pesos
end
end

Veamos si se entiende: como Bouba y Kiki se comportan exactamente de la misma


forma, generalizalos definiendo una clase Zombi que entienda los mismos cinco
mensajes que ellos. Podés ver las definiciones de ambos zombis en la solapa
Biblioteca.
Biblioteca

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)

@salud = [(@salud - puntos*2), 0].max

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.

Si el código es parecido pero no puede ser generalizado para que sea el


mismo, las clases no nos servirán. Al menos por ahora...

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.

Momento, ¿cómo es eso? ¿Una clase puede crear nuevos objetos?

¡Así es! Aprovechemos la clase Celular para instanciar los celulares


de María y Lucrecia:

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]

¡Muy bien! Tu solución pasó todas las pruebas

¿Por qué ahora escribimos bouba en lugar de Bouba? ¿O por


qué celular_de_maría en lugar de CelularDeMaría?

Hasta ahora estuvimos jugando con objetos bien conocidos,


como Pepita o Fito. Esos objetos, al igual que las clases, comienzan en
mayúscula. Pero bouba y celular_de_maría son variables: en particular, son
referencias que apuntan a instancias de Zombi y Celular.

Y como ya aprendiste anteriormente, las variables como saludo, despedida,


o kiki comienzan con minúscula.

Ejercicio 7: Al menos tenemos salud


Quizá hayas notado que nuestra clase Zombi tiene, al igual que tuvieron
los objetos Bouba y Kiki en su momento, un atributo @salud. Seguramente
tu Zombi se ve similar a este:

class Zombi

def initialize
@salud = 100
end

def salud
@salud
end

#...y otros métodos

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

> [Link]!(bouba, 25)


=> 50
> [Link]!(kiki, 10)
=> 80
>
Ejercicio 8: Inicializando instancias
Como viste recién, la salud no se comparte entre bouba y kiki a pesar de que
ambos sean instancias de Zombi.

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!

El mensaje initialize nos permite especificar cómo queremos que se


inicialice la instancia de una clase. ¡Es así de fácil!
¡anastasia llega para combatir los zombis! Definí una clase Sobreviviente que
sepa atacar! zombis e inicialice la energia en 1000. En la solapa Biblioteca podés ver el
código de la Juliana original.
Luego, definí juliana y anastasia como instancias de la nueva clase Sobreviviente.
Biblioteca

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

def atacar!(zombi, puntos)

zombi.recibir_danio!(puntos)

end

end

juliana = [Link]

anastasia = [Link]

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 9: Ahora sí: invasión


Prometimos una invasión zombi pero sólo tenemos dos . Ahora que
contamos con un molde para crearlos fácilmente, la clase Zombi, podemos
hacer zombis de a montones.
¿Eso significa que tenés que pensar un nombre para referenciar a cada
uno? ¡No! Si, por ejemplo, agregamos algunas plantas a un Vivero...

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!

Veamos si se entiende: Agregale veinte nuevos zombis a la colección caminantes. ¡No


olvides que los números entienden el mensaje times!
Luego, agregale un método ataque_masivo! a Sobreviviente, que reciba una colección de
zombis y los ataque a todos con 15 puntos de daño.
Solucion

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

def atacar!(zombi, puntos)

zombi.recibir_danio!(puntos)

end

def ataque_masivo!(zombis)

[Link] { |zombi| atacar!(zombi, 15)}

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)

@salud = [(@salud - puntos*2), 0].max

end

def sin_vida?

@salud == 0

end

end

caminantes = []

[Link] { [Link]([Link]) }

¡Muy bien! Tu solución pasó todas las pruebas

¡De acuerdo! Es importante tener en cuenta que nuestros


objetos también pueden crear otros objetos, enviando el mensaje new a
la clase que corresponda.

Por lo tanto, los casos en los que un objeto puede conocer a otro son:

 Cuando es un objeto bien conocido, como con los que veníamos


trabajando hasta ahora
 Cuando el objeto se pasa por parámetro en un mensaje ([Link]
bouba, 4)
 Cuando un objeto crea otro mediante el envío del mensaje new

Ejercicio 10: Al menos tenemos (menos) salud


juliana y anastasia estuvieron estudiando a los zombis y descubrieron que no
todos gozan de máxima vitalidad: algunos de ellos tienen menos salud
que lo que pensábamos.

¡Esto es un gran inconveniente! En nuestra clase Zombi, todos se inicializan


con @salud = 100. ¿Cómo podemos hacer si necesitamos que alguno de
ellos inicie con 90 de @salud? ¿Y si hay otro con 80? ¿Y si hay otro con 70?
No vamos a escribir una clase nueva para cada caso, ¡estaríamos
repitiendo toda la lógica de su comportamiento!

Afortunadamente el viejo y querido initialize puede recibir


parámetros que especifiquen con qué valores deseamos inicializar los
atributos al construir nuestros objetos. ¡Suena ideal para nuestro
problema!

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

¡Y de esa forma creamos tres plantas de 2 , 45 y 110 centímetros


de @altura!

¡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)

@salud = [(@salud - puntos*2), 0].max

end

def sin_vida?

@salud == 0

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Lo que hiciste recién en la clase Zombi fue especificar un constructor:


decirle a la clase cómo querés que se construyan sus instancias.

Los constructores pueden recibir más de un parámetro. Por ejemplo, si de


una Planta no sólo pudiéramos especificar su altura, sino también su
especie y si da o no frutos...

jazmin = [Link] 70, "Jasminum fruticans", true

Siguiente Ejercicio: Súper zombi

Ejercicio 11: Súper zombi


Finalmente llegó el momento que más temíamos: ¡algunos zombis
aprendieron a correr y hasta a recuperar salud! Y esto no es un problema
para las sobrevivientes únicamente, sino para nosotros también. Ocurre
que los súper zombis saben hacer las mismas cosas que los
comunes, pero las hacen de forma distinta. ¡No nos alcanza con una
única clase Zombi!

Un SuperZombi sabe_correr? , y en lugar del doble, recibe el triple de puntos


de daño. Sin embargo, puede gritar y decirnos su salud de la misma forma
que un Zombi común, y queda sin_vida? en los mismos casos: cuando
su salud es 0.

Pero eso no es todo, porque también pueden regenerarse!. Al hacerlo,


su salud vuelve a 100.

¡A correr! Definí la clase SuperZombi aplicando las modificaciones necesarias a la


clase Zombi.
Biblioteca

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)

@salud = [(@salud - puntos*3), 0].max

end

def sin_vida?

@salud == 0

end

def regenerarse!

@salud = 100

end

end

¡Muy bien! Tu solución pasó todas las pruebas

Veamos por qué decidimos hacer una nueva clase, SuperZombi:

 Pueden regenerarse!, a diferencia de un Zombi


 sabe_correr? tiene comportamiento distinto a la clase Zombi
 recibir_danio! tiene comportamiento distinto a la clase Zombi

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.

Siguiente Ejercicio: Ejercitando

Ejercicio 12: Ejercitando


¡Defenderse de la invasión no es para cualquiera! Las sobrevivientes
descubrieron que cada vez que realizan un ataque_masivo! su energía
disminuye a la mitad.

Pero también pueden beber! bebidas energéticas para recuperar las


fuerzas: cada vez que beben, su energia aumenta un 25%.

Modificá la clase Sobreviviente para que pueda disminuirse y recuperarse su energia.


class Sobreviviente

def initialize

@energia = 1000

end

def energia

@energia

end

def atacar!(zombie, danio)

zombie.recibir_danio!(danio)

end

def ataque_masivo!(zombis)

[Link] { |zombi| atacar!(zombi, 15) }

@energia *= 0.5

end

def beber!

@energia *= 1.25
end

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Ya casi terminamos! Antes de irnos, veamos un tipo de sobreviviente


distinto...

Ejercicio 13: Aliados


¡Nadie lo esperaba, pero igualmente llegó! Un Aliado se comporta
parecido a una Sobreviviente, pero su ataque_masivo! es más violento: brinda
20 puntos de daño en lugar de 15.

Por otro lado, su energia inicial es de solamente 500 puntos, y disminuye


un 5% al atacar!. Y además, beber! les provee menos energía: solo aumenta
un 10%.

Nuevamente, Sobreviviente y Aliado tienen comportamiento similar pero no


idéntico: no podemos unificarlo en una única clase. ¡Incluso hay
porciones de lógica que se repiten y otras que no en un mismo método!
Por ejemplo, en ataque_masivo!, los puntos de daño varían, pero el
agotamiento es el mismo para ambas clases.

Definí la clase Aliado. Podés ver a Sobreviviente en la solapa Biblioteca.


Biblioteca

class Sobreviviente
def initialize
@energia = 1000
end
def energia
@energia
end

def atacar!(zombie, danio)


zombie.recibir_danio!(danio)
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

def atacar!(zombi, puntos)

zombi.recibir_danio!(puntos)

@energia *= 0.95

end

def ataque_masivo!(zombis)

[Link] { |zombi| atacar!(zombi, 20)}

@energia *= 0.5

end

def beber!

@energia *= 1.1

end

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Terminaste Clases e Instancias!


¡Ya conocemos todo lo necesario acerca de las clases!

Recordá que sirven para generalizar comportamiento idéntico entre


objetos: si no es exactamente igual, es necesario crear una nueva clase,
como hicimos con Zombi y SuperZombi, o con Sobreviviente y Aliado. En esos
casos tuvimos que repetir parte de la lógica que coincidía entre las clases;
pronto aprenderemos una alternativa.
Herencia
En la guía anterior aprendimos que cuando varios objetos tienen
comportamiento en común podemos crear una clase que lo agrupe. Allí
se define ese comportamiento para evitar la repetición de lógica entre los
distintos objetos.

Sin embargo, cuando tenemos clases que tienen una parte de


comportamiento común pero otra que difiere, las herramientas que vimos
hasta el momento nos quedan cortas.

¡Pero ya no más! ¡Adentrémonos en el mundo de la herencia!

Ejercicios

 1. Aflojá con el aparatito


 2. Notebook
 3. Su superclase
 4. Arte abstracto
 5. ¿Me estás cargando?
 6. Prueba sorpresa
 7. Vamos de paseo
 8. Subí nomás
 9. Inconsciente colectivo
 10. Es un trabajo para super
 11. El regreso de los zombis
 12. Concretemos la herencia
 13. La defensa

Ejercicio 1: Aflojá con el aparatito


Es innegable que en la actualidad los dispositivos electrónicos atraviesan
nuestro día a día . Desde celulares hasta notebooks que están presentes
tanto en nuestro ocio como en nuestros trabajos o estudios. Es por eso
que vamos a modelar distintos dispositivos utilizando la programación
con objetos.

Para entrar en calor vamos a modelar la clase Celular, ¿qué sabemos de


ellos?

 Todos los celulares tienen su @bateria en 100 inicialmente;


 Cuando utilizamos un Celular, su batería disminuye en la mitad de
los minutos que lo hagamos. Por ejemplo: si usamos el celular 30
minutos, su batería bajará en 15.
 Los celulares se pueden cargar_a_tope! para dejar la batería en 100.

Veamos si se entiende: definí la clase Celular y también los


métodos initialize, utilizar! y cargar_a_tope!.

Solucion

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

¡Muy bien! Tu solución pasó todas las pruebas

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

Definí la clase Notebook, que sepa entender los


mensajes initialize, utilizar! y cargar_a_tope!.
Biblioteca

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! Tu solución pasó todas las pruebas

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

¡Obviamente se puede evitar esa repetición de lógica! Vamos al siguiente


ejercicio a ver cómo.

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.

Muchas veces esa jerarquía se puede visualizar en el mundo real: por


ejemplo, Perro y Gato entran en la categoría Mascota, mientras
que Cóndor y Halcón se pueden clasificar como Ave. Cuando programemos,
la jerarquía que utilicemos dependerá de nuestro modelo y de las
abstracciones que utilicemos.

class Ave
def volar!
@energia -= 20
end
end

class Condor < Ave


def dormir!(minutos)
@energia += minutos * 3
end
end

class Halcon < Ave


def dormir!(minutos)
@energia += minutos
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.

¡Uf! ¡Eso fue un montón! A ver si quedó claro.


Definí la clase Dispositivo y modificá las clases que definiste anteriormente para evitar
que haya métodos repetidos entre Celular y Notebook. Es importante que en el editor
definas arriba la superclase y abajo sus subclases.
Solucion

class Dispositivo

def initialize

@bateria = 100

end

def bateria

@bateria

end

def cargar_a_tope!

@bateria = 100

end

end

class Celular < Dispositivo

def utilizar!(minutos)

@bateria -= minutos/2

end

end

class Notebook < Dispositivo

def utilizar!(minutos)

@bateria -= minutos

end

end

¡Muy bien! Tu solución pasó todas las pruebas

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

Ejercicio 4: Arte abstracto


Sabiendo que contamos con las clases Celular y Notebook, ¿alguna vez
instanciaremos un objeto de la clase Dispositivo? ¡Probablemente no! ¿Por
qué querríamos crear algo tan genérico si podemos crear algo más
específico?

A este tipo de clases, como Dispositivo o Ave en el ejemplo del ejercicio


anterior, se las llama clases abstractas porque, a diferencia de las clases
concretas (como Celular o Notebook), nunca las instanciamos. En otras
palabras, no creamos objetos con esa clase, solo nos sirven para proveer
comportamiento a sus subclases.

Ejercicio 5: ¿Me estás cargando?


Una de las grandes molestias que nos traen los dispositivos electrónicos
es cuando se quedan sin batería.

Sabemos que tanto los celulares como las notebooks están descargados
si tienen 20 o menos de batería.

Definí el método descargado? en donde corresponda.


¡Dame una pista!

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

¡Muy bien! Tu solución pasó todas las pruebas

¿Acaso para la Notebook no deberíamos preguntar si está descargada? en


lugar de descargado??

¡Puede ser! Pero si tuvieramos un método por cada clase, no podríamos


tratar polimórficamente a los objetos. Por ejemplo, no habría manera de
saber cuántos dispositivos están descargados porque no existiría un único
mensaje que respondiera nuestra pregunta.
> [Link] { |dispositivo| [Link]? }
=> #¡Fallaría porque Notebook no podría responder al mensaje descargado?!

> [Link] { |dispositivo| [Link]? }


=> #¡Fallaría porque Celular no podría responder al mensaje descargada?!

Siguiente Ejercicio: Vamos de paseo

Ejercicio 6: Prueba sorpresa


¡Tranqui! no es la clase de prueba que estás pensando.

Ya hablamos mucho de las ventajas de la herencia para evitar la


repetición de lógica. Pero, ¿funciona todo esto que estuvimos haciendo?

Probá en la consola los siguientes comandos:

> un_celu = [Link]


> una_notebook = [Link]
> un_celu.descargado?
> un_celu.utilizar! 180
> un_celu.descargado?
> una_notebook.utilizar! 100
> una_notebook.cargar_a_tope!
> una_notebook.descargado?

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
>

Siguiente Ejercicio: Vamos de paseo


Ejercicio 7: Vamos de paseo
Desconectémonos un poco y salgamos de paseo. ¿En qué vamos?

Por ahora nuestras opciones son limitadas. Podemos elegir ir en Auto o


en Moto. De estos medios sabemos que:

 ambos comienzan con una cantidad que podemos establecer


de @combustible;
 los autos pueden llevar 5 personas como máximo y al recorrer! una
distancia consumen medio litro de @combustible por cada kilómetro
recorrido;
 las motos pueden llevar 2 personas y consumen un litro por
kilómetro recorrido;
 ambos pueden cargar_combustible! en la cantidad que digamos y al
hacerlo suben su cantidad de @combustible;
 ambos saben responder si entran? una cantidad de personas. Esto
sucede cuando esa cantidad es menor o igual al máximo que
pueden llevar.

¡Vamos a modelar todo esto!

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)

unas_personas <= maximo_personas

end

end

class Auto < MedioDeTransporte

def maximo_personas

end

def recorrer!(km)

@combustible -= km / 2

end

end

class Moto < MedioDeTransporte

def maximo_personas

end
def recorrer!(km)

@combustible -= km

end

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Excelente!

Estaría bueno tener algún medio de transporte más, ¿no? Acompañanos a


la próxima parada.

Ejercicio 8: Subí nomás


¿Y si no tenemos Auto ni Moto? Vamos a modelar Colectivos así tenemos un
poco más de variedad.

Los Colectivos son un MedioDeTransporte que tienen un máximo de 20


personas y que al recorrer! una distancia gastan el doble de @combustible de
los kilómetros que haya recorrido.

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

class Auto < MedioDeTransporte


def maximo_personas
# ...
end

def recorrer!(kilometros)
# ...
end
end

class Moto < MedioDeTransporte


def maximo_personas
# ...
end

def recorrer!(kilometros)
# ...
end
end

Solucion

class Colectivo < MedioDeTransporte

def maximo_personas

20

end

def recorrer! (kilometros)

@combustible-=kilometros*2

end

end

¡Muy bien! Tu solución pasó todas las pruebas

¿20 personas un colectivo? Yo he visto que lleve más. ¿Además sin


pasajeros?

Bueno, bueno, es verdad. Vamos a mejorar un poco nuestro Colectivo.

Ejercicio 9: Inconsciente colectivo


No hay 2 sin 3, tampoco hay 20 sin 21, o 30...

La verdad es que la cantidad de gente que puede entrar en un Colectivo es


variable, y para simplificar las cosas vamos a decir que en un colectivo
siempre entran personas.

Pero... ¿entonces no es un MedioDeTransporte?


Sí, en realidad es un MedioDeTransporte, solo que responde distinto a entran?.
Lo que podemos hacer es redefinir el método: si Colectivo define el
método entran? va a evaluar ese código en lugar del de su superclase.

Ahora que sabemos que se pueden redefinir métodos, aprovechemos y


cambiemos un poco más nuestra solución. Los colectivos siempre se
inicializan con 100 de @combustible y con 0 @pasajeros.

Redefiní los métodos initialize y entran? en la clase Colectivo.


Biblioteca

class MedioDeTransporte
def initialize(combustible)
# ...
end

def cargar_combustible!(combustible)
# ...
end

def entran?(pasajeros)
# ...
end

def maxi_personas
# ...
end
end

class Auto < MedioDeTransporte


def maximo_personas
# ...
end

def recorrer!(kilometros)
# ...
end
end

class Moto < MedioDeTransporte


def maximo_personas
# ...
end

def recorrer!(kilometros)
# ...
end
end

Solucion

class Colectivo<MedioDeTransporte

def maximo_personas
20

end

def recorrer! (kilometros)

@combustible-=kilometros*2

end

def entran? (personas)

true

end

def initialize

@combustible = 100

@pasajeros=0

end

end

¡Muy bien! Tu solución pasó todas las pruebas

¡Genial!

Esto de la herencia está buenísimo. Porque nos permite heredar el


comportamiento de una superclase pero redefinir aquellas cosas que
nuestras subclases hacen distinto. Pero cuidado, si tenemos que redefinir
todo probablemente no necesitemos heredar en primer lugar.

¿Y qué pasa cuando en una subclase no hago lo mismo que en la


superclase pero tampoco es taaaan distinto?

¡Vamos a verlo!

Ejercicio 10: Es un trabajo para super


Bien sabemos que los colectivos también necesitan cargar combustible
como cualquier MedioDeTransporte, pero ¡qué molesto para los pasajeros! Es
por esto que cuando un Colectivo carga combustible, además de
incrementarlo pierde a todos sus @pasajeros.
El tema es que si redefinimos cargar_combustible! en Colectivo vamos a repetir
lógica con nuestra superclase MedioDeTransporte. No necesariamente,
gracias al mensaje super.

Al utilizar super en el método de una subclase, se evalúa el método con el


mismo nombre de su superclase. Por ejemplo...

class Saludo
def saludar
"Buen día"
end
end

class SaludoDocente < Saludo


def saludar
super + " estudiantes"
end
end

De esta forma, al enviar el mensaje saludar a SaludoDocente, super invoca el


método saludar de su superclase, Saludo.

> mi_saludo = [Link]


> mi_saludo.saludar
=> "Buen día estudiantes"

¡Ahora te toca a vos! Redefiní el método cargar_combustible! en Colectivo, de modo que


haga lo mismo que cualquier MedioDeTransporte y además se quede sin pasajeros.
Recordá utilizar super para evitar repetir lógica.
Biblioteca

class MedioDeTransporte
def initialize(combustible)
# ...
end

def cargar_combustible!(combustible)
# ...
end

def entran?(pasajeros)
# ...
end

def maxi_personas
# ...
end
end

class Auto < MedioDeTransporte


def maximo_personas
# ...
end

def recorrer!(kilometros)
# ...
end
end

class Moto < MedioDeTransporte


def maximo_personas
# ...
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

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 11: El regreso de los zombis


¿Creíste que habíamos terminado con los zombis? ¡Nada más alejado de
la realidad!

Cuando surgieron los SuperZombi, notamos que parte de su


comportamiento era compartido con un Zombi común: ambos
pueden gritar, decirnos su salud, y responder si están sin_vida? de la misma
forma. Pero hasta allí llegan las similitudes: recibir_danio! y sabe_correr? son
distintos, y además, un SuperZombi puede regenerarse!, a diferencia de
un Zombi.

¡Esto nos da una nueva posibilidad! Podemos hacer que SuperZombi herede
de Zombi para:

 Evitar repetir la lógica de aquellos métodos que son iguales, ya


que se pueden definir únicamente en la superclase Zombi;
 redefinir en SuperZombi aquellos métodos cuya definición sea
distinta a la de Zombi;
 definir únicamente en SuperZombi el comportamiento que es
exclusivo a esa clase.

Veamos si se entiende: hacé que la clase SuperZombi herede de Zombi y modificala


para que defina únicamente los métodos cuyo comportamiento varía respecto
de Zombi. ¡Notá que la inicialización también es igual en ambas clases!
Solucion

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)

@salud = [@salud - puntos * 2, 0].max

end

end

class SuperZombi < Zombi

def sabe_correr?

true

end

def recibir_danio!(puntos)

@salud = [@salud - puntos * 3, 0].max

end

def regenerarse!

@salud = 100

end
end

¡Muy bien! Tu solución pasó todas las pruebas

Prestá atención: lo que hicimos aquí es parecido a la herencia de los


dispositivos, pero no igual. En nuestro ejemplo anterior, Dispositivo es una
clase abstracta, porque nunca la vamos a instanciar, y nuestros dos
dispositivos heredan de ella. Pero, ¿no queremos instanciar a la
clase Zombi?

Siguiente Ejercicio: Concretemos la herencia

Ejercicio 12: Concretemos la herencia


A diferencia de lo que pasaba con la clase abstracta Dispositivo y sus
subclases Celular y Notebook, Zombies una clase concreta
¡y SuperZombi hereda de ella sin problemas!

¿Esto quiere decir que los zombis existen?

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

En este caso, y al igual que con los dispositivos, las instancias


de SuperZombi entenderán todos los mensajes que estén definidos en su
clase, sumados a todos los que defina Zombi.

Y como ya aparecieron en muchos ejercicios, tanto los objetos de la


clase Zombi como los de SuperZombi quieren descansar! . Cuando descansan
una cantidad de minutos, su @salud se incrementa en esa cantidad.

Definí el método descansar! en donde corresponda.


Solucion

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)

@salud= [@salud -puntos*2, 0].max

end

end

class SuperZombi < Zombi

def sabe_correr?

true

end

def recibir_danio!(puntos)

@salud = [@salud - puntos* 3, 0].max

end

def regenerarse!

@salud = 100

end
end

¡Muy bien! Tu solución pasó todas las pruebas

Ejercicio 13: La defensa


Zombis por aquí, super zombis por allá, ¿quién podrá ayudarnos?

¡Volvieron las clases Sobreviviente y Aliado! Veamos parte de su


comportamiento:

class Sobreviviente
def initialize
@energia = 1000
end

def energia
@energia
end

def beber!
@energia *= 1.25
end

def atacar!(zombi, danio)


zombi.recibir_danio! danio
end
end

class Aliado
def initialize
@energia = 500
end

def energia
@energia
end

def beber!
@energia *= 1.10
end

def atacar!(zombi, danio)


zombi.recibir_danio! danio
@energia *= 0.95
end
end

Como verás, tenemos distintos grados de similitud en el código:

 energia es igual para ambas clases, porque sólo devuelve la energía;


 Una parte de atacar! coincide: en la que el zombi recibe_danio!, pero
en Aliado reduce energía y en Sobreviviente no;
 beber! es diferente para ambas clases.
Último esfuerzo: definí una clase abstracta Persona que agrupe el comportamiento
que se repite y hacé que las clases Sobreviviente y Aliado hereden de ella.
Solucion

class Persona

def energia

@energia

end

def atacar!(zombi,danio)

zombi.recibir_danio! danio

end

end

class Sobreviviente < Persona

def initialize

@energia = 1000

end

def beber!

@energia *= 1.25

end

end

class Aliado < Persona

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!

Recordá que la herencia es un concepto amplio que tiene muchas


variantes: primero vimos clases abstractas, que no se instancian. También
aprendimos a redefinir los métodos cuando heredamos un método pero
queremos que se comporte de otra forma.

Luego vimos un caso de herencia de una clase concreta, y cómo las


subclases heredan los métodos de su superclase. Por último aprendimos
a usar super: cuando una subclase lo envía, se evalúa el método del mismo
nombre de su superclase.

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

Un programa es la descripción de la solución a un problema que puede


ser ejecutada por una computadora. Está compuesto por la secuencia de
instrucciones necesarias para que pueda lograr su cometido. Al ejecutar el
programa la computadora llevará a cabo lo que le indiquen dichas
instrucciones. El código fuente (o simplemente, código) es la forma en
que escribimos estas instrucciones en un lenguaje de programación
determinado.

Sintaxis

La sintaxis es el conjunto de reglas de escritura del lenguaje en el que


estamos programando.

Un programa que no cumpla con la sintaxis del lenguaje no va a poder


ser “comprendido” por la computadora. Por ejemplo, la sintaxis establece
cuándo usar mayúsculas o minúsculas, cuándo abrir y cerrar paréntesis,
llaves o corchetes, qué palabras tienen un uso reservado, etc.

Por otro lado, la semántica es el significado de las instrucciones que


creamos respetando la sintaxis del lenguaje, lo que interpreta y puede
hacer la computadora al ejecutar nuestro código.

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

Tal como los seres humanos nos comunicamos utilizando distintos


lenguajes, para darle instrucciones a una computadora deberemos
hacerlo utilizando algún lenguaje de programación. Hay muchos y cada
uno tiene sus características, reglas sintácticas, convenciones y
aplicaciones. Si bien cuando programamos podemos encontrar palabras
en inglés u otros idiomas, los lenguajes de programación siguen reglas
totalmente diferentes de las de aquellos.

Algunos lenguajes sirven para cualquier tipo de problema (lenguajes de


propósito general) y otros sirven para hacer cosas específicas. Por
ejemplo:

 Gobstones es un lenguaje destinado únicamente a enseñar los


conceptos fundamentales de la programación;
 JavaScript es de propósito general y se puede usar en una gran
variedad de contextos;
 SQL es un lenguaje que sólo sirve para expresar soluciones a
problemas de manejo de información en una base de datos.

Computadora

Una computadora es cualquier máquina capaz de almacenar y procesar


información para ayudarnos a resolver problemas. Si bien solemos asociar
el término al clásico aparato con una pantalla y un teclado, los teléfonos
inteligentes (smartphones), televisores inteligentes (smart TV)
y tablets también son computadoras que cumplen funciones más
específicas.

Error

Equivocarse es una parte importante de aprender a programar, los errores


pueden enseñarnos más sobre cómo plasmamos nuestras ideas en los
programas y sobre las particularidades del lenguaje elegido. Entre los
errores más comunes podemos encontrar:

 no respetar las reglas sintácticas del lenguaje de programación;


 no resolver el problema para el cual estamos creando nuestro
programa;
 realizar operaciones que no están permitidas.

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.

Su representación visual facilita la ejercitación de la abstracción y la


contextualización. Por eso es el lenguaje que elegimos para presentar los
fundamentos de la programación.

El entorno de Gobstones
Tablero

El tablero es una cuadrícula compuesta por celdas. Las distintas tareas


que hacen nuestros programas con las bolitas y el tablero nos permiten
representar y resolver problemas muy variados. Podemos ver su estado
antes y después de ejecutar un programa.

Bolitas

Cada celda del tablero puede contener un número ilimitado de bolitas


que pueden ser de cuatro colores diferentes: Negro, Verde, Rojo y Azul. Las
herramientas que nos provee Gobstones para manipular las bolitas nos
permiten lograr diferentes configuraciones del tablero para modelar
situaciones y resolver problemas.

Cabezal

El cabezal es un punto de referencia que se ubica en una celda


determinada (la celda actual), y recibe y ejecuta las instrucciones que
operan sobre el tablero y las bolitas, como ponerlas, sacarlas, contar
cuántas hay y moverse desde su celda actual hacia otras del tablero.

Boom

En Gobstones nos toparemos frecuentemente con el ¡Boom! Esta


explosión es una representación gráfica para avisarnos que le estamos
pidiendo a la computadora que haga algo que no puede resolver, por
ejemplo cuando intentamos hacer movimientos fuera del tablero o sacar
bolitas de una celda en la que no las hay.

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

Para crear un programa en Gobstones debemos escribir la


palabra program en minúsculas y a continuación, entre llaves { }, sus
instrucciones. Los programas en Gobstones no llevan nombre. program es
la palabra reservada de Gobstones para indicar el comienzo de un
programa.

program {
Mover(Este)
Poner(Azul)
}

Procedimientos

Los procedimientos son una herramienta de los lenguajes que nos


permiten agrupar dentro de un bloque de código instrucciones que
realizan una tarea específica, y darle un nombre. Nos ayudan a crear
programas más claros, porque al utilizarlos organizamos mejor los pasos
que resuelven un problema, describimos mejor nuestra estrategia y
evitamos repetir lógica.

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

En otras palabras, al definir un procedimiento estamos indicando las


instrucciones precisas que ejecutará al ser invocado.

Invocar un procedimiento es utilizarlo. Para hacerlo hay que escribir su


nombre y los paréntesis dentro de un programa, función u otro
procedimiento. Al ejecutar un programa que incluya la invocación a uno o
varios procedimientos la computadora podrá ponerlos en acción. Por
ejemplo, si quisieramos invocar el
procedimiento PonerUnaBolitaDeCadaColor dentro de un programa
deberíamos escribir:

program {
PonerUnaBolitaDeCadaColor()
}

El procedimiento no tendrá ningún efecto hasta que no lo invoquemos en


al menos un lugar.

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.

La palabra reservada para la repetición simple es repeat, y va seguida por el


número de repeticiones entre paréntesis y los comandos a repetir entre
llaves. Por ejemplo:

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:

Si intentamos repetir la acción de Poner(Azul) y Mover(Este) cuatro veces, en


el último paso vamos a estar fuera de los márgenes del tablero y las
instrucciones no serán válidas. Si, en cambio, repetimos esas acciones tres
veces no colocaremos una bolita azul en la última celda. La solución es
hacer tres repeticiones y por fuera de su estructura nos encargamos de
poner la bolita en la última celda:

program{
repeat(3){
Poner(Azul)
Mover(Este)
}
Poner(Azul)
}

De esa forma el tablero obtenido será este:

Parámetros y argumentos

Cuando queremos generalizar el comportamiento de un procedimiento


para que se adecúe a distintas situaciones de uso similares, podemos
utilizar parámetros. Los parámetros no tienen un valor determinado en el
momento de la definición del procedimiento, pero pueden tomar
potencialmente cualquier valor (siempre que tenga sentido). El parámetro
es un "agujero" que debemos completar con la información particular que
necesitemos al invocar el procedimiento.

Al definir el procedimiento incluiremos entre paréntesis el parámetro (o


parámetros) con un nombre descriptivo en minúsculas. Por ejemplo:

// Este procedimiento nos permitirá movernos dos celdas en cualquier dirección.


procedure Mover2PasosHaciaEl(dirección) {
Mover(dirección)
Mover(dirección)
}

Al invocar el procedimiento tendremos que pasarle un argumento en la


misma posición que el parámetro correspondiente. Cada argumento es el
valor específico que reemplazará al parámetro que le corresponda en
cada una de sus apariciones dentro de la definición de la función o
procedimiento invocado.

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

La alternativa condicional se compone de una estructura de control que


utiliza la palabra if (que significa “si” en inglés). Se escribe if, la condición y
entre llaves las acciones que se deben realizar si la condición se cumple.
Si la condición no es verdadera no se van a ejecutar las instrucciones
entre las llaves, sino que el programa seguirá su curso normal con los
comandos fuera de éstas.

program {
if(hayBolitas(Azul)) {
Sacar(Azul)
} // en este caso si hay al menos una bolita azul va a sacar una.
}

Si queremos hacer una acción específica cuando no se cumple la


condición del if (y solo en ese caso), podemos utilizar la sentencia else (si
no en inglés).

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

Al igual que los procedimientos, las funciones nos permiten dividir el


problema en subtareas para evitar repeticiones y hacer más fácil de
entender la solución. La diferencia entre ambos es que las funciones no
describen acciones sino que encapsulan expresiones, realizan algún tipo
de procesamiento con información de su contexto y devuelven un
resultado, sin ningún efecto real sobre el tablero. Lo que retorne la
función debería ir entre paréntesis a continuación de la palabra return.
La definición e invocación de funciones también debe tener un nombre
claro y descriptivo que indique con precisión qué hace y cuál será el
resultado que nos retornará esa función. A diferencia de los
procedimientos, las funciones se definen utilizando la palabra function y su
nombre con la primera letra de cada palabra en mayúsculas a excepción
de la primera (deEstaForma). Por ejemplo:

function nroBolitasTotal() {
return (nroBolitas(Azul) + nroBolitas(Negro) + nroBolitas(Rojo) + nroBolitas(Verde))
}

Procedimientos primitivos
Poner(color)

Pone una bolita del color indicado en la casilla actual. Ejemplo:

program {
Poner(Rojo) // pone una bolita roja en la casilla actual.
}

Sacar(color)

Saca una bolita del color indicado de la casilla actual. Ejemplo:

program {
Sacar(Negro) // saca una bolita negra de las que hay en la casilla actual.
}

Mover(direccion)

Mueve el cabezal indicador de la casilla actual un paso hacia la dirección


indicada. Ejemplo:

program {
Mover(Este) // mueve el cabezal una vez hacia el Este.
}

IrAlBorde(direccion)

Lleva el cabezal todo lo que se puede hacia la dirección indicada. Ejemplo:

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)

Retorna un número: la cantidad de bolitas del color indicado que hay en


la casilla actual. Ejemplo, asumiendo la siguiende celda actual:

nroBolitas(Rojo) // retorna 4

opuesto(direccion)

Retorna una dirección: la dirección opuesta a la provista. Ejemplo:

opuesto(Norte) // retorna Sur

opuesto(numero)

Retorna un número: el original, negado. Ejemplo:

opuesto(59) // Retorna -59

siguiente(direccion)

Retorna una dirección: la siguiente a la recibida como argumento, es


decir, la próxima en sentido horario. Ejemplo:

siguiente(Oeste) // retorna Norte


siguiente(Norte) // retorna Este
siguiente(Este) // retorna Sur
siguiente(Sur) // retorna Oeste

previo(direccion)
Retorna una dirección: la anterior a la recibida como argumento, es decir,
la próxima en sentido anti horario. Ejemplo:

previo(Sur) // retorna Este

hayBolitas(color)

Retorna un booleano: es verdadero cuando en la casilla actual hay al


menos una bolita del valor indicado. Ejemplo, asumiendo la siguiende
celda actual:

hayBolitas(Rojo) // retorna verdadero


hayBolitas(Verde) // retorna falso

puedeMover(direccion)

Retorna un booleano: es verdadero cuando el cabezal puede moverse en


esa dirección (o sea, no está en el borde). Por ejemplo, estando el cabezal
en la esquina de abajo a la izquierda:

puedeMover(Norte) // retorna verdadero


puedeMover(Oeste) // retorna falso

Bibliografía complementaria

 [Link]
[Link]
Apéndice

 Referencia rápida del lenguaje JavaScript


o Declaración de Funciones
o Operadores matemáticos
o Operadores lógicos
o Comparaciones
o Alternativa Condicional
o Variables
o Repetición indexada
 Biblioteca simplificada
o longitud(unString)
o convertirEnMayuscula(unString)
o comienzaCon(unString, otroString)
o imprimir(unString)
o tirarDado()
o listasIguales
o longitud(unaLista)
o agregar(unaLista, unElemento)
o remover(unaLista, unElemento)
o posicion(unaLista, unElemento)
 Bibliografía complementaria

Referencia rápida del lenguaje JavaScript


El lenguaje JavaScript es utilizado ampliamente para construir software en
todo el mundo, siendo una de las principales tecnologías de la Web. En
este capítulo sólo usamos una muy pequeña parte del mismo, que
listamos a continuación:

Declaración de Funciones

A partir de la Lección 1: Funciones y tipos de datos


Las funciones en JavaScript se declaran mediante la palabra clave function,
y su cuerpo va entre llaves { y }:

function nombreDeLaFuncion(parametro1, parametro2, parametro3) {


return ...;
}

Toda función debe tener al menos un retorno, que se expresa


mediante return.

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

A partir de la Lección 1: Funciones y tipos de datos


true && false
true || false
! false

Comparaciones

A partir de la Lección 1: Funciones y tipos de datos


// para cualquier tipo de dato
"hola" === "hola"
"hola" !== "chau"

// para números
4 >= 5
4>5
4 <= 5
4<5

Alternativa Condicional

A partir de la Lección 1: Funciones y tipos de datos


Los ifs en JavaScript encierran la condición entre paréntesis y su cuerpo
entre llaves:

if (hayPersonasEnEspera()) {
llamarSiguientePersona();
}

Además, los ifs pueden opcionalmente tener un else:

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

A partir de la Lección 3: Variables y procedimientos


Las variables nos permiten recordar valores y se declaran mediante la
palabra reservada let y se les da un valor inicial usando =:

let pesosEnMiBilletera = 100;


let diasQueFaltanParaElVerano = 10;

La mismas se asignan mediante =:

pesosEnMiBilletera = 65;
diasQueFaltanParaElVerano = 7;

En ocasiones las asignaremos usando el valor anterior:

pesosEnMiBilletera = pesosEnMiBilletera * 2;
diasQueFaltanParaElVerano = diasQueFaltanParaElVerano - 1;

La asignación anterior se puede compactar combinando el signo = y la


operación:

pesosEnMiBilletera *= 2;
diasQueFaltanParaElVerano -= 1;

Repetición indexada

A partir de la Lección 7: Recorridos


Las listas pueden ser recorridas, visitando y haciendo algo con cada uno
de sus elementos. Para ello contamos con la estructura de control for..of,
que encierra su generador entre paréntesis (( y )) y su cuerpo entre llaves
({ y }):

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)

A partir de la Lección 1: Funciones y tipos de datos


Versión simplificada de length
Uso:

> longitud("hola")
4

convertirEnMayuscula(unString)

A partir de la Lección 1: Funciones y tipos de datos


Versión simplificada de toUpperCase
Convierte un unString en mayúsculas:

> convertirEnMayuscula("hola")
"HOLA"

comienzaCon(unString, otroString)

A partir de la Lección 1: Funciones y tipos de datos


Versión simplificada de startsWith
Dice si unString empieza con otroString:

> comienzaCon("aprendiendo a programar", "aprendiendo")


true

> comienzaCon("aprendiendo a programar", "aprend")


true
> comienzaCon("aprendiendo a programar", "programar")
false

> comienzaCon("aprendiendo a programar", "tomar el té")


false

imprimir(unString)

A partir de la Lección 3: Variables y procedimientos


Versión simplificada de [Link]
Imprime por pantalla unString:

> imprimir("¡estoy imprimiendo!")


¡estoy imprimiendo!

tirarDado()

A partir de la Lección 3: Variables y procedimientos


Devuelve al azar un número entre 1 y 6:

> tirarDado()
5
> tirarDado()
1
> tirarDado()
2

listasIguales(unaLista, otraLista)

A partir de la Lección 5: Listas


> listasIguales([1,4,7], [1,4,7])
true

> listasIguales([1,4,7], [1,4,8])


false

longitud(unaLista)

A partir de la Lección 5: Listas

 length de listas

Nos dice cuan largo es unaLista:

> longitud([true, false, false, true])


4
> longitud([5, 6, 3])
3

agregar(unaLista, unElemento)

A partir de la Lección 5: Listas


Versión simplificada de push
Inserta unElemento al final de unaLista. Este es un procedimiento que no
devuelve nada pero modifica a unaLista:

> let cancionesFavoritas = ["La colina de la vida", "Zamba por vos"]


// agrega el elemento "Seminare" a la lista cancionesFavoritas
> agregar(cancionesFavoritas, "Seminare")
// ahora la lista tiene un elemento más:
> cancionesFavoritas
["La colina de la vida", "Zamba por vos", "Seminare"]

remover(unaLista, unElemento)

A partir de la Lección 5: Listas


Quita unElemento de unaLista. Este es un procedimiento que no devuelve
nada pero modifica a unaLista:

> let listaDeCompras = ["leche", "pan", "arroz", "aceite", "yerba"]


// removemos "pan"
> remove(listaDeCompras, "pan")
// "pan" ya no está en lista de compras
> listaDeCompras
["leche", "arroz", "aceite", "yerba"]

posicion(unaLista, unElemento)

A partir de la Lección 5: Listas


Versión simplificada de indexOf
Nos dice en qué posición se encuentra unElemento dentro de unaLista. Si el
elemento no está en la lista, devuelve -1

> let premios = ["dani", "agus", "juli", "fran"]


> posicion(premios, "dani")
0
> posicion(premios, "juli")
2
> posicion(premios, "feli")
-1

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.

Conceptos de programación con objetos


Objeto y ambiente

A partir de la Lección 1: Objetos y mensajes


Los objetos son entes computacionales con los que interactuaremos para
resolver problemas. Estos objetos "viven"en un ambiente:

En este ambiente podemos ver a los objetos Pepita, 90 y 100.

Envío de mensajes

A partir de la Lección 1: Objetos y mensajes


La manera de interactuar con los objetos es a través del envío de
mensajes haciendo [Link]:

> [Link]!
> [Link]! 20

En este caso Pepita es el objeto al cual le enviamos:

 el mensaje volar! que no recibe argumentos;


 y el mensaje comer! con el argumento 20.

Definición de objetos

A partir de la Lección 2: Definiendo objetos: métodos y estado


La definición de objetos en Ruby comienza anteponiendo module antes del
nombre y finaliza con end.

module Pepita
end

module Norita
end

Definición de métodos

A partir de la Lección 2: Definiendo objetos: métodos y estado


Para que un objeto entienda un mensaje es necesario crear un método
dentro del mismo. La definición de los métodos comienzan con def y, al
igual que en la declaración de objetos, finaliza con end. En el caso de los
métodos creados dentro de un module es necesario anteponer al
nombre self.. En caso que nuestro método reciba parámetros debemos
ponerlos entre paréntesis separados por coma.

module Pepita
def [Link]!
end

def [Link]!(distancia)
end

def [Link]!(cantidad, comida)


end
end

Interfaz

A partir de la Lección 1: Objetos y mensajes


Interfaz es el conjunto de mensajes que entiende un objeto. En el ejemplo
anterior, la interfaz de Pepita está compuesta por los
mensajes cantar!, volar! y comer!.
Asignación

A partir de la Lección 2: Definiendo objetos: métodos y estado


Para asignarle un valor a una variable utilizamos =.

numero_favorito = 8
color_favorito = "Violeta"

self

A partir de la Lección 2: Definiendo objetos: métodos y estado


Es la manera que tiene un objeto de enviarse mensajes a sí mismo; en
estos casos self es el objeto receptor del mensaje.

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

A partir de la Lección 2: Definiendo objetos: métodos y estado


La responsabilidad, en la programación con objetos, está relacionada con
qué objeto debería resolver las determinadas partes de nuestro problema.
Si un objeto no es responsable de hacer algo lo debe delegar en el
correspondiente.
Atributos

A partir de la Lección 2: Definiendo objetos: métodos y estado


Los atributos son objetos que nos permiten representar una característica
de otro objeto. Un objeto conoce a todos sus atributos por lo que puede
enviarles mensajes. Los atributos se escriben anteponiendo @ y si bien no
es necesario inicializarlos, hasta que no lo hagamos valdrán nil.

module Pepita
@energia = 100

def [Link]!
end

def [Link]=(una_ciudad)
@ciudad = una_ciudad
end

def [Link]!(distancia)
@energia = @energia - distancia * 2
end

def [Link]!(cantidad, comida)


end
end

En este caso @energia es un atributo de Pepita que:

 @energia tiene un valor inicial de 100;


 cuando Pepita recibe el mensaje volar! disminuye su @energia el doble
de la distancia recorrida.
 @ciudad vale nil hasta que no le enviemos a Pepita el
mensaje ciudad= con una ciudad como argumento.

Estado

A partir de la Lección 2: Definiendo objetos: métodos y estado


El estado de un objeto es el conjunto de atributos que posee. Todos los
atributos son privados, para acceder o modificar los atributos de un
objeto es necesario definir métodos dentro del mismo.

Accessors

A partir de la Lección 3: Polimorfismo y encapsulamiento


Los accessors son métodos que nos permiten acceder o modificar el
estado de un objeto y son conocidos como getters y setters
respectivamente.
module Pepita
@energia = 100

def [Link]
@energia
end

def [Link]=(nueva_energia)
@energia = nueva_energia
end
end

Encapsulamiento

A partir de la Lección 3: Polimorfismo y encapsulamiento


El encapsulamiento es la recomendable práctica de minimizar la
exposición del estado de nuestros objetos. Para ello definiremos solo
aquellos accessors que sean indispensables; tengamos en cuenta que no
siempre vamos a querer definir getters y/o setters para todos los atributos
de cada objeto. Veamos un ejemplo:

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

En este caso AutoDeFabi:


 tiene definido un getter para su atributo @patente. Sin embargo, no
define un setter ya que tiene sentido que pueda decir su patente
pero que no se pueda modificar externamente;
 tiene un setter para su atributo @color ya que el objeto Fabi puede
modificarlo directamente;
 no define ningún accessor para su atributo @nafta ya que en caso
que Fabi desee cargar nafta le enviará el mensaje cargar! a AutoDeFabi.

Convenciones para la nominación de métodos

A partir de la Lección 2: Definiendo objetos: métodos y estado


A la hora de ponerle un nombre a los métodos que definimos hay que
tener en cuenta ciertas convenciones de Ruby, es decir, algunos acuerdos
entre la comunidad de personas que programan en este lenguaje:

 Los nombres de métodos que producen un cambio de estado


deben finalizar con !;
 Los nombres de métodos que retornan un valor booleano deben
finalizar con ?;
 Los getters llevan el mismo nombre que el atributo que retornan
pero sin el @.
 Los setters llevan el mismo nombre que el atributo que modifican,
pero sin el @ y con = al final.

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

Si bien nuestro código funcionará correctamente en caso de no respetar


estas convenciones, será menos comprensible para otras personas que lo
lean.
Alternativa Condicional

A partir de la Lección 3: Polimorfismo y encapsulamiento


La alternativa condicional en Ruby comienza con if seguido por la
condición y termina con end:

if [Link]?
[Link]! 10
end

En caso de contar con un rama de else, end va al final del mismo:

if [Link]?
[Link]! 10, "alpiste"
else
[Link]! 15
end

A diferencia de otros lenguajes, en Ruby podemos hacer elsif en caso de


tener un if dentro de un else:

if [Link]?
[Link]!
elsif [Link]?
[Link]!
else
[Link]!
end

Polimorfismo

A partir de la Lección 3: Polimorfismo y encapsulamiento


El polimorfismo en objetos es la capacidad que tiene un objeto de poder
enviarle el mismo mensaje indistintamente a objetos diferentes. Estos
objetos deben entender este mensaje más allá de cómo este definido el
método asociado al mismo, es decir, dos o más objetos son polimórficos
cuando comparten una interfaz. Para que estemos ante un caso de
polimorfismo es necesaria la presencia de al menos tres objetos: uno que
envíe el mensaje y dos distintos que puedan entenderlo. Veámoslo en un
ejemplo:

Supongamos que Agus puede realizar llamadas por celular enviandole un


mensaje llamar! con un parámetro minutos a su atributo @celular:

module Agus
def [Link]=(un_celular)
@celular = un_celular
end

def self.realizar_llamada!(minutos)
@[Link]! minutos
end
end

El celular que Agus utiliza puede ser tanto su CelularPersonal como


su CelularLaboral:

module CelularPersonal
@saldo = 200

def [Link]!(minutos)
@saldo -= minutos
end
end

module CelularLaboral
@minutos_consumidos = 0

def [Link]!(minutos)
@minutos_consumidos += minutos
end
end

Gracias a que CelularPersonal y CelularLaboral son polimórficos para el


mensaje llamar!, Agus puede realizar llamadas sin tener que verificar qué
celular está utilizando.

Referencias

A partir de la Lección 4: Referencias


Cuando le enviamos un mensaje a un objeto, en realidad no lo
conocemos directamente sino que lo hacemos a través de etiquetas
llamadas referencias. Algunos ejemplos de referencias y envío de
mensajes a través de las mismas son:

 las variables

dia = "domingo"
[Link]

 las referencias implícitas


"insomnio".upcase
^
+-- Acá hay una referencia implícita al objeto "insomnio"

 los objetos bien conocidos (los que declaramos con module)

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

A partir de la Lección 5: Colecciones


Las colecciones son objetos que contienen referencias a otros objetos. Un
tipo de colección son las listas, las cuales se escriben entre corchetes ([]) y
permiten tener objetos repetidos con un orden determinado dentro de
ellas:

> libros = [Fundacion, Socorro, Elevacion, Kriptonita, Socorro]


Otro tipo de colecciones muy común son los sets, los cuales a diferencia
de las listas no pueden tener elementos repetidos y sus elementos no
tienen un orden determinado:

> numeros_aleatorios = [1,27,8,7,8,27,87,1]


> numeros_aleatorios
=> [1,27,8,7,8,27,87,1]
> numeros_aleatorios.to_set
=> #<Set: {1, 27, 8, 7, 87}>

Bloques de código

A partir de la Lección 5: Colecciones


Los bloques son objetos que representan un mensaje o una secuencia de
envíos de mensajes, sin ejecutar, lista para ser evaluada cuando
corresponda.

> anio_actual = 2021


> anio_nuevo = proc { anio_actual = anio_actual + 1 }

Estos bloques de código pueden tomar parámetros escritos


entre || separados por comas.

> saludador = proc { |saludo, nombre| saludo + " " + nombre + ", que lindo día para programar, ¿no?" }

Dentro de cada bloque podemos usar y enviarle mensajes tanto a los


parámetros del bloque (saludo y nombre) como a las variables declaradas
fuera del mismo (anio_actual).

Por último, para ejecutar el código dentro del bloque debemos enviarle el
mensaje call con los argumentos correspondientes.

> anio_nuevo.call
=> 2022

> [Link]("Hola", "Jor")


=> "Hola Jor, que lindo día para programar, ¿no?"

Clases e instancias

A partir de la Lección 6: Clases e Instancias


Las clases son objetos que sirven de moldes para crear nuevos objetos
que tienen el mismo comportamiento.
Por ejemplo, si tuvieramos dos perros representados con los
objetos Firulais y Stimpy:

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

Podemos ver que tienen el mismo comportamiento. Para poder


solucionar esta repetición podríamos crear la clase Perro:

class Perro
def initialize(energia)
@energia = energia
end

def jugar!(un_tiempo)
@energia -= un_tiempo
end

def recibir_duenio!
@energia += 100
end
end

El método initialize de las clases permite especificar cómo se inicializan las


instancias de una clase. En este método declararemos los valores iniciales
de los atributos. Por último para crear nuestros objetos debemos hacer:

firulais = [Link] 200


stimpy = [Link] 300
Estos nuevos objetos creados a partir de una clase (firulais y stimpy) son
instancias de la misma. Es importante tener en cuenta que:

 Todo instancia pertenece a una y sólo una clase.


 No se puede cambiar la clase de una instancia en tiempo de
ejecución.

Herencia

A partir de la Lección 7: Herencia


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.

Por ejemplo si tuvieramos:

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

Podríamos crear la clase Mascota:


class Mascota
def initialize(energia)
@energia = energia
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 <:

class Gato < Mascota


def recibir_duenio!
@energia -= 10
end
end

class Perro < Mascota


def recibir_duenio!
@energia += 100
end
end

En nuestra nueva jerarquía Mascota es una superclase de la cual heredan


las subclases Gato y Perro.

Redefinición

A partir de la Lección 7: Herencia


La redefinición de métodos de una superclase nos permite modificar en
las subclases el comportamiento definidio originalmente. Por ejemplo si
en una subclase Gallina de Mascota quisieramos redefinir el método jugar! lo
haríamos de esta forma:

class Gallina < Mascota


def jugar!(un_tiempo)
@energia -= 5
end

def recibir_duenio!
@energia *= 2
end
end

Clases abstractas

A partir de la Lección 7: Herencia


Las clases abstractas son clases que no se desea instanciar. Sirven para
abstraer la lógica repetida de otras clases pero no las usaremos como
molde de otros objetos. En contraposición, aquellas que sí instanciaremos
son las llamadas clases concretas. En el ejemplo anterior Mascota es una
clase abstracta mientras que Gato y Perro son clases concretas.

super

A partir de la Lección 7: Herencia


super nos permite redefinir un método pero sólo agregar una parte nueva
a la funcionalidad, reutilizando la lógica común que está definida en la
superclase. Al utilizar super en el método de una subclase, se evalúa el
método con el mismo nombre de su superclase.

Por ejemplo:

class Pichicho < Perro


def recibir_duenio!
super
[Link]!
end
end

Operadores
Operadores matemáticos

A partir de la Lección 1: Objetos y mensajes


8+7
32 - 9
2*3
4/2

Operadores lógicos

A partir de la Lección 1: Objetos y mensajes


true && false
true || false
! false

Comparaciones

A partir de la Lección 1: Objetos y mensajes


Pepita == Norita
"ser" != "estar"
7 >= 5
7>5
7 <= 5
7<5

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]

A partir de la Lección 2: Definiendo objetos: métodos y estado


Permite obtener el valor absoluto de un número.
> [Link]
=> 8

> (-8).abs
=> 8

> (3 - 7).abs
=> 4

[Link] bloque

A partir de la Lección 3: Polimorfismo y encapsulamiento


Ejecuta el código del bloque tantas veces como diga numero.
> [Link] = 5

> [Link] { [Link] = [Link] * 2 }

> [Link]
=> 40

[Link]

A partir de la Lección 4: Referencias


Retorna un nuevo string con todos los caracteres de string en mayúsculas.
> "libro".upcase
=> "LIBRO"

[Link]

A partir de la Lección 4: Referencias


Retorna la cantidad de caracteres de string.
> "camino".size
=> 6
[Link]?

Lección 4: Referencias
Nos permite saber si numero es par.
> [Link]?
=> true

> [Link]?
=> false

[Link]? otro_objeto

A partir de la Lección 4: Referencias


Nos permite saber si objeto y otro_objeto son referencias que apuntan a
exactamente el mismo objeto.
> un_string = "lamparita"
> otro_string = un_string

> un_string.equal? "lamparita"


=> false

> un_string.equal? otro_string


=> true

[Link] elemento

A partir de la Lección 5: Colecciones


Agrega elemento a coleccion.
> numeros_de_la_suerte = [8, 7, 42]

> numeros_de_la_suerte.push 9

> numeros_de_la_suerte
=> [8, 7, 42, 9]

[Link] elemento

A partir de la Lección 5: Colecciones


Remueve elemento de coleccion.
> numeros_de_la_suerte = [8, 7, 42]

> numeros_de_la_suerte.delete 7

> numeros_de_la_suerte
=> [8, 42]

[Link]? elemento

A partir de la Lección 5: Colecciones


Nos permite saber si elemento pertenece a coleccion.
> [25, 87, 776].include? 8
=> true

> [25, 87, 776].include? 9


=> false

[Link]

A partir de la Lección 5: Colecciones


Retorna la cantidad de elementos dentro de coleccion.
> ["hola", "todo", "bien", "por", "acá"].size
=> 5

[Link] bloque_con_condicion

A partir de la Lección 5: Colecciones


Retorna una nueva colección con los elementos de coleccion que cumplan
con la condición de bloque_con_condicion. Este método no tiene efecto
sobre coleccion.
> [1, 2, 3, 5, 7, 11, 13].select { |un_numero| un_numero > 5 }
=> [7, 11, 13]

[Link] bloque_con_condicion

A partir de la Lección 5: Colecciones


Retorna el primer el elemento de coleccion que cumpla con la condición
de bloque_con_condicion. Si ningún elemento cumple la condición nos
devuelve nil.
> [1, 2, 3, 5, 7, 11, 13].find { |un_numero| un_numero > 15 }
=> nil

[Link]? bloque_con_condicion

A partir de la Lección 5: Colecciones


Nos permite saber si todos los elementos de coleccion cumplen con la
condición de bloque_con_condicion.
> [1, 2, 3, 5, 7, 11, 13].all? { |un_numero| un_numero > 5 }
=> false

> [1, 2, 3, 5, 7, 11, 13].all? { |un_numero| un_numero < 20 }


=> true

[Link] bloque

A partir de la Lección 5: Colecciones


Retorna una nueva colección con el resultado de ejecutar el código
de bloque por cada elemento de coleccion.
> [1, 2, 3, 4, 5].map { |un_numero| un_numero * 2 }
=> [2, 4, 6, 8, 10]

[Link] bloque_con_condicion

A partir de la Lección 5: Colecciones


Retorna cuántos elementos de coleccion cumplen con la condición
de bloque_con_condicion.
> [1, 2, 3, 5, 7, 11, 13].count { |un_numero| un_numero > 3 }
=> 4

[Link] bloque

A partir de la Lección 5: Colecciones


Retorna la suma de los valores obtenidos al ejecutar el código
de bloque en cada elemento de coleccion.
> juegos_de_mesa = [Ajedrez, Damas, Ludo]

> juegos_de_mesa.sum { |un_juego| un_juego.cantidad_de_piezas }


=> 60 # 32 del ajedrez + 24 de las damas + 4 del ludo

[Link] bloque

A partir de la Lección 5: Colecciones


Ejecuta el código de bloque por cada elemento de coleccion. El
método each no retorna una nueva colección sino que tiene efecto sobre
la original.
> golondrinas = [Pepita, Norita, Mercedes]

> [Link] { |una_golondrina| una_golondrina.comer_lombriz! } # Hace que cada golondrina de l


a colección coma lombriz.

[Link]

A partir de la Lección 6: Clases e Instancias


Crea y retorna una nueva instancia de Clase.
> guitarra = [Link]
> piano = [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?...

Definí en Ruby el método cantidad_de_gente_aprobada que responda a cuántas personas


aprobaron de Alumnado.
Solucion

module Alumnado

@estudiantes = [May, Gus, Ro, Agus, Lu, Ale]

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

También podría gustarte