0% encontró este documento útil (0 votos)
317 vistas83 páginas

Errores en Programación y Parámetros

Este documento discute varios temas relacionados con la programación, incluyendo el uso de parámetros, la definición y uso de procedimientos, la reutilización de código, y el uso de repeticiones. Explica cómo definir procedimientos que acepten parámetros para hacer el código más genérico y reutilizable. También destaca la importancia de usar la solución más simple posible y reutilizar código existente en lugar de volver a escribirlo.

Cargado por

Miguel Trubiano
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 DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
317 vistas83 páginas

Errores en Programación y Parámetros

Este documento discute varios temas relacionados con la programación, incluyendo el uso de parámetros, la definición y uso de procedimientos, la reutilización de código, y el uso de repeticiones. Explica cómo definir procedimientos que acepten parámetros para hacer el código más genérico y reutilizable. También destaca la importancia de usar la solución más simple posible y reutilizar código existente en lugar de volver a escribirlo.

Cargado por

Miguel Trubiano
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 DOCX, PDF, TXT o lee en línea desde Scribd

Errores comunes con procedimientos y parámetros

Reutilización de herramientas
Programar se trata de constantemente construir herramientas de cada vez más alto nivel que
nos ayuden a resolver nuestro problema. A medida que avancemos en las clases y en la
dificultad, el Poner y Mover van a quedar cada vez más enterrados, porque sino es
imposible construir cosas más interesantes que una línea.
Muchos teclearon en el e y el f de la tarea; cuando se les pidió el DibujarFila, que era
de más alto nivel, se olvidaron del Rojo y Azul salteado y volvieron a Poner y Mover:
¡NO! Siempre construimos sobre lo anterior, los ejercicios están incluso planteados así. En
programación copiar y pegar es un indicio de que algo estamos haciendo mal.
Confusión entre definición y uso
 Cuando lo defino, no sé qué valor va a tener, justamente ese es el chiste. Por eso,
nunca nunca nunca un parámetro se va a poder llamar Norte ni Rojo, porque eso
espero que me lo pase quien lo va a usar.
 Cuando lo uso, tengo que darle un valor, que por ahora se puede hacer de 2 formas:
con un literal (Azul, Negro, Este, Sur) o “pasándole” otro parámetro (sólo vale
cuando un procedimiento llama a otro, no se puede hacer esto en el program, porque
no puede tener parámetros).
Parametritis
Es un mal que aqueja tanto a aprendices como a profesionales. Cada vez que aprendemos
una herramienta nueva, tendemos a querer usarla por todos lados, aún cuando esto
complejiza nuestro código.
En programación, la mejor solución es siempre la más sencilla, y aprender a hacer eso es
toda una habilidad. Nosotros tenemos una ventaja que no tienen otras disciplinas: cambiar
no nos cuesta casi nada, y tenemos que aprender a aprovecharlo. Moraleja: parametricen si
y sólo si eso les hace escribir menos código, y no más.
Ejercitación
Banderas. Armamos pseudo-banderas de Argentina, Italia, Francia y Perú, con la
condición de que para construir una bandera tenía que haber 3 llamados al mismo
procedimiento. El código, con alguna que otra variante, terminó quedando así:
procedure Argentina() {
FranjaHorizontal(Azul)
Mover(Norte)
FranjaHorizontal(Negro)
Mover(Norte)
FranjaHorizontal(Azul) }
procedure Italia() {
FranjaVertical(Verde)
Mover(Este)
FranjaVertical(Negro)
Mover(Este)
FranjaVertical(Rojo) }
Una vez construidas las 4 banderas, nos dimos cuenta que podíamos generalizar todavía un
poco más: para armar una bandera horizontal o vertical de 3 franjas basta simplemente con
elegir los 3 colores. La segunda versión quedó entonces así:
procedure Argentina() {
BanderaHorizontal(Azul, Negro, Azul)
}
procedure Italia() {
BanderaVertical(Verde, Negro, Rojo)
}

Como cierre, concluimos en que esto simplemente era un ejercicio para usar parámetros y
más parámetros, y por eso seguimos abstrayendo hasta llegar a generalizar la construcción
de las banderas. De nuevo, la solución más simple siempre es la mejor, y sólo vamos a
intentar hacer algo “más genérico” si la situación lo amerita.
Cuadrado relleno. La siguiente tarea fue armar un procedimiento que permitiera construir
un cuadrado de 4x4 con un color para el contorno y otro para el relleno. Surgieron de nuevo
algunas dudas, varixs confundieron el ejemplo que yo di (borde rojo y contorno verde) e
hicieron un procedimiento que sólo construía cuadrados de esos colores.
La estrategia sugerida fue pensar el contorno por un lado y el relleno por otro, quedando
como solución propuesta la siguiente:
procedure Cuadrado(colorRelleno, colorContorno) {
Contorno(colorContorno)
Mover(Este)
Mover(Norte)
Relleno(colorRelleno)
}

Varios dibujos con líneas negras. Lo último, que además quedó como tarea, fue resolver
los ejercicios que están desde la página 9 de la guía en adelante, con dos pequeños cambios:
 en vez de implementar los LineaNorte4, LineaEste4, LineaSur4 y
LineaOeste4 que se pedían, la idea es hacerlo todo con un Linea4(direccion);
 lo mismo para los LineaNorte4V, LineaEste4V, LineaSur4V y LineaOeste4V,
pero esta vez van a necesitar parametrizar la dirección de la ida y la de la vuelta
Linea4V(direccionIda, direccionVuelta. Obviamente, la de la vuelta
siempre tiene que ser la opuesta a la de la ida (todavía no conocemos una mejor forma
de manejar esto, paciencia…).
Para quienes terminen todos los que están ahí, les queda como desafío hacer este hermoso
dibujo de un numeral o hashtag, alusivo a los tiempos digitales que corren:
Pista: sale pensándolo como dos pasillos (ver ejercicio c).
aprender a usar una nueva herramienta: la repetición simple. En gobstones, esto lo
conocemos como repeat.
Motivación
Hicimos un procedimiento Poner37Verdes, que hace justamente eso,
poner 37 bolitas verdes en el casillero actual. Para ello, no escribimos 37
veces el Poner , sino que usamos el repeat, que es la nueva
herramienta que tenemos .
program {
Poner37Verdes()
}
procedure Poner37Verdes(){
repeat(37){
Poner(Verde)
}
}
Dijimos también que la repetición simple cambia el flujo de ejecución. Antes era recto,
lineal (una línea atrás de la otra), y ahora, cuando aparece un repetir, aparece lo que se
llama un ciclo.

Jugando un poco
A. Hacer un procedimiento Poner10AlLado, que pone 10 bolitas Negras, todas en el
casillero que está al Este del casillero actual.
B. Hacer un procedimiento PonerLejos que ponga 1 bolita Negra 7 casilleros al Este, y
vuelva a la posición original.
Estos dos ejercicios A y B nos sirvieron para entender que se pueden poner instrucciones
antes y después del repeat.
C. Teniendo en cuenta este tablero inicial:

Hacer corresponder estos 4 programas con sus tableros finales:

program { program { program { program {


 Poner(Azul)  repeat(3){  repeat(3){  repeat(3){
 repeat(3){   Poner(Azul)  Poner(Azul)   Mover(Norte)
  Mover(Norte) }   Mover(Norte)  Poner(Azul)
 }  Mover(Norte) }  }
} } } }
Desordenadas:

En este ejercicio vimos, sobretodo con los últimos dos programas, que sigue
importando el orden de las instrucciones dentro del repeat así como ya importaba
fuera.

El cuadrado ahora es fácil


D. Hacer el procedimiento Cuadrado5x5Negro, que dibuja un cuadrado de esas medidas,
relleno, todo con una bolita negra en cada casillero.
Se nos ocurrieron dos posibles estrategias.

 La primera, hacer un zigzag hacia arriba. Como si fuera una impresora, imprimo
hacia el Este, subo, e imprimo hacia el Oeste, y así.
 La segunda estrategia es la que elegimos, porque aprovecha que algo se repita. Es
así: Dibujo una línea, vuelvo sin dibujar, y subo. Y así.
procedure Cuadrado5x5Negro() {
repeat(5){
HacerLinea5()
MoverOeste5()
Mover(Norte)
}
}
procedure HacerLinea5(){
repeat(5){
Poner(Negro)
Mover(Este)
}
}
procedure MoverOeste5(){
repeat(5){
Mover(Oeste)
}
}

BOOM! Tu tablero no es suficientemente grande… Muchos intentaron hacer el


cuadrado en un tablero de 5x5, pero tenían el problema de que en su estrategia el
cabezal necesitaba un casillero más, porque se pasaba. Mucho cuidado con esto.
Con Fede el Martes van a profundizar esto, que les adelanto, se llama caso borde.

Más ejercitación
E. Hacer el procedimiento Diagonal4x23(), que haga lo siguiente con bolitas azules:
F. Hacer el procedimiento MoverN(cant,direccion) que mueva el cabezal tantas veces
como se indique en la dirección que se indique
G. Hacer el procedimiento PonerN(cant,color) que ponga en la celda actual tantas
bolitas como indique cant, del color indicado.
H. Hacer de nuevo el ejercicio E, pero ahora haciendo que Diagonal4x23() use el
procedimiento PonerN(...).
I. Hacer el procedimiento LineaVa(long, dir, color) para que dibuje una “línea” de
bolitas en la dirección dir, del color indicado y de la longitud indicada.
J. Hacer nuevamente el ejercicio que hicieron con Fede de ContornoYRelleno(), para
que use los procedimientos anteriores donde convenga.
Nombres de las variables
Hicimos un pequeño apartado en el que hablamos sobre los nombres. Por ejemplo, si quiero
Si queremos Le ponemos Pero no le ponemos y tampoco
Un
moverHaciaArriba
procedimiento Moverhaciaarriba
MoverHaciaArrib (porque un procedimiento
que se llame (porque debemos separar
a debe empezar con
“Mover hacia visualmente las palabras)
mayúscula)
arriba”
Un parámetro CantidadDePasos
cantidaddepasos
que se llame (porque los parámetros
cantidadDePasos (porque debemos separar
“cantidad de comienzan con
visualmente las palabras)
pasos” minúscula)
1. Volver a definir el procedimiento que hicieron con Fede de la guía 2
(PonerConDobleYTriple(cantRojas)), que pone en la celda actual, la
cantidad indicada de celdas rojas, el doble de negras, y el triple de verdes. Esta vez,
sin usar repeat, usando PonerN (que ya la tienen definida) y usando expresiones.
2. Hacer el procedimiento ReplicarAzulesConRojas(), que pone tantas bolitas
rojas en el casillero actual como cantidad de bolitas azules. Para ilustrar lo que hace,
tres ejemplos:
3. Hacer el procedimiento SacarTodas(color) que saca todas las bolitas del
casillero actual que son del color indicado.
4. Ejecutar a mano, a partir del tablero inicial propuesto, este programa, y obtener el
tablero final: ¡NO VALE EJECUTARLO en Gobstones!

5. DuplicarCelda(), que duplica todos los colores. Es decir, si en el tablero inicial


en la celda actual ya hay 2 bolitas rojas y 5 azules, cuando el procedimiento
DuplicarCelda() se ejecute, el tablero final tendrá 4 bolitas rojas y 10 azules.
6. PasarTodoANegro() “transforma” todas las bolitas de la celda actual en negras.
7. DejarExactamente(color,n), cuando hay muchas bolitas de un color, este
procedimiento sirve para sacar las necesarias para llegar a n. (No vale Poner en
ningún momento, sólo sacar)
8. Hacer el procedimiento Linea(long,dir,color) que sea como LineaVa
(usarla), pero que al finalizar deje el cabezal en la posición inicial.
Fotos de la clase
¡Recuerden que no hay que repetir código! En particular en PasarTodoANegro()
deberían reusar SacarTodas()
Tarea
1. Hacer el procedimiento TocoYMeVoy(dir,color), que viaja en la dirección dir,
pone una bolita del color indicado, y vuelve. Para saber cuántas veces moverse,
cuenta las bolitas negras del casillero inicial. ¡Reusar procedimientos que ya

hayamos hecho! O sea, Si parto de este tablero: y


hago TocoYMeVoy(Este,Rojo), obtengo este tablero:
Porque había 3 bolitas negras en la posición inicial. Si

parto de este tablero: y hago


TocoYMeVoy(Oeste,Verde), obtengo este tablero:

Porque había 2 bolitas negras en la posición inicial.

2. Hacer el procedimiento Ele3(direccion) que hace una “L” de 3 bolitas de ancho


y 3 bolitas de alto. La dirección indica el sentido de la “L”. Por ejemplo, si
ejecutamos: Ele3(Norte) dibuja una clásica “L”, y si ejecutamos: Ele3(Oeste)
dibuja una “L” acostada, mirando hacia arriba. El casillero inicial es la esquina de la
L, y el cabezal debe volver a la posición inicial. Por ejemplo, Ele3(Oeste)

produce lo siguiente: Pista: necesitan una expresión que


está en el machete de Gobstones y que todavía no vieron

formalización de expresiones
La última vez vieron una especie de procedimientos que devuelven o denotan valores:
nroBolitas(color), opuesto(direccion) y otros tantos que ya están en el machete;
el nombre correcto para estos “procedimientos especiales” es expresiones. Entonces a las
que ya conocían, que se llaman expresiones literales (7, Sur, Rojo) se le agregan estas
otras más inteligentes, que hacen alguna operación, computan, pueden depender de la
entrada (argumentos o estado del tablero).
Con esta noción, empezaron a hacer algunos programas y procedimientos que dependen
del tablero. Por ejemplo, ejecutar PasarTodoANegro() tiene un efecto si hay bolitas y
otro efecto (en particular, ninguno) si no las hay. Hoy vamos a seguir en esa línea de “lo
desconocido”, vamos a seguir aprendiendo a preguntarle cosas a Gobstones.
Alternativa condicional
Dentro de todo el universo de preguntas que podemos hacer, las que nos van a interesar son
aquellas que puedan responderse por sí o por no, o siendo más formales por Verdadero y
Falso (hola Lucrecia).
Entre todos, surgieron estas preguntas:

Luego, vimos un ejemplo: MoverMiedoso(dir). ¿Qué hace? Antes de moverse en la


dirección dada, pregunta si puedeMover (por eso es miedoso).
De acá en adelante, hicimos unos cuantos ejercicios, que pongo acá más abajo. Los que
están (entre paréntesis) son de la guía complementaria 3 y los que están [entre corchetes]
son de la práctica 3.
 (3a) AsegurarAlMenosUna(col) - acá aparece el not como forma de negar una
condición: not hayBolitas(col). Es como el ¬p o ~p de Matemática.
 (3b) AsegurarUnaDeCada() - hay que reutilizar el anterior, con cada uno de los
colores.
 [28] DesempatarDos(c1, c2) - acá surge la primera expresión booleana
compuesta, hay que usar un and: nroBolitas(c1) == nroBolitas(c2)
 [30] Desempatar() - similar al anterior. Un truquito matemático que vimos es que
alcanza con hacer 3 comparaciones para saber que los 4 son iguales.
 [27] PonerCSiHayXeY(c, x, y) - fácil, parecido al 28.
Hasta ahí la complejidad venía casi exclusivamente en pensar “la pregunta”, la expresión
booleana. A partir del ejercicio (6) surgió la necesidad de hacer algo distinto si no se
cumplía tal condición, y así surgió el else. Arrancamos entonces otra tanda de ejercicios:
 (6) MoverPalanteOPatras(dirAdelante, colGuia) -
 (7) MoverSegunColor(dir1, dir2, col) - en la misma línea que el anterior.
 [31] PonerOSacarAcorde(c, acorde) - en la misma línea que el anterior.
 (8) MoverSegunCantDeColor(col) - un embole. Moraleja: se pueden anidar
ifs -poner uno adentro del otro- aunque es feo, conviene delegar siempre que se
pueda (en este caso no se podía).
 (9) MoverSegunColor(dir1, dir2, col) - este salía más o menos fácil.
 (10) DescomprimirHacia(dir, col1, col2) - ¡reutilizar! sale usando el
procedimiento anterior.
Repaso de estado del tablero
Hoy vimos un truquito para solucionar el problema de TocoYMeVoy. El truquito no es tan
importante, lo importante es entender por qué no salía el ejercicio:
Solución incorrecta:

procedure TocoYMeVoy(dir,color){
MoverN(nroBolitas(Negro),dir)
Poner(color)
MoverN(nroBolitas(Negro),opuesto(dir))
}

Acá el paso a paso que explica que cuando ya estoy lejos, no sé cuánto volver, porque el
nroBolitas es una expresión que sí o sí tengo que usar en el casillero inicial. ¡Allá lejos
no hay bolitas negras, están acá!
Solución con truquito (lee el tablero sólo una vez):
procedure TocoYMeVoy(dir,color) {
TocoYMeVoyConCant(nroBolitas(Negro),dir,color)
}
procedure TocoYMeVoyConCant(cant,dir,color) {
MoverN(cant,dir)
Poner(color)
MoverN(cant,opuesto(dir))
}

Dominios: Escapando del Incendio


Hoy introdujimos dominios, lo que significa que de ahora en más vamos a empezar a usar
el tablero, las bolitas y el cabezal para representar ideas de la realidad, como ser un reloj,
una persona escapando del fuego, ó un bosque con árboles.
Esto implica que deben aparecer las abstracciones del dominio en mi programa. En
otras palabras, si hay una persona que debe escapar de un incendio, la palabra “Tipo” ó
“Persona” tiene que aparecer en el procedimiento que corresponda. En nuestro caso de
“Escapando del incendio”, hicimos un procedimiento que se llamaba AvanzarUnPaso,
que representaba un paso en el camino de la persona, y el procedimiento MoverTipito
que justamente movía a las personas. Dar un paso es una abstracción de dominio, y la
hicimos aparecer en nuestro programa como un procedimiento, y lo mismo pasa con la idea
de Persona, que estaba representada por una bolita Negra pero escondimos ese hecho
detrás del procedimiento MoverTipito.
La estrategia siempre primero:

La versión final fue:


procedure AvanzarUnPaso(){
Mover(Este)
if(hayBolitas(Rojo)){
VolverYMoverTipito(Norte)
} else {
VolverYMoverTipito(Este)
}
}

procedure VolverYMoverTipito(dir){
Mover(Oeste)
Sacar(Negro)
Mover(dir)
Poner(Negro)
}

Dominios: El bosque
Hicimos también el ejercicio del Bosque, que está al final de la Guía 3.
Aquí vuelve a ser importante que aparezcan las abstracciones de dominio en nuestro
programa. En otras palabras, si el enunciado habla de semillas, habla de nutrientes y de
árboles, entonces tiene que haber procedimientos acordes. No vale que nuestro programa
hable sólo de bolitas.

Miren acá, por ejemplo: usamos UsarSemilla en vez de Sacar(Rojo). ¡Importantísimo!


La importancia de nombrar las cosas
La semana anterior estuvieron hablando con Alf sobre qué importante es ponerle nombre a
las partes de nuestro problema y que esos nombres aparezcan en nuestro programa. Eso nos
ayuda en varios aspectos:
 sólo mirando el código podemos entender de qué va nuestro problema, lo que
reduce la distancia entre el problema real y el programa que lo resuelve;
 al olvidarnos de las bolitas, el universo de problemas que podemos resolver es
mucho más grande;
 nos “despegamos” de la representación, haciendo que la misma sea más fácil de
cambiar.
Todo muy lindo, pero con lo que sabemos hasta ahora se nos está escapando la tortuga…
veamos un ejemplo.
En el ejercicio El bosque de la guía 3, se pedía lo siguiente:
Escribir el procedimiento Germinar(), que transforma una semilla en planta en la
celda actual. La germinación consume tres unidades de nutrientes. Si en la celda no
hay semilla, o no hay suficientes nutrientes, no se hace nada.
y nosotros propusimos esta solución:
procedure Germinar() {
if (hayBolitas(Rojo) && nroBolitas(Azul) >= 3) {
TransformarSemillaEnArbol()
}
}

Se ve que los conceptos de “hay semilla” y “hay suficientes nutrientes” que estaban en la
definición del problema se perdieron en la representación: nuestro procedimiento sólo
habla de bolitas de colores. Pero también se ve que con lo aprendido hasta ahora no
podemos mejorarlo, ya que lo que necesitamos es poder crear nuestras propias
expresiones. ¿Y entonces qué hacemos?
Funciones, ¡al poder!
Vamos a sumar a unas nuevas invitadas a nuestra fiesta de la programación: las funciones.
En cierta forma, podemos decir que son primas de los procedimientos, pero tienen una
diferencia fundamental, siempre nos dan algo. Pensemos en las funciones que conocemos
hasta ahora:
Nombre ¿Qué nos da?
nroBolitas(color
Un número
)
puedeMover(dir) Un booleano (V/F)
hayBolitas(color
Un booleano (V/F)
)
A este “algo” que “nos dan” las funciones lo solemos llamar, más formalmente, valor de
retorno, y decimos que una función denota, devuelve o retorna un valor. Si miramos la
tablita también podemos reconocer que estos valores en el universo Gobstones pueden ser
de distintos tipos: números, booleanos y colores (ok, no está en la tabla, pero creanmé que
también se puede).
¡Basta de charla! Empecemos a mejorar el código de Germinar(). Lo primero que vamos
a querer hacer es una función colorSemillas(), para poder poner ahí el color que
elegimos para representarlas.
function colorSemillas() {
return (Rojo)}
Veamos un poco la sintaxis de esto:
 la primera línea es similar a la definición de un procedure, sólo que acá la palabra
clave es function y el nombre empieza con una minúscula (como ya habíamos
visto que pasaba con las expresiones primitivas y los parámetros). Podemos tener
también parámetros en las funciones, de hecho todas las que habíamos visto los
tenían, aunque en este caso no hay ninguno;
 la última línea (y única en este caso) tiene otra palabrita nueva: el return.
Básicamente, eso se lee como “devolvé Rojo” y siempre nuestras funciones tienen
que tener exactamente un return, el cual debe estar en la última línea de la
definición. Entre los paréntesis va aquello que querramos que nuestra función
retorne, que en este caso es simplemente Rojo.
Para ejercitarlo, releimos el enunciado de “El bosque” y propusimos funciones que nos
ayudaran a abstraer aún más el problema. Más o menos entre todos salieron las siguientes:
 cantidadNutrientes()
 cantidadArboles()
 hayNutrientesNecesarios()
De ahora en adelante, ya no vale usar hayBolitas o nroBolitas cuando podamos en su
lugar escribir una función que abstraiga nuestro problema.
Las invitadas ideales
Volviendo a nuestra metáfora de la fiesta de la programación, las funciones tienen otro
aspecto importantísimo en el cual se diferencian de los procedimientos: antes de irse,
limpian todo y lo dejan igual que como lo encontraron (quién pudiera tener invitados
así…).
Pero qué mejor que comprobarlo uno mismo, volvamos por un rato al mundo de las bolitas
y escribamos la función hayBolitasAl(dir, color), que nos indica si hay alguna
bolita del color dado en la celda vecina correspondiente. Importante: el cabezal tiene que
quedar donde empezó.
Antes de largarnos a implementarla, vamos a ver un truquito para poder probarlas, ya que
ahora lo que nos interesa no es mirar el tablero sino el retorno. Como hacíamos antes, se
puede escribir un program, pero esta vez agregándole un return al final.
program {
return (miFuncionLoca()) }

Luego, podemos ver el valor en la pestaña Valores de retorno.


Ahora sí, hagamos la función. Probablemente lo primero que surja es esta solución:
function hayBolitasAl(dir, color) {
Mover(dir)
return (hayBolitas(color)) }

Pero, si el return tiene que ser la última línea entonces ¿cómo hago para volver? El punto
es que no hace falta, porque como dijimos recién las funciones son limpias o puras, en el
sentido de que al terminar deshacen los efectos producidos sobre el tablero.
Repaso de Funciones
Rehicimos el ejercicio de escapando del incendio:

procedure AvanzarUnPaso(){
if(hayIncendioAlEste()){
MoverTipito(Norte)
} else {
MoverTipito(Este)
} }
procedure MoverTipito(dir){
Sacar(Negro)
Mover(dir)
Poner(Negro)
}
function hayIncendioAlEste(){
Mover(Este)
return (hayIncendio())
}
function hayIncendio(){
return (hayBolitas(colorFuego()))
}
function colorFuego(){
return (Rojo) }

Es importante que puedan hacer funciones como:


 hayIncendioAlEste
 hayIncendio ¡no vale usar nroBolitas(Rojo) directamente!
 colorFuego ¡no vale poner Rojo en todos lados!

While (Repetición condicional)


Si ahora queremos escapar por completo del tablero, necesitamos saber el tamaño del
tablero, ¿no?…. ¡NO! Podemos usar un repeat que en vez de tomar un número, toma una
condición.

Entonces, queda:
program {
while(puedoMover(Este)){
AvanzarUnPaso()
}
}
¡Y listo! Eso repite mientras se cumpla que se puede mover al Este. En cuanto deja de
cumplirse… ¡para!.
La estructura del while (que es nuestra repetición condicional), entonces, es así:

Hicimos el ejercicio LimpiarHacia(dir), que limpiaba tooodas las celdas en la


dirección indicada:
La Montaña
Hay una montaña (representada por bolitas azules), cuya ladera tiene sectores verticales. El
escalador (representado por una bolita negra), debe escalar la montaña, y también puede
hacer túneles y encontrar oro.
1. Definir el procedimiento EncontrarSaliente, que hace que hace que el
escalador se mueva hacia el norte siguiendo la montaña (nunca parado en una
casilla de la montaña, sino de costado) hasta encontrarse con una saliente hacia el
Este, y se sube y se frena ahí a descansar. Ejemplo de tablero inicial y final:

(Debe funcionar
para cualquier montaña, por alta que sea)
2. Definir el procedimiento CavarTunel(dir), que cava un túnel (saca bolitas de
montaña) desde donde está parado el escalador, en línea recta y hasta que se acabe
la montaña, que puede ser:
o bien porque salí del otro lado de la montaña
o o bien porque llegué al fin del tablero.
3. Estos van de yapa para que practiquen: Definir la función hayOroAl(dir), que
busca oro (representado por bolitas rojas) en esa dirección, y denota si en esa
“línea” hay oro ó no. No hace falta mover al escalador, se puede sólo mover el
cabezal. Por ejemplo, en el siguiente tablero hayOroAl(Este) denota True, pero

hayOroAl(Sur) denota False.


4. Definir el predicado RecogerOroDeVeta(dir), que recoge todo el oro de una
veta sobre la que está el cabezal. dir me dice si la veta es vertical ú horizontal:
Norte implica que la veta es vertical, y Este que la veta es horizontal. Acá
tampoco hace falta mover al escalador, supongamos que el cabezal es su robot
minero. El escalador se queda donde está. El cabezal debe volver al origen. Por
ejemplo, si hagoRecogerOroDeVeta(Norte) en este tablero:

Obtengo este otro tablero:


Precondición: el cabezal ya está sobre una veta, y el
escalador está en esa misma celda
Soluciones ejs 1 y 2

Distribución de mercadería
1. Fácil
2. Búsqueda - fácil, usar las funciones de 1
3. Búsqueda, hay que usar opuesto, usar las funciones de 1
4. Usar 2 y 3 + un if y una función para ver si hay suficiente
5. Idem 4
6. Combinación de 4 y 5
7. No lo hacemos - necesita recorrer el tablero
8. Función de búsqueda con retorno
9. Combinación del anterior
Unitarios y federales
Vamos a usar el tablero para representar un campo de batalla, donde intervienen dos
ejércitos: los unitarios (representados con bolitas azules) y los federales (representados con
bolitas rojas).
En cada celda puede haber o no combatientes, y de cada uno de ellos nos va a interesar
conocer su rango. Los rangos están representados por la cantidad de bolitas de colores,
respetando la siguiente codificación:
Cant.
Rango
bolitas
1 Soldado raso
2 Teniente
3 Capitán
4 Comandante
Parte 1: inteligencia
Lo primero que vamos a necesitar es una serie de funciones que nos sirvan para “hacer
inteligencia” sobre el campo de batalla.
1. haySoldado() que indica si hay algún soldado en la celda actual.
2. rangoSoldado(colorEjercito) que indica el rango del soldado perteneciente
al ejército dado que hay en la celda actual.
3. haySoldadoHacia(dir) que indica si hay algún soldado en dirección dir.
4. gradoSoldadoMasCercano(dir, colorEjercito) que devuelve el grado del
soldado más cercano en dirección dir, perteneciente al ejército correspondiente.
5. haySoldadoALaVista(dir, colorEjercito) que indica si hay algún soldado
de ese ejército a la vista, o sea: si miramos en línea recta hacia dir lo primero que
vemos es un soldado de ese color.
6. haySuperiorALaVista(dir, colorEjercito) que indica si hay algún
superior a la vista en esa dirección. Para saber si hay un superior, hay que comparar
con el rango del soldado que está en la celda actual (se puede asumir que hay uno).
Si en el trayecto hacia el superior hay algún enemigo, la función debería devolver
False. Ayudín: lo primero que hay que mirar es si hay un soldado de mi bando a
la vista en la dirección requerida.
7. puedeAvanzarHacia(colorEjercito, dirAvance) que indica si un soldado
ubicado en la celda actual podría avanzar en una dirección dada. Para poder
avanzar, es necesario que haya aliados a mis costados: por ejemplo para poder
moverme al Norte tiene que haber un soldado de mi mismo bando hacia el Este y
hacia el Oeste. Ayudín: revisar las funciones del machete que trabajan con
direcciones.
Parte 2: estrategia
En esta segunda parte nos vamos a encargar de mover distintos soldados por el campo de
batalla.
1. MoverSoldado(colorEjercito, dir) que mueva al soldado de la celda actual
en la dirección dada. Ayudín: como no sabemos el rango del soldado, una vez que
nos movamos no sabremos cuántas bolitas había en la posición original. El truco acá
es construir primero otro procedimiento MoverBolitas(color, cantidad,
direccion) y con ese definir el que se pide.
2. AvanzarLoQuePuedaHacia(colorEjercito, dirAvance) que avance al
soldado de la celda actual todo lo que pueda en la dirección dada, teniendo en
cuenta lo ya mencionado sobre los movimientos de los soldados.
3. ReportarseConSuperiorHacia(colorEjercito, dir) asumiendo que hay
un superior en la dirección dada, avanzar hasta quedar al lado de él.
4. ReportarseConSuperior(colorEjercito) asumiendo que hay un superior en
alguna de las cuatro direcciones, avanzar hasta quedar al lado de él.
Cómo encarar un ejercicio con while y funciones
Buenas! El jueves intentamos continuar con el ejercicio que dejó Fede de tarea. Después de
intentar por un rato largo, hicimos un cambio completo, para atacar algo diferente, y no
quedarnos trabados con eso. ¡Es importante eso! Nos ayuda a despejar la cabeza para luego
poder atacar nuevamente el problema. Además… ejem… debíamos seguir con el tema de la
clase…
Pero sé que varios se quedaron con las ganas de saber cómo se hacía. Así que aquí les
traigo una pequeña explicación que espero les ayude:
¿Hay soldado a la vista?
haySoldadoALaVista(dir, colorEjercito) que indica si hay algún soldado de ese
ejército a la vista, o sea: si miramos en línea recta hacia dir lo primero que vemos esun
soldado de ese color.
 ¿Nos piden un programa, una función ó un procedimiento? Una función. Entonces,
lo que tenemos que hacer es denotar algo. (devolver algo). Si hubiera sido un
procedimiento, deberíamos concentrarnos en cambiar el tablero, pero nos pidieron
una función, así que lo que importa es lo que denotamos, porque después de lo que
hagamos, el tablero al final quedará igual.
 ¿Qué tipo denota? Y, dice indica si hay algún soldado… O sea… Verdadero o
Falso! entonces, el tipo de lo que devuelvo es booleano.
 Lo más importante es entender qué es lo que me denota. Ya sabemos el tipo, pero
¿Qué significa haySoldadoALaVista? … Significa imaginarse que estoy parado
mirando hacia adelante, y si “veo” un soldado, entonces es cierto.
 Una vez que sabemos que queremos una función, que tiene de denotar booleano, y
lo que significa, debemos pensar la estrategia. Si quiero “ver si hay lejos”, mi
estrategia puede tener dos pasos: 1- ir. 2- fijarme y devolver.
Ahora sí un poco de código:
function haySoldadoALaVista(dir, colorEjercito){
# paso 1: intentar ir hasta el soldado
# paso 2: devolver si en la celda a la que llegué hay soldado del
colorEjercito.
}

¡Cuidado! ¡Hay que pensar antes de largarse a escribir! Vale usar lápiz y papel para
plantear borradores.
Y recién ahora podemos desglosar esos pasos: ¿Hay algún procedimiento previo que me
sirva para alguno de los dos pasos?
 Para el paso 1: no. Lamentablemente voy a tener que hacerlo.
 Para el paso 2: SSssss casi. Tenemos una función haySoldado(), pero se fija si
hay soldado de cualquier ejército, no del color indicado. También vamos a tener
que hacerlo.
Entonces, una vez que ya sabemos que estamos obligados a codificar porque no tenemos
cosas hechas…
function haySoldadoALaVista(dir, colorEjercito){
while( # no llegué a donde quiero... ){
Mover(dir)
}
return (#si estoy parado en el soldado ó no)
}

Y para saber si estoy ó no parado en el soldado que quiero, puedo inventarme una función
haySoldadoDe(color), que me diga si hay un soldado de ese color, de manera que me
queda todo así:
function haySoldadoALaVista(dir, colorEjercito){
while( puedeMover(dir) && not haySoldadoDe(color) ){
Mover(dir)
}
return (haySoldadoDe(color))
}

function haySoldadoDe(color){
return (hayBolitas(color))
}

La condición del while, puedeMover(dir) && not haySoldadoDe(color), que


parece sacada de la galera, no lo es: significa que mientras pueda moverme y no haya
encontrado lo que quiera, sigo moviéndome. Ese while con esa condición y el Mover
adentro, es el paso 1. Cuando finalmente “llegué”, no sé si llegué porque me choqué con el
final ó porque encontré lo que quiero, por lo que el paso 2 es fijarme cuál de esas dos
situaciones es.
Casos borde
¿Otra vez con ésto? ¡Sí! Hay que pensar siempre en los casos borde. Las preguntas que hay
que hacerse en este caso son:
 ¿Qué pasa si no hay un soldado? Y, por el código que planteamos, llegará al borde
del tablero, el while cortará, y el paso 2 return (haySoldadoDe(color))
retornará falso.
 ¿Qué pasa si en el primer casillero hay un soldado del color que busco? Ah, esto es
interesante: Si en el primer casillero hay un soldado, entonces al preguntar while(
puedeMover(dir) && not haySoldadoDe(color) ) (mientras no haya
soldado) ya no se cumpliría… ¡Porque apenas empecé ya hay soldado de ese color!
Entonces, nunca se mueve, ¡Porque ya encontré mi soldado, está acá mismo!.

Ejemplo:
En ese caso, haySoldadoALaVista(Este, Rojo) ¡Denota True! ¡Pero si no hay al
Este…! Ah, sí que hay: es el soldado sobre el que está parado el cabezal. ¡Nunca entró al
while! Es importante notar este caso borde.
Búsquedas
Éste recorrido se lo conoce normalmente como Búsqueda. Las búsquedas tienen la
siguiente estructura:
while( puedo dar un paso && no encontré ){
dar un paso
}

Se llama búsqueda, porque da pasos hasta encontrar, y cuando encuentra para. Esto me
puede servir después tanto para hacer procedimientos como funciones muy útiles.
¿Hay superior a la vista?
haySuperiorALaVista(dir, colorEjercito) que indica si hay algún superior a la
vista en esa dirección. Para saber si hay un superior, hay que comparar con el
rango del soldado que está en la celda actual (se puede asumir que hay uno). Si en
el trayecto hacia el superior hay algún enemigo, la función debería devolver False.
Bueno, empecemos como con el otro ejercicio:
 ¿Nos piden un programa, una función ó un procedimiento? Una función. Hay que
devolver algo.
 ¿De qué tipo es? Y, el nombre es hay…., así que tengo que denotar True si hay, y
False si no.
 ¿Qué significa lo que me piden? Ah, en este hay que pensar más: Al decir “a la
vista” parece similar al anterior… Pero ¡ojo! que las apariencias engañan. Lo que
quiero saber es, no sólo si hay a la vista un soldado, sino que además su rango debe
ser superior al mío.
 Entonces, ahora podemos plantear una estrategia que, puede describirse igual que
recién hicimos: 1- Fijarme si hay soldado a la vista. 2. Fijarme si su rango es mayor
al mío. ¡y el resultado es un Y lógico entre ambos!

Borrador:
function haySuperiorALaVista(dir, colorEjercito){
return (hay soldado a la vista && su rango es superior al mío)
}

¿Se ve cómo está pensada la función? Acá, si hay que recorrer, se hará ese recorrido en una
función auxiliar. La primera parte (hay soldado a la vista) es del punto anterior, y podemos
reusarlo:
function haySuperiorALaVista(dir, colorEjercito){
return (haySoldadoALaVista(dir,colorEjercito) && su rango es superior
al mío)
}

y la segunda parte , lo podemos resolver haciendo rango de él > rango mío, ¡y para
eso se puede usar otra función que hicimos antes! Estoy hablando de
gradoSoldadoMasCercano (para el rango de él) e inventarnos una función
gradoActual(color) que diga el rango de la celda actual…
Entonces quedaría:
function haySuperiorALaVista(dir, colorEjercito){
return (haySoldadoALaVista(dir,colorEjercito) &&
gradoSoldadoMasCercano(dir,colorEjercito) > gradoActual(colorEjercito))
}
function gradoActual(color){
return (nroBolitas(color))
}
Peeeeeero hay un problema: ¿Recuerdan el caso borde del que hablamos antes? ¡Tanto
haySoldadoALaVista como gradoSoldadoMasCercano tienen el mismo caso inicial!
Esto significa que si ya hay un soldado del color indicado en la celda actual, no van a
buscar otro lejos, se quedan acá.

Ejemplo:

En ese caso, gradoSoldadoMasCercano(Este, Rojo) ¡Denota 2! ¡y yo quería que


denote 4! Ah, el truco es moverse antes de chequear….
Entonces, para no complejizarnos demasiado, vamos a suponer que siempre voy a poderme
mover al menos un paso en la dirección indicada. Y vamos a resolver así nuestro problema:
Como yo quiero saber si hay un soldado más allá de mi casilla actual, y el grado que
quiero tampoco es el de la casilla actual, entonces voy a moverme de la casilla actual para
comenzar a chequear desde la casilla de al lado
La solución final queda:
function haySuperiorALaVista(dir, colorEjercito){
Mover(dir) # Salgo de la casilla actual
return (haySoldadoALaVista(dir,colorEjercito) &&
gradoSoldadoMasCercano(dir,colorEjercito) >
gradoAnterior(dir,colorEjercito))
}
function gradoAnterior(dir,color){
Mover(opuesto(dir)) # Como me moví, tengo que volver a buscar el grado
return (nroBolitas(color))
}

Apuestas
Ahora, pensemos el ejercicio de Apuestas, de la Guía 4 Parte 2.
El procedimiento AgregarApuesta(nroJugador,nroApostado,monto) que agrega
la apuesta indicada en alguna celda vacía. Precondición: hay al menos una celda vacía.
 ¿Programa, función ó procedimiento? Procedimiento. O sea, me piden cambiar
algo.
 No tiene sentido pensar un tipo de retorno, así que pasamos directamente a qué me
piden: El tablero tiene bocha de apuestas, y casillas que están vacías. El objetivo es
poner una nueva apuesta en una de esas vacías. ¡Guarda! El cabezal puede estar en
cualquier lado…
 Y ahora, podemos pensar estrategia: 1- Ir hasta una celda vacía. 2- Poner la
información en la celda encontrada.
procedure AgregarApuesta(nroJugador,nroApostado,monto){
# Paso 1: ir hasta celda vacía
# Paso 2: poner la info
}

Lo cual más o menos quedó así:


Recorrido del tablero
Y ahora tenemos que resolver el problema de buscar una celda vacía. ¡Sabemos hacerlo!
¡Es una búsqueda! Sólo que ahora, cada uno de los pasos cambian, porque debo recorrer
todo el tablero, y no sólo una línea.
Entonces, vamos a mantener la estrategia de la búsqueda, pero vamos a cambiar el
pasito que damos en el while, para que cada pasito sea en una nueva celda del tablero, con
el dibujo que se indica a continuación:

Y ahora que tenemos una idea de cómo realizar esa búsqueda, podemos plantearla así:
Les dejamos acá escrito cómo serían los procedimientos y funciones IrAlOrigen(),
haySiguiente() y IrAlSiguiente(), que les sirven para recorrer el TODO el
tablero de abajo hacia arriba, con la estrategia planteada arriba.
¡A la biblioteca directo!
procedure IrAlOrigen(){
IrAlBorde(Oeste)
IrAlBorde(Sur)
}
procedure IrAlSiguiente(){
if(puedeMover(Este)){
Mover(Este)
} else {
IrAlBorde(Oeste)
Mover(Norte)
} }
function haySiguiente(){
return (puedeMover(Este) || puedeMover(Norte))
}

Tarea
 Ejercicio 7 del dominio de apuestas (estaElJugador(nroJugador))
 Ejercicio 8 del dominio de apuestas
( alguienJugoMasDe(nroApostado,cantMinima))
Metodología Alf para la resolución de problemas
complejos
Nos hacemos las cuatro preguntas:
 ¿Nos piden un programa (raro a esta altura), una función ó un procedimiento?
 En caso de que sea una función, ¿qué tipo denota? Recordemos que los tipos
posibles en Gobstones son: número, color, dirección y booleano.
 ¿Qué tiene que hacer? Ojo acá con los casos borde.
 ¿Qué estrategia vamos a seguir? Vale pensar: ¿se parece a alguno de los esquemas
(búsqueda, recorrido de tablero completo, etc) con los que ya trabajamos?
Seguimos con las apuestas
Ejercicio 2. Respondamos las preguntas:
1. Es un procedimiento.
2. No aplica.
3. Recorrer toda la mesa, haciendo lo que corresponda con cada apuesta.
4. Como el tablero puede estar lleno de apuestas, hay que recorrerlo por completo: eso
ya vimos cómo hacerlo. Pensemos ahora lo que hay que hacer en cada celda:
 Lo primero, ver si efectivamente hay alguna apuesta.
 Si la hay, decidir si ganó o perdió, esto se logra mirando el número apostado.
 Si corresponde, Pagar(): paga 5 veces el monto de la apuesta.
 Si no, Cobrar(): se queda con todo lo apostado.
procedure PagarYCobrar(nroQueSalio) {
IrAlInicio()
while (haySiguiente()) {
if (hayApuesta()) {
ProcesarApuesta(nroQueSalio)
}
IrAlSiguiente()
} }
procedure ProcesarApuesta(nroQueSalio) {
if (esApuestaGanadora(nroQueSalio)) {
Pagar()
} else {
Cobrar()
} }

La necesidad de recordar
Teniendo en cuenta la restricción de el return tiene que estar en la última línea, ¿cómo
hacemos para que una función retorne cosas diferentes? Ejemplos de esto son: ¿de qué
bando hay más soldados? ¿hacía qué dirección hay un superior? ¿qué número es más
grande entre a y b?
Surge así la necesidad de recordar valores en algún lado, para poder usarlos más tarde o
incluso para poder modificarlos (por ejemplo, para contar algo o hacer una suma de muchas
cosas). Básicamente, lo que hacemos es darle un nombre a un valor, para poder utilizarlo
más tarde en otro punto del programa.
Como ejemplo, pensemos SIN EJECUTARLO EN GOBSTONES cuántas bolitas rojas
pone cada uno de estos programas:
program {
numerito := 2
PonerN(numerito, Rojo)
}
program {
numerito := 2
numerito := 5
PonerN(numerito, Rojo)
}
program {
numerito := 2
numerito := numerito + 2
PonerN(numerito, Rojo)
}

A estos nombres, que se escriben con minúscula inicial y son también expresiones, los
llamaremos variables. Algunos tips para tener en cuenta:
 a la acción de darle un valor la conocemos como asignación: asigno el valor 5 a la
variable numerito;
 podemos hacer tantas asignaciones como querramos, cada una sobreescribe (pisa) a
la anterior;
 si intento usar una variable a la cual nunca le asigné un valor: ¡BOOM!
Repaso de variables
Buenas!
Antes que nada, recuerden que les subí el nuevo machete oficial (v1.1) en la sección de
material.
Hoy continuamos con los ejercicios que dejó Fede de la Guía 5:
 Ejercicio 6: nroBolitasAlSiHay(dir,col)
 Ejercicio 7: nroBolitasEnVecinas(col)
 Ejercicio 8: nroBolitasYoYMisVecinos(col)

Varios se equivocaron e intentaron poner && en vez de +. Vimos que esto era porque no
están pensando en qué me piden. Recuerden siempre tenerlo en cuenta. En la bitácora del
jueves pasado, les puse que lo que necesito saber para resolver un ejercicio es:
 Saber si me piden un programa, un procedimiento ó una función.
 Entender qué parámetros entran y, si es una función, el tipo de que retorna.
 Por supuesto, lo importante, entender qué me piden, ó sea, qué significa el
procedimiento ó la función. ¡Hay que tenerlo en la cabeza todo el tiempo!
 Recién después pensar una estrategia, se puede bocetar por arriba con código “de
mentirita”
 Y recién después, tirarse a codificar bien.
Ejercicio adicional de variables:
Además, hicimos este ejercicio adicional:

En azul se ve la solución. La idea era hacer el seguimiento de cómo iban quedando las
variables a medida que el programa avanza.
Más Apuestas
Después, continuamos con la guía 5, que tiene la segunda parte de el ejercicio de Apuestas
de la guía 4. Hicimos hasta el ejercicio 5 inclusive, y para esos últimos dos ejercicios
hicimos una puesta en común.
 Ejercicio 1: cuantosApostaronA(nroApostado)
 Ejercicio 2: cuantaPlataSeApostoA(nroApostado)
 Ejercicio 3: cuantaPlataAposto(nroJugador)
 Ejercicio 4: algunJugadorApostoMasDe(nroApostado,minimo)
 Ejercicio 5: algunJugadorApostoEnTotalMasDe(minimo)

Les transcribo la solución del ejercicio 2, cuantaPlataSeApostoA(nroApostado).

function cuantaPlataSeApostoA(nroApostado){
plata := 0
IrAlOrigen()
while(haySiguiente){
if(hayApuestaA(nro)){
plata := plata + montoApostado()
}
IrAlSiguiente
}
# ¡Caso borde! En la última celda debemos volver a chequear si hay que
sumar el monto...
if(hayApuestaA(nro)){
plata := plata + montoApostado()
}
return (plata)
}
function hayApuestaA(nro){
return (nroApostado() == nro)
}
function nroApostado(){
return (nroBolitas(colorNumero()))
}
function montoApostado(){
return (nroBolitas(colorMonto())) }

Acá es importante notar la estrategia de recorrido completo:


while( puedo dar un paso ){
procesar la celda actual
dar un paso
}
procesar la celda actual

Notar el caso borde al final, necesario como se necesitaba en el repeat.


Les paso la solución de los ejercicios 4 y 5 que hicimos en el pizarrón:
Acá, en estos dos puntos, como justo estaba la estrategia de búsqueda, la refrescamos.
Notar que la estrategia en ambos puntos, 4 y 5, se repite:
while( puedo dar un paso && no encontré ){
dar un paso
}

Esta es una forma muy válida de pensar una estrategia. No siempre van a ser búsquedas,
pero este pseudocódigo me puede ayudar a pensar lo importante sin concentrarme en
detalles.
Enunciados que guiaron la clase
1. Hacer la función doble(numero), que recibe un número y denota el doble del
mismo.
2. Hacer la función max(nro1,nro2), que denota el máximo entre ambos números.
3. Hacer la función dobleDelMaximo(nro1,nro2), que denota el doble del
máximo entre ambos números.
4. Hacer la función quienGano, que denota el color del equipo ganador de un partido.
En un partido juegan dos equipos (hay dos colores) y cada uno mete una cantidad de
goles. Para pensar: ¿Cuántos parámetros debe recibir la función?, pero también,
¿Cuántas cosas necesito?.
5. Hacer la función diferenciaDeGoles, que recibe un partido y denota la
diferencia de goles.
6. Hacer la función jugoEn(colorEquipo,partido), que dice si el equipo
indicado jugó en ese partido.
7. Hacer la función puntosDe(colorEquipo,partido), que dice cuántos puntos
sacó. Recordemos que en un campeonato de fútbol, los puntos en un partido son: si
el equipo ganó, tiene 3 puntos. Si empató tiene 1 punto, y si perdió tiene 0 puntos.
8. Ahora juguemos con un tipo Fecha, que tiene día, mes y año: hacer la función
esPrimerCuatri(fecha), que dice si esa fecha es del primer cuatrimestre.
9. Hacer la función esNavidad(fecha) que dice si esa fecha es el 25 de diciembre.
Repaso de variables y funciones
Bueno, en principio arrancamos con los primeros tres ejercicios.
function doble(numero){
return (2*numero)
}
function max(nro1,nro2){
maximo := nro1
if(nro2 > nro1){
maximo := nro2
}
return (maximo)
}

Ahora bien, al llegar al tercer punto, esta es una solución incorrecta:


function dobleDelMaximo(nro1,nro2){
maximo := nro1
if(nro2 > nro1){
maximo := nro2
}
return (2*maximo)
}

Porque hay que reutilizar las funciones de arriba. Recordemos que si primero quiero hacer
el max, y luego quiero hacer el doble, puedo usar la función max y mandarle el
resultado a la función doble.
Eso se hace así:
Y si yo quisiera saber “el cuadrado del doble del máximo”, eso se hace así:
cuadrado(doble(max(nro1,nro2))). ¿Se entiende cómo se van pasando los valores a
cada función?
Intro a Registros
Ahora nos topamos con el punto 4:
Hacer la función quienGano, que denota el color del equipo ganador de un partido.
En un partido juegan dos equipos (hay dos colores) y cada uno mete una cantidad
de goles. Para pensar: ¿Cuántos parámetros debe recibir la función?, pero también,
¿Cuántas cosas necesito?.
Con lo que sabemos hasta ahora, para poder hacer quienGano necesitamos 4 parámetros:
el color y los goles que metió el equipo 1, y el color y los goles del equipo 2.
Entonces, podríamos por ejemplo hacer estas pruebas en el program:
Y para eso la función queda definida así:

Ahora bien, nos hacemos la pregunta: ¿Dónde está el partido?.


El partido está representado por esos cuatro datos: colorEq1, colorEq2, goles1 y
goles2.
Lo que aprendimos hoy es que los lenguajes de programación tienen siempre una forma de
crear mi propio tipo para hacer que nuestra función reciba sólo una cosa, ó sea, un
partido entero, y no desmembrado.
Un poco de teoría

Se llaman estructuras de datos a los datos que están compuestos por otros datos. En
nuestro caso, los partidos están compuestos por colores y números. Pero podríamos tener
también fechas, que van a estar compuestas por día, mes y año, ó también podríamos tener
calles, que pueden tener altura y sentido.
Para crear nuestro propio tipo Partido (lo vamos a escribir con mayúscula), vamos a
necesitar poner arriba de todo en nuestro archivo lo siguiente:
type Partido is record {
field colorEq1
field colorEq2
field cantGolesEq1
field cantGolesEq2
}

Fíjense que se llaman campos a cada una de las componentes de un registro. Cada
componente tiene un nombre.
Ahora que tenemos eso en nuestro archivo, en nuestro program debo crear el partido. Para
crear el partido, se escribe Partido(....) y ahí en el medio se pone lo que tiene el
partido adentro, separado por comas, y con una notación medio extraña, que es así:
nombreDelCampo <- valor. Eso significa que en ese campo, el registro tendrá ese
valor.
Rápidamente un ejemplo para no confundirnos:
program {
boliviaArgentina := Partido(colorEq1 <- Verde, colorEq2 <- Azul,
cantGolesEq1 <- 6, cantGolesEq2 <- 1)
riverBoca := Partido(colorEq1 <- Verde, colorEq2 <- Azul,
cantGolesEq1 <- 6, cantGolesEq2 <- 1)
}

Ahí hemos creado dos partidos, y los metimos cada uno en una variable distinta. ¡Todo el
partido entra dentro de una variable!
Ahora podemos usarlo para pasarle a quienGano sólo una cosa:
program {
boliviaArgentina := Partido(colorEq1 <- Verde, colorEq2 <- Azul,
cantGolesEq1 <- 6, cantGolesEq2 <- 1)
riverBoca := Partido(colorEq1 <- Verde, colorEq2 <- Azul, cantGolesEq1
<- 6, cantGolesEq2 <- 1)
return(quienGano(boliviaArgentina))
}

Ahora veamos cómo cambia quienGano:


function quienGano(elPartido){
ganador := colorEq1(elPartido)
if(cantGolesEq2(elPartido) > cantGolesEq1(elPartido)){
ganador := colorEq2(elPartido)
}
return (ganador)
}

Notar que la estrategia y el algoritmo son exactamente los mismos que en nuestra primer
versión de quienGano. Pero hay algo diferente:
Antes colorEq1 llegaba por parámetro. Pero ahora ¡Por parámetro llega elPartido!
¿Dónde está colorEq1? -> Está dentro del partido.
Lo que es interesante de saber, es que cuando escribimos type Partido is record
{... se generan automáticamente cuatro funciones que me permiten acceder al
registro:
 La función colorEq1(partido), que saca el color del equipo 1 de adentro del
partido, y me devuelve ese color.
 La función colorEq2(partido), que saca el color del equipo 2 de adentro del
partido, y me devuelve ese color.
 La función cantGolesEq1(partido), que saca el la cantidad de goles del equipo
1 de adentro del partido, y me devuelve ese número.
 La función cantGolesEq2(partido), que saca la cantidad de goles del equipo 2
de adentro del partido, y me devuelve ese número.
¡No hace falta codificarlas, ya me las dan!. Estas funciones se denominan accessors ó
proyectores de un registro. Fíjense que esas funciones tienen el mismo nombre que el
nombre de las componentes.
Entonces, así se explica por qué ahora tengo que poner:
ganador := colorEq1(elPartido)
en lugar de:
ganador := colorEq1.
Eso es porque ¡Tengo que sacar el colorEq1 de adentro del partido! Y usando las funciones
que me dan, puedo hacerlo. Volvé a leer el código de arriba, de la función
quienGano(partido), que vas a ver cómo estamos usando esas cuatro funciones para
acceder a las cosas que están dentro del partido.
Más práctica
Hacer la función diferenciaDeGoles, que recibe un partido y denota la diferencia
de goles.
function diferenciaDeGoles(unPartido){
return (cantGolesEq1(unPartido) - cantGolesEq2(unPartido))
}

Hacer la función jugoEn(colorEquipo,partido), que dice si el equipo indicado


jugó en ese partido.
function jugoEn(colorEquipo,partido){
return (colorEquipo == colorEq1(partido) || colorEquipo ==
colorEq2(partido))
}

Hacer la función puntosDe(colorEquipo,partido), que dice cuántos puntos sacó.


Recordemos que en un campeonato de fútbol, los puntos en un partido son: si el
equipo ganó, tiene 3 puntos. Si empató tiene 1 punto, y si perdió tiene 0 puntos.
function puntosDe(colorEquipo,partido){
puntos := 0
if(gano(colorEquipo,partido)){
puntos := 3
}
if(empato(partido)){
puntos := 1
}
return (puntos)
}

¡Delegamos! en funciones auxiliares. ¡No olvidarse de dividir en subtareas!


function gano(colorEquipo,partido){
return (colorEquipo == quienGano(partido))
}
function empato(partido){
return (diferenciaDeGoles(partido)==0)
}

registros
Parte 1: más sobre registros
Ahora juguemos con un tipo Fecha, que tiene día, mes y año:
type Fecha is record {
field dia
field mes
field anio
}

1. Hacé la función esAniversarioRevolucionDeMayo(fecha) que dice si esa


fecha es el 25 de Mayo.
2. Hacé la función esDiaIndependencia(fecha) que dice si esa fecha es el 9 de
Julio.
3. Hacé la función esPrimerCuatri(fecha), que dice si esa fecha es del primer
cuatrimestre.
4. Codificá esFeriado(fecha), asumiendo que sólo son feriados el Aniversario de
la Revolución de Mayo y el Día de la Independencia.
5. finDeMes(fecha), que indique si nos acercamos al fin del mes (digamos, del 20
en adelante).
6. esDiaDeNioquis(fecha), que mire si el día es 29.
7. mismoAnio(fecha1, fecha2) y mismoMes(fecha1, fecha2).
8. Usando las dos anteriores: esMasAntigua(fecha1, fecha2). Ojo, es un poco
largo, pensá bien la estrategia y todos los casos posibles.
9. cuantosAniosPasaron(fecha1, fecha2). Bonus: contemplar la posibilidad
de que todavía no haya llegado la fecha.
10. primerDiaInvierno(anio) que tome un año y devuelva el primer día de
invierno de ese año.
11. ultimoDiaInvierno(anio) que tome un año y devuelva el último día de
invierno de ese año.
12. esInvierno(fecha) que denote si es un día de invierno en Argentina (21 de
Junio - 20 de Septiembre). Sale fácil con esMasAntigua y las dos anteriores.
13. Siguiendo la misma estrategia de los últimos ejercicios, hacé esVerano(),
esOtonio() y esPrimavera().
14. Usando todo lo anterior, implementá estacion(fecha) que devuelva el color
correspondiente a la estación del año que ocurre en esa fecha: Rojo para el verano,
Negro para el otoño, Azul para el invierno y Verde para la primavera.

Parte 2: registros con registros


Tenemos ahora un Estudiante, modelado con fecha de nacimiento,
DNI, número de materias aprobadas y un campo que nos indica si es
mujer.
type Estudiante is record {
field fechaNacimiento
field dni
field nroMateriasAprobadas
field esMujer
}

1. Asumiendo que existe una función diaDeHoy() que devuelve qué día es hoy,
escribí edad(estudiante), usando cuantosAniosPasaron. Para poder
probarlo, escribí efectivamente la función diaDeHoy() con cualquier fecha que te
quede cómoda para hacer las cuentas (como por ejemplo, el día en el que estés
haciendo estos ejercicios).
2. elMasViejo(estudiante1, estudiante2), que devuelva al estudiante más
viejo.
3. Se lanzó una beca para estimular las vocaciones TIC, destinada a mujeres de entre
18 y 35 años. Codificá puedeRecibirBeca(estudiante) que indique si un
estudiante podría pedir la beca.
4. esIngresante(estudiante), que nos indique si es ingresante: no tiene que
tener materias aprobadas.
5. estaAvanzado(estudiante) que nos indique si un estudiante está avanzado en
la carrera. Esto es así si ya aprobó más de la mitad de las materias, que son 30 en
total.
6. En la búsqueda de auxiliares académicos, nos pidieron encontrar una pareja
pedagógica que cumpla ciertos requisitos: ambos estudiantes avanzados, de la
misma edad y distinto sexo. Programá la función
puedenSerParejaPedagogica(estudiante1, estudiante2) que indique
eso.
7. podriaSerElPadre(estudiante1, estudiante2) que indique si la primera
persona podría ser el padre de la segunda. Digamos que para que esto sea cierto
debe ser al menos 18 años más grande.
8. nacioEnArgentina(estudiante) que nos indique si un estudiante nació en
Argentina. ¿Cómo darse cuenta? Fácil, los ciudadanos extranjeros tienen DNIs con
números mayores a 90.000.000.
9. Desde la Secretaría de Inclusión de la Universidad nos pidieron desarrollar una
función que determine si un estudiante se encuentra dentro del grupo vulnerable,
para poder realizar un seguimiento especial sobre ellos. Escribí la funcion
estaEnGrupoVulnerable(estudiante) teniendo en cuenta las siguientes
reglas (te conviene mucho dividir en subtareas y prestar especial atención a todo lo
definido hasta ahora):
o los migrantes menores de 21 años lo son, por el riesgo de no poder
sustentarse económicamente y tener que volver a sus países;
o las mujeres entre 25 y 35 años también están incluidas, por la posibilidad de
quedar embarazadas y tener que dejar la Universidad;
o todos los ingresantes lo son, porque pueden sentirse abrumados por la
exigencia y verse tentados a abandonar.

Enunciados que guiaron la clase


1. esDiaMasAntiguo(fechaA,fechaB) denota verdadero cuando la fecha A es más
antigua que la fecha B, pero sin mirar el año, sólo mirando el mes y el día.
Ejemplo: Si tengo revolucionDeMayo := Fecha(dia <- 25, mes <- 5,
anio <- 1810) otraFecha := Fecha(dia <- 31, mes <- 1, anio <-
2016) Cuando yo pregunto
esDiaMasAntiguo(otraFecha,revolucionDeMayo) denota True.
2. cuantosAniosPasaron(fecha1, fecha2). Contemplar la posibilidad de que
todavía no haya llegado la fecha. Precondición: fecha2 está después que fecha1.
¡Es el punto 9 del martes pasado! Pero ahora es obligatorio contemplar no haber
llegado a la fecha. Por ejemplo, entre el 25/05/2013 y el 01/05/2016 pasaron 2 años
(el 25/05 van a haber pasado 3).
3. ultimoDiaInvierno(anio) que tome un año y devuelva el último día de
invierno de ese año. ¡Es el punto 11 del martes pasado!.
4. yaPasoMiCumple() denota True si ya pasó mi cumpleaños de este año, y hace uso
de la función diaDeHoy(). Pista: hacer una función que diga cuál es mi cumpleaños
y también usarla.
5. Siguiendo con estudiantes: Hacer la función yo(), que retorne un estudiante, que lo
represente a uds.
6. nuevoIngresante(dni,fechaNac,sexo) recibe los datos de un estudiante y
denota un estudiante completo, con 0 materias aprobadas.
7. ingresanteGemelo(unEstudiante) recibe un estudiante y denota otro
estudiante, su gemelo. El estudiante que devuelve tiene el DNI siguiente, la misma
fecha de nacimiento, 0 materias aprobadas, y el mismo sexo.
8. aprobarMateria(unEstudiante) recibe un estudiante y lo modifica,
agregándole una materia aprobada. O sea, devuelve un estudiante nuevo que es igual
al original, salvo que tiene una materia aprobada más.
9. cambioDeSexo(unEstudiante) recibe un estudiante y lo hace más feliz: el
estudiante descubrió que en realidad es del sexo opuesto y quiere cambiárselo, así
que la función devuelve el estudiante con el sexo cambiado.
10. corregirAnioNacimiento(unEstudiante, nuevoAnio) que denota el
mismo estudiante pero con el anio en el que nació corregido con el nuevoAnio.
11. yaPasoElCumpleDe(unEstudiante) denota verdadero si ya pasó el cumple de
este año del estudiante en cuestión.
Soluciones propuestas puntos 1 al 5
 Punto 1:
function esDiaMasAntiguo(fechaA,fechaB){
return(mes(fechaA) < mes(fechaB) || (mismoMes(fechaA,fechaB) &&
dia(fechaA) <= dia(fechaB)))
}

 Punto 2:
function cuantosAniosPasaron(fecha1, fecha2){
cuantosAnios := anio(fecha2) - anio(fecha1)
if(esDiaMasAntiguo(fecha2,fecha1)){
cuantosAnios := cuantosAnios - 1
}
return (cuantosAnios)
}

 Punto 3:
function ultimoDiaInvierno(elAnio){
return (Fecha(dia <- 20, mes <- 09, anio <- elAnio))
}
Acá es interesante detenerse y notar que estoy armando y devolviendo
una fecha, como si fuera un número.
Teniendo en cuenta que ésto:
cuenta := 5 + 3
return (cuenta)

es lo mismo que esto:


return (5+3)

entonces decir:
laFechaADevolver := Fecha(dia <- 20, mes <- 09, anio <- elAnio)
return (laFechaADevolver)

es lo mismo que:
return (Fecha(dia <- 20, mes <- 09, anio <- elAnio))

 Punto 4:
function yaPasoMiCumple(){
return (esDiaMasAntiguo(miCumple(),diaDeHoy()))
}

function diaDeHoy(){
return (Fecha (dia <- 26, mes <- 5, anio <- 2016))
}

function miCumple(){
return (Fecha (dia <- 13, mes <- 11, anio <- 1986))
}

 Punto 5 (lo hace cada uno, pero puede tener esta forma:)
function yo(){
return (Estudiante(fechaNacimiento <- miCumple(), dni <- 33333333,
nroMateriasAprobadas <- 43, esMujer <- False))
}

 Punto 6:
Acá es importante entender que recibo por parámetro partecitas de un estudiante, y debo
devolver un estudiante entero.
function nuevoIngresante(dni, fechaNac, sexo){
return Estudiante(dni <- dni, fechaNacimiento <- fechaNac, esMujer <-
sexo, nroMateriasAprobadas <- 0)
}
Acá es importante notar que no se puede escribir dia(unEstudiante)
¡Porque el estudiante no tiene dias! Su fechaNacimiento tiene dia.
Acá es importante mirar esta parte:
function nuevoIngresante(dni, fechaNac, sexo){
return Estudiante(dni <- dni, ….
¿Cuál es la diferencia entre esos dos dni? Fácil: recordemos que la sintaxis es:
nombreDelCampo <- valor
Entonces, el que está a la izquierda es el nombre del campo donde estoy queriendo poner
el valor, y el que está a la derecha es el nuevo valor que me viene por parámetro.
Bonus
Una nueva versión de esDiaMasAntiguo, usando la siguiente estrategia: Para saber si el
dia es más antiguo que el otro, puedo cambiar los años de las fechas para que sean iguales,
y luego usar la función esMasAntigua, que recibe dos fechas y me dice cuál es la más
antigua. Ella es la encargada de revisar el día y el mes. ¡Ya lo habíamos hecho la clase
pasada!
/* Versión 2, reeee fumeta BONUS considerando temas que vienen después:
*/
function esDiaMasAntiguo(fechaA,fechaB){
return esMasAntigua(Fecha( dia <- dia(fechaA), mes <- mes(fechaA) ,
anio <- anio(fechaB)) , fechaB),
}

Cambiando el dominio: Compus


type Computadora is record {
field memoria // es una Memoria
field tamanioDisco // es un número
field procesador // es un Procesador
field esNotebook // es un booleano
}

type Procesador is record {


field velocidadNucleo // es un número
field cantNucleos // es un número
field marca // es un color (Rojo: AMD, Azul: Intel, Verde:
ARM)
}

type Memoria is record {


field velocidad // es un número
field tamanio // es un número
}

1. Hacer las funciones colorARM(), colorIntel(), colorAMD() que denoten los


colores correspondientes.
2. Hacer la función notebookGrosa() que denote una computadora que es una
notebook con una RAM de 8Gb y 1200 MHz de velocidad, un disco de 500 Gb y un
procesador AMD de 4 núcleos con 2300 MHz de velocidad.

3. Hacer la función pcTranca() que denote una computadora de


escritorio con una RAM de 4Gb y 800 MHz de velocidad, un disco
de 500 Gb y un procesador Intel de 2 núcleos con 1600 MHz de
velocidad.

4. Hacer la función estaBienArmada(unaCompu) que reciba una computadora y


diga si está bien armada. Esto sucede cuando la velocidad del procesador es la
misma que la velocidad de la memoria. Ojo, las notebooks están siempre bien
armadas, sin importar las velocidades.
5. Hacer la función velocidadReal(unaCompu) que reciba una compu y diga la
velocidad real, que es el mínimo entre las velocidades de la RAM y el procesador.
6. Hacer la función duplicarTamanio(unaMemoria) que reciba una memoria y
cambie el tamanio de la memoria al doble. (debe denotarse la memoria entera).
7. Hacer la función cambiarProcesador(unaCompu,unProcesador) que reciba
una compu y un procesador y cambie el procesador por el indicado. (debe denotarse
la compu).
8. Hacer la función cambiarMemoria(unaCompu,unaMemoria) que reciba una
compu y una Memoria y cambie la memoria entera por la indicada. (debe denotarse
la compu).
9. Hacer la función overclockear(unaCompu) que reciba una compu y aumente la
velocidad de su procesador en 300 MHz. (debe denotarse la compu).
10. Hacer la función quemarMemoria(unaCompu) que reciba una compu y disminuya
a la mitad el tamanio de la memoria (debe denotarse la compu)

Objetivos de la clase
 Introducir la noción de listas, como secuencia ordenada de elementos del mismo
tipo.
 Contar que en Gobstones las listas también son inmutables.
 Mostrar cómo construirlas, con el literal [] y la concatenación ++.
 Mostrar cómo proyectarlas, usando head, tail, last e init.
 Ver cómo recorrer una lista usando while.

Constructores y proyectores
Las tres diferencias entre listas y registros:
 Un tipo de registro tiene una cantidad fija y definida de componentes. [Link]. el tipo
de registro Partido tiene 5 componentes, Fecha tiene 3. Una lista puede tener la
cantidad de elementos que uno quiera: puede haber una lista con 3 números, una
con 5 números y otra con 8 números, y son todas listas de números.
 Cada componente de un registro tiene un nombre, que es el mismo nombre del
proyector correspondiente. Los elementos de una lista no tienen cada uno un
nombre, y por lo tanto no es posible acceder directamente al que yo quiera (ya
veremos que sí podemos programarlo nosotros).
 En un mismo registro puede haber componentes de distinto tipo. [Link]. en un Partido
tengo cuatro números y una Fecha. Todos los elementos de una misma lista tienen
que ser del mismo tipo. Si una lista es de números, tienen que ser todos números.
Puede haber listas de distinto tipo, [Link]. una lista de números, una de direcciones y
otra de registros Partido, lo que no vale es que en la misma lista haya [Link]. un
número y una dirección.
Vimos cómo construirla con [] y cómo proyectarla con head, tail, last e init.
Algunos ejercicios sobre esto:
 segundo(lista) - el head del tail de la lista
 tercero(lista) - el segundo del tail de la lista
 sumaDeLosPrimerosTres(lista) - usando head, segundo y tercero
 losPrimerosTres(lista) - usando head, segundo y tercero
 losExtremosCoinciden(lista) - usando head y last
 extremos(lista) - usando head y last
 anteultimo(lista) - el last del init de la lista
 antepenultimo(lista) - el anteultimo del last de la lista
 losUltimosTres(lista) - usando head, anteultimo y antepenultimo
Otra forma de construir una lista es “pegando” otras dos: [1, 2, 3] ++ [4, 5]
equivale a [1, 2, 3, 4, 5]; cuando hacemos esto decimos que estamos concatenando
dos listas. Ojo que ambas cosas deben ser listas, [1, 4] ++ 5 produce BOOM, lo
correcto es hacer [1, 4] ++ [5].
¡A practicar!
 duplicar(lista) - usando ++
 triplicar(lista) - usando ++
 primeroPalFondo(lista) - mezcla de head, tail y ++
 elUltimoSeraElPrimero(lista) - mezcla de last, init y ++
 multiplicar(lista, cuantasVeces) - usando ++ y repeat
También hablamos de la lista vacía, de la que no se puede proyectar nada, y de cómo saber
si una lista es vacía o no, con isEmpty. Una cosa importante: el tail de una lista de un
elemento es la lista vacía, lo mismo el init.
Recorridos sobre listas
El recorrido es bastante similar al que hacíamos para un tablero, veamos dos ejemplos de
funciones que computan el tamaño:
function tamanioTablero() {
IrAlOrigen()
total := 0
while (haySiguiente()) {
total := total + 1
IrAlSiguiente()
}
return (total + 1)
}
function tamanioLista(lista) {
porRecorrer := lista
total := 0
while (not isEmpty(porRecorrer)) {
total := total + 1
porRecorrer := tail(porRecorrer)
}
return (total)
}
Diferencias importantes:
 necesitamos que la lista venga por parámetro, porque ya no es global como lo era
el tablero;
 como no tenemos un cabezal, hay que recordar por qué parte del recorrido vamos:
para eso usamos una variable que vamos actualizando en cada iteración;
 cuando la lista se termina ya no hay nada más que procesar, no hay caso borde.
En definitiva, la gran diferencia gran es que en este caso el recorrido lo manejamos
nosotros y por eso hace falta usar una variable para saber por dónde vamos (antes esa tarea
la resolvía Gobstones con el cabezal).
Más ejercicios:
 sumatoria(lista) - devuelve la suma de todos los números de la lista;
 elDobleDeCada(lista) - devuelve una lista donde cada elemento es el doble del
elemento de la lista original;
 siguientes(lista) - devuelve una lista con el siguiente de cada número (o sea,
+1);
 opuestos(lista) - devuelve una lista con los opuestos de cada número;
 reverso(lista) - da vuelta la lista, sale recorriendo con tail e init.
Tarea:
 enesimo(lista, posicion) - devuelve el elemeto de la lista que está en la
posición que llegó por parámetro. Por ejemplo: enesimo([3, 8, 13], 2)
devuelve 8, porque es el elemento que está en la posición 2.
 repetidos(lista, cuanto) - devuelve una lista que tiene cada elemento
repetido la cantidad de veces que vino por parámetro. Por ejemplo
repetidos([6, 9, 3], 4) devuelve [6, 6, 6, 6, 9, 9, 9, 9, 3, 3,
3, 3], o sea cada elemento de la lista original repetido 4 veces. Pista: usar
multiplicar.
Recorridos
 Repaso de recolección (ó “mapeo”).
 Filtro.
 Recolección con filtro.
 Búsqueda.
Enunciados de clase:
1. siguientes(direcciones) - devuelve una lista donde cada elemento es el
siguiente del elemento de la lista original. Si le paso una lista [Norte, Este,
Este, Sur], denota la lista [Este, Sur, Sur, Oeste].
2. Pregunta teórica: ¿Puedo pasarle una lista de números al punto anterior?
3. Pregunta teórica: ¿Puedo pasarle una lista de direcciones al punto opuestos de la
clase pasada?
4. fuerzas(colores) - devuelve una lista de números donde cada elemento
representa la fuerza del color de la lista original. La fuerza del Rojo es 17, igual que
la del Negro. La fuerza del Azul es 15, igual que la del Verde. En una lista
[Negro, Rojo, Verde] el resultado es [17, 17, 15].
5. decapitar(listaDeListas) - devuelve una lista con las cabezas de cada
elemento de la lista original. Por ejemplo, decapitar([[1,2,3,4],
[66,77,88],[9,0,9]]) denota la lista [1,66,9].
6. mayoresA(unNumero, numeros) - recibe un número y una lista, y denota una
lista con aquellos números que son mayores al indicado. Por ejemplo, si quiero
saber los mayoresA(5,[16,3,4,56,7,1,8]) denota la lista [16,56,7,8].
7. losLindos(colores) - recibe una lista de colores y denota una lista con los
colores lindos de la lista original. El Azul es un color feo, los demás son lindos. Por
ejemplo, losLindos([Rojo, Rojo, Azul, Verde, Azul]) denota la lista
[Rojo,Rojo,Verde].
8. losPares(nros) - recibe una lista de números, y denota una lista conteniendo
sólo los números pares de la lista original.
9. tripleDeLosMenoresA(numero,nros) - recibe un número y una lista de
números y retorna una lista, cuyos elementos son el triple de cada elemento menor
al indicado. Por ejemplo tripleDeLosMenoresA(6,[3,8,4,7]) denota la lista
[9,12].
10. fuerzaDeLosLindos(colores) - recibe una lista de colores, y denota la fuerza
de cada uno de los colores lindos de la lista original.
11. ¡No todo son recorridos! Hacer la función multiplosDe3Hasta(tope) -
devuelve la lista de los múltiplos de 3 empezando de 0 hasta llegar al tope. Por
ejemplo, multiplosDe3Hasta(14) da la lista [0,3,6,9,12].
 Introdujimos el foreach como una herramienta útil para realizar recorridos
completos sobre listas. Básicamente resuelve por nosotros el problema de recorrer
una lista de izquierda a derecha y en cada iteración podemos “mirar por dónde va”
accediendo a la variable.
 Vimos que los registros pueden tener campos que guardan listas y las listas
pueden estar compuestas por registros. Para ejercitar esto, continuamos con la
práctica de los estudiantes universitarios.
Deben terminar de resolver los primeros cuatro ejercicios de la segunda parte y
enviarlos por mail - incluyan también las funciones que utilicen en su resolución.

Práctica Universidad - listas


Parte 3: registros con listas y listas con registros
Vamos a reemplazar el campo nroMateriasAprobadas por una lista de las notas
obtenidas, y agregamos también otra lista para registrar los aplazos:
type Estudiante is record {
field fechaNacimiento // Fecha
field dni // número
field notasMateriasAprobadas // lista de números
field aplazos // lista de números
field esMujer // booleano
}
1. Escribí funciones que sirvan para calcular la longitud, sumatoria y el
promedio de una lista de números y guardalas en tu Biblioteca. Tenelas muy en
cuenta para programar los siguientes ejercicios.
2. Para que siga funcionando todo lo que ya escribimos hasta ahora, programá la
función nroMateriasAprobadas que indique cuántas materias aprobó un
estudiante. Para pensar, cuando hayas terminado: al modificar la estructura de
nuestro registro, la cantidad de materias aprobadas ya no está explícitamente en
ningún campo pero aún así se puede calcular, reemplazando lo que antes era un
proyector por una función que escribimos nosotros. Lo interesante es que ¡todo
sigue funcionando! - después de todo, los proyectores también son funciones.
3. Para realizar distintos trámites dentro de la Universidad, el Departamento de
Alumnos necesita poder determinar el promedioSinAplazos y el
promedioConAplazos de un estudiante. Programá ambas funciones.
4. El Consejo Interuniversitario Nacional otorga becas de Estímulo a las Vocaciones
Científicas para aquellos estudiantes que deseen iniciar su formación en la
investigación. Como requisitos, piden que quien se presente esté avanzado en la
carrera (ver parte anterior), tenga a lo sumo 30 años y un promedio con aplazos de
al menos seis puntos. Escribí la función aptoBecaEvcCin que determine si un
estudiante podría postularse.
A partir de la lista de todos los estudiantes de TPI, queremos obtener una serie de
estadísticas. Desarrollá una función para cada uno de los siguientes puntos:
1. una lista con los promediosConAplazosDe todos ellos;
2. el promedioHistoricoConAplazos, un número que se calcula sacando el
promedio de los promedios de todos los estudiantes;
3. la lista de estudiantesMujeres que estudian la carrera;
4. el porcentajeDeMujeres que estudian la carrera. Recordá que para calcular un
porcentaje tenés que dividir la porción que te interesa (en este caso las mujeres) con
el total de elementos (en este caso todos los estudiantes) y multiplicar eso por 100.
5. una lista con las edades de todos los estudiantes;
6. una lista con las edadesMigrantesVarones;
7. la lista de los estudiantesAvanzados;
8. la lista de los estudiantesIngresantes;
9. la cantidadEstudiantesEnGrupoVulnerable.
 registros con listas y listas con registros.
 Hicimos varios tipos de búsquedas.
Cambio de dominio:
type Producto is record {
field id // número
field precio // número
field ingredientes // lista de ingredientes
}
type Ingrediente is record {
field tipo // color. Rojo es grasa, Azul es azúcar, Verde es harina.
field gramos // número
field caloriasPorGramo // número
}
program {
producto1 := Producto(id<-1, precio<-15, ingredientes<-[
Ingrediente(tipo<-Azul,gramos<-100,caloriasPorGramo<-2)
])
producto2 := Producto(id<-2, precio<-25, ingredientes<-[
Ingrediente(tipo<-Verde,gramos<-50,caloriasPorGramo<-2),
Ingrediente(tipo<-Rojo,gramos<-50,caloriasPorGramo<-5)
])
producto3 := Producto(id<-3, precio<-10, ingredientes<-[
Ingrediente(tipo<-Verde,gramos<-36,caloriasPorGramo<-1),
Ingrediente(tipo<-Azul,gramos<-24,caloriasPorGramo<-5),
Ingrediente(tipo<-Verde,gramos<-36,caloriasPorGramo<-3)
])
producto4 := Producto(id<-4, precio<-55, ingredientes<-[
Ingrediente(tipo<-Rojo,gramos<-34,caloriasPorGramo<-3),
Ingrediente(tipo<-Rojo,gramos<-34,caloriasPorGramo<-6)
])
losProdus := [producto1, producto2, producto3, producto4]
}
1. Hacer la función costoTotal(productos), que recibe una lista de productos y
denota la suma de todos los precios.
2. Hacer la función encontrarProducto(productos, id) que recibe una lista de
productos y un id de producto y denota el producto (registro entero) que tiene ese
id. Precondición: Hay un y sólo un producto con ese id en la lista
3. Hacer la función ingredienteCalorico(ingredientes) que recibe una lista
de ingredientes y denota el primer ingrediente (registro entero) que tiene más de
100 calorías totales.
4. Hacer la función productoDeMasDe(productos,valor) que recibe la lista de
productos y un valor y denota el primer producto cuyo precio es mayor al valor.
5. Hacer la función cantIngredientesDelProducto(productos, id) que
recibe una lista de productos y un id de producto y denota la cantidad de
ingredientes que tiene.
6. Hacer la función ingredienteConGrasa(producto) que recibe un producto y
denota el primer ingrediente que tiene grasa. Precondición: El producto tiene varios
ingredientes, uno de los cuales tiene grasa
Hicimos todas las funciones menos la 4 y la 6.
Algunas soluciones:
Punto 1:
Aprovechamos para hacer una comparación entre resolverlo con foreach y resolverlo con
while. Algo importante que cambia entre ambas soluciones es lo que está remarcado en
verde: El elemento actual. El elemento actual al recorrer con while, es la cabeza de la lista
recorrido. En cambio, con el foreach ese elemento es la variable que usemos en el foreach.
Importante: Dijimos que se les va a evaluar que usen foreach y while cuando
corresponda.
El truco es:
 Si necesito recorrer por completo la lista, entonces va foreach.
 Si no hace falta recorrer toda la lista, y debo cortar el recorrido,
entonces va while.
Recorrido completo Recorrido con corte
Con foreach Con while
Recolección, filtro, recolección con filtro, Búsquedas, Alguno cumple,
Totalización (contar, acumular) todos cumplen
En la sección de Material están los esquemas de recorrido explicados. ¡A leer!
Punto 2:
Es el primer ejemplo de búsqueda en listas que vemos:

Vimos que podemos hacerlo de forma muy parecida al punto 2:


¡Pero no hay que repetir código! Así que se puede reusar el punto 2:

Tarea - Más sobre Universidad


1. Hacer la función del punto 6 de arriba.
2. Hacer la función estudianteConDni(estudiantes,dni), que dada una lista
de estudiantes y un dni, obtiene el registro entero que representa al estudiante que
tiene ese dni. Precondición: en la lista está el estudiante con ese dni.
3. Hacer la función cantAplazosDe(estudiantes,dni), que, dada una lista de
estudiantes y un dni, obtiene la cantidad de aplazos del estudiante indicado.
Precondición: en la lista está el estudiante con ese dni.
4. Hacer la función dniDelGroso(estudiantes), que dada una lista de
estudiantes, denota el dni del primer estudiante groso. Un estudiante es groso
cuando no tiene aplazos y tiene más de 9 de promedio. Precondición: en la lista hay
al menos un estudiante groso
qué tipo de recorrido utilizar en cada caso:
1. Hacer la función quemarPixeles(colores) que hace que todos los Rojo de la
lista de colores se transformen en Negro. Por ejemplo,
quemarPixeles([Negro,Rojo,Azul,Rojo]) denota la lista
[Negro,Negro,Azul,Negro].
2. Hacer la función quemarPrimerPixel(colores), que hace que sólo el primer
pixel Rojo se queme. Por ejemplo,
quemarPrimerPixel([Negro,Rojo,Azul,Rojo]) denota la lista
[Negro,Negro,Azul,Rojo].
3. Hacer la función sacarPrimeraOcurrencia(lista,elemento) que recibe una
lista y un elemento, y denota el resultado de sacar sólo la primera ocurrencia del
elemento en la lista. Por ejemplo,
sacarPrimeraOcurrencia([Rojo,Azul,Verde,Azul], Azul) denota la lista
[Rojo,Verde,Azul].
4. Hacer la función reemplazarProducto(productos, idSacar,
productoNuevo) que recibe una lista de productos, un id del producto que quiero
sacar, y un producto entero nuevo, y denota la lista en la que sólo cambia el producto
indicado, reemplezándolo por el nuevo. Por ejemplo, si tengo una lista con una barrita
de cereal (id 6), un alfajor (id 7), y un bocadito (id 3) cuando haga
reemplazarProducto(productos, 7, chocolate) entonces voy a obtener
una lista con la barrita de cereal, el chocolate y el bocadito. O sea, obtengo una lista
idéntica a la original pero donde estaba el id 7 sacó el producto alfajor y puso el
chocolate. Precondición: Hay un y sólo un producto con ese id en la lista.
5. Hacer la función hacerLight(producto) que recibe un producto y lo hace light. Ó
sea, denota un producto idéntico al original, pero con su primer ingrediente graso
transformado en harina, y con la mitad de las calorías por gramo.
Por ejemplo, si hago que este producto se haga light:
Producto(id<-5, precio<-55, ingredientes<-[
Ingrediente(tipo<-Azul,gramos<-20,caloriasPorGramo<-5),
Ingrediente(tipo<-Rojo,gramos<-15,caloriasPorGramo<-8),
Ingrediente(tipo<-Rojo,gramos<-20,caloriasPorGramo<-6)
])
obtengo:

Producto(id<-5, precio<-55, ingredientes<-[


Ingrediente(tipo<-Azul,gramos<-20,caloriasPorGramo<-5),
Ingrediente(tipo<-Verde,gramos<-15,caloriasPorGramo<-4),
Ingrediente(tipo<-Rojo,gramos<-20,caloriasPorGramo<-6)
])

Van las soluciones que hicimos en clase:

 Punto 2 quemarPrimerPixel

Recordemos que ... ++ tail(porRec) lo que hace es concatenar a la lista de


quemados el resto de la lista sin recorrer. Se pone el tail porque se desea evitar poner el
Rojo encontrado.
Además, es importante recordar el caso borde, que es considerar que puede no haber
ningún rojo, entonces hay que poner un ìf para que sólo añada el [Negro] cuando
hayamos encontrado algo.
 Punto 3 sacarPrimeraOcurrencia

Acá recuerden mirar también el caso borde.


 Punto 5 hacerLight

Entendamos la estructura primero (qué recibo y qué devuelvo):


Luego comenzamos entendiendo que es una modificación de registro,
donde hay que delegar la modificación de la lista

Luego la modificación de la lista delega en la modificación deun


registro ingrediente
Y finalmente se hace la modificación de un registro ingrediente

Enunciado y program
 Acá el enunciado
 Los puntos que se recomienda hacer en clase son: (Igual en casa practiquen con
todos)
 Punto 2. diasQueAlquilo(videoclub, nroCliente)
 Punto 3. seTeFueLaMano(videoclub, nroCliente)
 Punto 5. cargarActor(videoclub, nroPelicula,nroActor)
 Punto 6. esDocumental(videoclub,nroPelicula)
 Punto 14. cuantoDebe(videoclub,nroCliente)
 Punto 8. pelisPedorras(videoclub)
 Punto 13. puedoAlquilar(videoclub,nroPelicula)
El program:
type Videoclub is record {
field pelis -- [Pelicula]
field alquileres -- [Alquiler]
}
type Pelicula is record {
field nroPelicula -- numero que identifica a la pelicula
field actores -- lista de numeros (cada numero identifica a
un actor)
field duracion -- numero, indica cantidad de minutos
field cantCopias -- numero, indica de cuantas copias es dueño
el videoclub
}
type Alquiler is record {
field nroPelicula -- numero que identifica a la pelicula.
field nroCliente -- numero que identifica al cliente.
field diasAlquiler -- numero que indica cuantos dias se llevo
la peli
}
program {
lasPelis := [
Pelicula( nroPelicula <- 101, actores <- [20,45,57], duracion <- 126,
cantCopias <- 4),
Pelicula( nroPelicula <- 102, actores <- [20], duracion <- 140,
cantCopias <- 2),
Pelicula( nroPelicula <- 103, actores <- [33,57], duracion <- 50,
cantCopias <- 1)
]
losAlquileres := [
Alquiler(nroPelicula <- 101, nroCliente <- 3001, diasAlquiler <- 7),
Alquiler(nroPelicula <- 101, nroCliente <- 3005, diasAlquiler <- 4),
Alquiler(nroPelicula <- 102, nroCliente <- 3001, diasAlquiler <- 8),
Alquiler(nroPelicula <- 102, nroCliente <- 3005, diasAlquiler <- 4)
]
elClub := Videoclub(
pelis <- lasPelis,
alquileres <- losAlquileres
)
return (diasQueAlquilo(elClub, 3001)) }

se les va a pedir:
 Que piensen la estrategia.
 Que deleguen y dividan en subtareas.
 Que no repitan código (y usen las abstracciones existentes).
 Que pongan buenos nombres (que hagan código expresivo).
 ¡Que piensen! ¡Que usen su criterio!
¿Por qué se les va a pedir esto? Porque en su vida profesional ayuda a construir software de
calidad , flexible y robusto .
Bueno, y siempre van a usar ideas como tipo, lista, registro, variable, procedimiento,
función, recorrido, instrucción, alternativa condicional, repetición, filtro, recolección,
búsqueda …. ¡AGH! ¡Es BOCHA lo que saben! Pero fuera de estas cosas, la lista de arriba
es la importante.
Posible solución para el ejercicio 2.11 de Funcional en Mumuki: [Link]
[Link]/exercises/18-funcional-practica-valores-y-funciones-pinos
Raw

[Link]

pesoPino altura = pesoBase altura + pesoCopa altura


pesoBase altura = 3 * enCm (min 3 altura)
pesoCopa altura = 2 * enCm (max 0 (altura - 3))
enCm mtrs = 100 * mtrs
esPesoUtil kg = kg > 400 && kg < 1000
sirvePino = esPesoUtil . pesoPino
Ejercicios Prácticos. Tema 3. Clases y objetos
 Ejercicios

A continuación, se presenta una batería de ejercicios sencillos con el objetivo de


aprender a dominar las estructuras de control if y switch.
1. Escriba un método que reciba dos números enteros (a,b) y devuelva si -a- es mayor que -
b-.
2. Escriba un método que reciba por parámetro dos cadenas y que devuelva si una es igual a
la otra .
3. Escriba un método que reciba tres reales y devuelva el mayor de los tres.
4. Escriba un método que reciba dos reales y devuelva el menor de los dos. ¿qué ocurre si los
dos reales son iguales?
5. Suponga que está escribiendo un programa que se ejecutará en el ordenador de una caja
de una tienda. Tiene que escribir un método que reciba el total de la compra efectuada y
el importe que entrega el cliente. El método mostrará por pantalla "falta importe" cuando
la cantidad entregada sea inferior al total de la compra. "Gracias por su compra" si el
importe entregado es exacto al de la compra. Y, "su cambio es X", donde X es el cambio a
devolver si la cantidad entregada supera al total de la compra.
6. Suponga que se presenta por pantalla un menú de usuario. Con las opciones:
1.- Seleccionar cliente.
2.- Insertar cliente.
3.- Editar cliente.
4.- Borrar cliente.
5.- Salir.
Se pide implementar un método que reciba un caracter correspondiente a la opción
seleccionada por el usuario y que imprima por pantalla una cadena significativa de la
opción que ha seleccionado.
7. Escribir un método que reciba la inicial del día de la semana (L,M,X,J,V,S,D) y devuelva el
nombre completo del día.
8. Escriba un método que en base a una palabra de entrada en inglés permita mostrar su
traducción al castellano. De momento, sólo se podrán traducir los términos: computer,
mouse y keyboard.
9. Escriba un método que calcule la cuantía económica que supone un exceso de velocidad
(valor entero) en una autopista. Las reglas son las siguientes:
- De 0 a 60Kms/h: multa de 300 euros por velocidad por debajo de límites.
- Mayor que 60 Kms/h hasta 120 kms/h: no hay multa.
- Mayor que 120 Kms/h y menor igual que 140 Kms/h, multa de 300 euros.
- Ente 140 y 180, multa de 600 euros.
- Mayor que 180, 1000 euros de multa.
10. Dados dos objetos Figura, donde simplemente, una figura está representada por el
número de lados. Crear un método que reciba dos objetos de la clase Figura y determine si
son iguales. Vamos a suponer que dos figuras son iguales si tienen el mismo número de
lados.

Resultados. Ejercicios
Ejercicio
 Solución:

/**
 * Método que devuelve si un número -a- es mayor que otro -b-
 */
boolean esMayor(int a, int b)
{
 return (a>b);
 /*
  * Setencia equivalente a:
  * if (a>b) return true;
  * else return false;   */
}
 Solución:
/**
 * Método que devuelva si una cadena de caracteres es igual a otra
 */
boolean esIgualCadena(String cadena1, String cadena2)
{
  return ([Link](cadena2));
}

/**
 * Dados tres reales devolver el mayor de los tres.
 */
double mayorDouble(double a, double b, double c)
{
  double mayor = 0;
  if (a>mayor) mayor = a;
  if (b>mayor) mayor = b;
  if (c>mayor) mayor = c;
  return mayor;
}

o Solución:
/**
 * Dados dos reales devolver el menor de los dos
 * ¿Qué pasa si son iguales? -> Devuelve b
 */
double menorDouble(double a, double b)
{
  if (a<b) return a;
  else return b;
}

 Solución:

/**
  * Suponga que está escribiendo un programa para un ordenador de
una caja de   * una tienda.
  * Tiene que escribir un método que reciba el total de la compra
efectuada y   * el importe que entrega el cliente.
  * El método mostrará por pantalla "falta importe" cuando la
cantidad   
  * entregada sea inferior al total de la compra.
  * "gracias por su compra" Si el importe entregado es exacto al de
la compra.   * Y, "su cambio es X", donde X es el
  * cambio a devolver si la cantidad entregada supera al total de
la compra.
*/
void cambioCaja(double total, double entregado)
{
  if (total == entregado)
   [Link]("Gracias por su compra.");
  else if (total > entregado)
   [Link]("Falta importe.");
  else
   [Link]("Su cambio es: " + [Link](entregado
- total));
}
o Solución:

/**
  * Suponga que se presenta por pantalla un menú de usuario.
Con las opciones:
  * 1.- Seleccionar cliente.
  * 2.- Insertar cliente.
  * 3.- Editar cliente.
  * 4.- Borrar cliente.
  * 5.- Salir.
  * Se pide implementar un método que reciba un caracter
correspondiente a la opción   * seleccionada
  * por el usuario y que imprima por pantalla una cadena
significativa de la opción   *que ha seleccionado.
*/
void opcionMenu(char opcion)
{
  switch (opcion)
  {
    case '1':
      [Link]("Seleccionar cliente.");
      break;
    case '2':
      [Link]("Insertar cliente.");
      break;
    case '3':
      [Link]("Editar cliente.");
      break;
    case '4':
      [Link]("Borrar cliente.");
      break;
    case '5':
      [Link]("Salir cliente.");
      break;
    default:
      [Link]("Opcion no reconocida");
  }
}
.
 Solución:
/**
  * traductor de días de la semana.
  * Escribir un método que reciba la inicial del día de la semana y
devuelva   * el nombre completo del día.
*/
void diaSemana(char dia)
{
  switch (dia)
  {
    case 'L':
      [Link]("Lunes");
      break;
    case 'l':
      [Link]("Lunes");
      break;
    case 'M':
      [Link]("Martes");
      break;
    case 'm':
      [Link]("Martes");
      break;
    case 'X':
      [Link]("Miercoles");
      break;
    case 'x':
      [Link]("Miercoles");
      break;
    case 'J':
      [Link]("Jueves");
      break;
    case 'j':
      [Link]("Jueves");
      break;
    case 'V':
      [Link]("Viernes");
      break;
    case 'v':
      [Link]("Viernes");
      break;
    case 'S':
      [Link]("Sabado");
      break;
    case 's':
      [Link]("Sabado");
      break;
    case 'D':
      [Link]("Domingo");
      break;
    case 'd':
      [Link]("Domingo");
      break;
    default:
      [Link]("Dia incorrecto");
    }
}
  Ejercicio 8.

 Solución:

/**
  * Escriba un método que en base a una palabra de entrada en inglés   
  * permita mostrar
  * su traducción al castellano. De momento, sólo se podrán traducir los
* términos:
  * computer, mouse y keyboard
*/
void traductor(String termino)
{
  if ([Link]("computer"))
    [Link]("ordenador");
  else if ([Link]("mouse"))
    [Link]("raton");
  else if ([Link]("keyboard"))
    [Link]("teclado");
  else
    [Link]("Termino no reconocido.");

  // ¿Se podría utilizar un switch?


}

  Ejercicio 9.

 Solución:

 
/**
* Escriba un método que calcule la cuantía económica que supone un exceso
de
* velocidad en una autopista. Las reglas son las siguientes:
* - De 0 a 60Kms/h: multa de 300 euros por velocidad por debajo de
límites.
* - Mayor que 60 Kms/h hasta 120 kms/h: no hay multa.
* - Mayor que 120 Kms/h y menor igual que 140 Kms/h, multa de 300 euros.
* - Ente 140 y 180, multa de 600 euros.
* - Mayor que 180, 1000 euros de multa.
* Nota: Estos valores son inventados.
*/
void calculoMulta(int velocidad)
{
  if ((velocidad > 0) && (velocidad <=60))
    [Link]("300 euros por velocidad bajo límites");
  else if ((velocidad>60) && (velocidad<= 120))
    [Link]("Sin multa");
  else if ((velocidad>120) && (velocidad<=140))
    [Link]("300 euros por exceso de velocidad");
  else if ((velocidad>140) && (velocidad<=180))
    [Link]("600 euros por exceso de velocidad");
  else
    [Link]("1000 euros por exceso de velocidad");
}
  Ejercicio 10
 Solución:

 class Figura
{
  private int numLados;

  /**
   * Constructor de la clase.
   */
  Figura (int numLados)
  {
    [Link] = numLados;
  }

  boolean equals(Figura f)
  {
   if ([Link] == [Link])
     return true;
   else
     return false;
   // Más elegante escribir; return ([Link] = [Link]);
  }
} // class Figura

/**
  * Dados dos objetos Figura, donde simplemente, una figura está
  * representada por el número de lados. Crear un método que reciba dos
  * objetos de la clase Figura y determine si son iguales.
  */
boolean figurasIguales(Figura figura1, Figura figura2)
{
  return ([Link](figura2));
}
Introducción a JavaScript

3.1. Variables
Las variables en los lenguajes de programación siguen una lógica similar a las
variables utilizadas en otros ámbitos como las matemáticas. Una variable es un
elemento que se emplea para almacenar y hacer referencia a otro valor. Gracias a
las variables es posible crear "programas genéricos", es decir, programas que
funcionan siempre igual independientemente de los valores concretos utilizados.
De la misma forma que si en Matemáticas no existieran las variables no se podrían
definir las ecuaciones y fórmulas, en programación no se podrían hacer programas
realmente útiles sin las variables.
Si no existieran variables, un programa que suma dos números podría escribirse
como:
resultado = 3 + 1

El programa anterior es tan poco útil que sólo sirve para el caso en el que el primer
número de la suma sea el 3 y el segundo número sea el 1. En cualquier otro caso, el
programa obtiene un resultado incorrecto.
Sin embargo, el programa se puede rehacer de la siguiente manera utilizando
variables para almacenar y referirse a cada número:
numero_1 = 3
numero_2 = 1
resultado = numero_1 + numero_2

Los elementos numero_1 y numero_2 son variables que almacenan los valores que
utiliza el programa. El resultado se calcula siempre en función del valor almacenado
por las variables, por lo que este programa funciona correctamente para cualquier
par de números indicado. Si se modifica el valor de las variables numero_1 y
numero_2, el programa sigue funcionando correctamente.
Las variables en JavaScript se crean mediante la palabra reservada var. De esta
forma, el ejemplo anterior se puede realizar en JavaScript de la siguiente manera:
var numero_1 = 3;
var numero_2 = 1;
var resultado = numero_1 + numero_2;

La palabra reservada var solamente se debe indicar al definir por primera vez la
variable, lo que se denomina declarar una variable. Cuando se utilizan las variables
en el resto de instrucciones del script, solamente es necesario indicar su nombre.
En otras palabras, en el ejemplo anterior sería un error indicar lo siguiente:
var numero_1 = 3;
var numero_2 = 1;
var resultado = var numero_1 + var numero_2;

Si cuando se declara una variable se le asigna también un valor, se dice que la


variable ha sido inicializada. En JavaScript no es obligatorio inicializar las variables,
ya que se pueden declarar por una parte y asignarles un valor posteriormente. Por
tanto, el ejemplo anterior se puede rehacer de la siguiente manera:
var numero_1;
var numero_2;
numero_1 = 3;
numero_2 = 1;
var resultado = numero_1 + numero_2;

Una de las características más sorprendentes de JavaSript para los programadores


habituados a otros lenguajes de programación es que tampoco es necesario
declarar las variables. En otras palabras, se pueden utilizar variables que no se han
definido anteriormente mediante la palabra reservada var. El ejemplo anterior
también es correcto en JavaScript de la siguiente forma:

var numero_1 = 3;
var numero_2 = 1;
resultado = numero_1 + numero_2;

La variable resultado no está declarada, por lo que JavaScript crea una variable
global (más adelante se verán las diferencias entre variables locales y globales) y le
asigna el valor correspondiente. De la misma forma, también sería correcto el
siguiente código:
numero_1 = 3;
numero_2 = 1;
resultado = numero_1 + numero_2;

En cualquier caso, se recomienda declarar todas las variables que se vayan a


utilizar.
El nombre de una variable también se conoce como identificador y debe cumplir
las siguientes normas:
 Sólo puede estar formado por letras, números y los símbolos $ (dólar) y _ (guión
bajo).
 El primer carácter no puede ser un número.
Por tanto, las siguientes variables tienen nombres correctos:
var $numero1;
var _$letra;
var $$$otroNumero;
var $_a__$4;

Sin embargo, las siguientes variables tienen identificadores incorrectos:

var 1numero; // Empieza por un número


var numero;1_123; // Contiene un carácter ";"
3.2. Tipos de variables
Aunque todas las variables de JavaScript se crean de la misma forma (mediante la
palabra reservada var), la forma en la que se les asigna un valor depende del tipo
de valor que se quiere almacenar (números, textos, etc.)
3.2.1. Numéricas
Se utilizan para almacenar valores numéricos enteros (llamados integer en inglés) o
decimales (llamados float en inglés). En este caso, el valor se asigna indicando
directamente el número entero o decimal. Los números decimales utilizan el
carácter . (punto) en vez de , (coma) para separar la parte entera y la parte
decimal:
var iva = 16; // variable tipo entero
var total = 234.65; // variable tipo decimal

3.2.2. Cadenas de texto


Se utilizan para almacenar caracteres, palabras y/o frases de texto. Para asignar el
valor a la variable, se encierra el valor entre comillas dobles o simples, para
delimitar su comienzo y su final:
var mensaje = "Bienvenido a nuestro sitio web";
var nombreProducto = 'Producto ABC';
var letraSeleccionada = 'c';

En ocasiones, el texto que se almacena en las variables no es tan sencillo. Si por


ejemplo el propio texto contiene comillas simples o dobles, la estrategia que se
sigue es la de encerrar el texto con las comillas (simples o dobles) que no utilice el
texto:
/* El contenido de texto1 tiene comillas simples, por lo que
se encierra con comillas dobles */
var texto1 = "Una frase con 'comillas simples' dentro";

/* El contenido de texto2 tiene comillas dobles, por lo que


se encierra con comillas simples */
var texto2 = 'Una frase con "comillas dobles" dentro';

No obstante, a veces las cadenas de texto contienen tanto comillas simples como
dobles. Además, existen otros caracteres que son difíciles de incluir en una variable
de texto (tabulador, ENTER, etc.) Para resolver estos problemas, JavaScript define un
mecanismo para incluir de forma sencilla caracteres especiales y problemáticos
dentro de una cadena de texto.
El mecanismo consiste en sustituir el carácter problemático por una combinación
simple de caracteres. A continuación se muestra la tabla de conversión que se debe
utilizar:
Si se quiere incluir... Se debe incluir...

Una nueva línea \n

Un tabulador \t

Una comilla simple \'

Una comilla doble \"

Una barra inclinada \\

De esta forma, el ejemplo anterior que contenía comillas simples y dobles dentro
del texto se puede rehacer de la siguiente forma:
var texto1 = 'Una frase con \'comillas simples\' dentro';

var texto2 = "Una frase con \"comillas dobles\" dentro";

Este mecanismo de JavaScript se denomina "mecanismo de escape" de los


caracteres problemáticos, y es habitual referirse a que los caracteres han sido
"escapados".
Ejercicio 2
Modificar el primer script del capítulo anterior para que:
1. El mensaje que se muestra al usuario se almacene en una variable llamada mensaje
y el funcionamiento del script sea el mismo.
2. El mensaje mostrado sea el de la siguiente imagen:
Figura 3.1 Nuevo mensaje que debe mostrar el script

11.2. Ejercicio 2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[Link]
<html xmlns="[Link]
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Ejercicio 2 - Mostrar mensajes complejos</title>
<script type="text/javascript">
var mensaje = "Hola Mundo! \n Qué facil es incluir \'comillas simples\' \n
y \"comillas dobles\" ";
alert(mensaje);
</script>
</head>
<body>
<p>Esta página muestra un mensaje complejo</p>
</body>
</html>
 

También podría gustarte