Pac-Man

Pac-Man

¿Qué queremos hacer?

Nos gustaría programar un juego cuyo escenario es un mapa en el que
intervienen distintos tipos de elementos: paredes, un Pac-Man, fantasmas,
y pastillas comestibles. El jugador controla al Pac-Man, y los fantasmas
se mueven de acuerdo con distintos criterios.

Vamos a hacer varias simplificaciones para poder trabajar con el juego en clase:

  1. Todas las posiciones en los extremos del mapa tienen paredes, de tal manera que los personajes no pueden caerse fuera del mapa.
  2. El Pac-Man comienza ubicado sobre la coordenada (1, 1), que no tiene paredes.
  3. Todas las pastillas son del mismo tipo.
  4. Cuando el Pac-Man entra en contacto con una pastilla, la pastilla desaparece y el jugador gana un punto.
  5. Cuando el Pac-Man entra en contacto con un fantasma, el jugador pierde una vida y el Pac-Man se reubica sobre la coordenada (1, 1).
  6. No nos vamos a preocupar por lo que pasa cuando el jugador llega a tener 0 vidas (“pierde”) o llega a comer todas las pastillas (“gana”).

¿Cómo podríamos programar un Pac-Man en Gobstones?

Siempre que programamos, lo que hacemos es representar la realidad usando datos: números, booleanos, listas, registros, etc. Es prácticamente imposible representar toda la realidad; lo que hacemos es representar los aspectos y las partes de la realidad que nos interesan en un contexto determinado. Una vez que elegimos una manera de representar la parte de la realidad que nos interesa, podemos resolver problemas de la realidad trabajando con los datos que la representan.

Notemos que la representación de la realidad usando datos, y la interpretación de los datos para entenderlos como parte de la realidad, son tareas exclusivamente humanas, que quedan fuera del alcance de lo que puede hacer una computadora. Los programas, a lo sumo, pueden servir para convertir una representación en otra.

También puede ser interesante notar que los dibujitos de las manzanas no son las manzanas de la realidad. Son a su vez una representación de la realidad.

Esto no es una manzana

Ejercicio 1

¿Cuál es la parte de la realidad que queremos representar en el caso de nuestro juego de Pac-Man? ¿Cómo podemos representarla usando números, booleanos, listas y registros?

Vamos a discutir cómo podríamos definir un registro Juego que sirva para representar los aspectos de un juego de Pac-Man que nos interesan.

  • No hay una sola manera de representar un juego de Pac-Man. ¿Se les ocurren otras maneras?
  • Algunas maneras de representar un juego de Pac-Man pueden ser más convenientes que otras. Vamos a comparar las representaciones que propusimos.
  • ¿Cuál es el invariante que debe cumplir un registro del tipo Juego para representar efectivamente un juego de Pac-Man?
  • ¿Cómo se podría modificar la representación para que haya otros tipos de pastillas?

Ejercicio 2

El siguiente tipo sirve para representar la configuración de colores con la que se dibujan los elementos del juego en la pantalla:

type ConfigColores is record {
    field colorPacman // color con que se dibuja el Pac-Man
    field colorFantasma // color con que se dibujan los fantasmas
    field colorPastilla // color con que se dibujan las pastillas
    field colorPared // color con que se dibujan las paredes
}

Programar el procedimiento RenderJuego(juego, config) que recibe
un juego de Pac-Man y una configuración de colores, y dibuja el juego en el tablero de Gobstones, usando los colores indicados en la configuración.

Ejercicio 3

En Introducción a la Programación no estudiamos cómo
hacer programas que puedan interactuar con el usuario por medio del teclado.
Esto es porque el usuario y el teclado pertenecen a la realidad, pero
la programación no se basa en manejar la realidad, sino fundamentalmente en manejar datos que representan la realidad.

Programar la función moverPacman(juego, tecla) que recibe
un juego de Pac-Man y una dirección, que representa la tecla presionada por el jugador, y denota el juego de Pac-Man que resultaría de mover el Pac-Man hacia esa dirección. Observaciones:

  1. Si hay una pared, el Pac-Man debe quedar donde estaba.
  2. Si hay una pastilla, el Pac-Man debe comerla y ganar un punto.
  3. Si hay un fantasma, el Pac-Man debe volver a la coordenada (1, 1) y perder una vida.

Ejercicio 4 (abierto)

Programar la función moverFantasmas(juego) que recibe un juego de Pac-Man y denota el juego de Pac-Man que resultaría de mover los fantasmas, usando algún criterio para moverlos. Si alguno de los fantasmas entra en contacto con el Pac-Man, el Pac-Man debe volver a la coordenada (1, 1) y perder una vida.

En el juego original de Pac-Man, cada fantasma tiene su propia personalidad. Por ejemplo, el fantasma rojo persigue al Pac-Man, mientras que el fantasma rosa trata de ubicarse en el lugar hacia donde el Pac-Man está yendo.

Un criterio sencillo (que no daría lugar a un juego muy divertido) podría ser que cada fantasma se mueva hacia la primera dirección (N, E, S, O) hacia donde no haya una pared. Un criterio un poco más interesante sería que cada fantasma se mueva
hacia la dirección que más lo acerque a la coordenada donde el Pac-Man se encuentra actualmente.

Publicado en Uncategorized | Deja un comentario

Administrador de dependencias

Introducción

Los paquetes de software suelen tener dependencias. Una dependencia es un segundo paquete que provee un conjunto de funcionalidades necesarias para que el primer paquete funcione. Por ejemplo, el paquete PyGobstones tiene dos dependencias: el paquete Python y el paquete PyQt4.

En general, un paquete puede tener varias dependencias. Cada dependencia a su vez puede tener dependencias, y así sucesivamente. Vamos a suponer que no puede haber dependencias circulares, es decir que si A depende de B, B no puede depender de A.

Existen herramientas, conocidas como administradores de paquetes, que facilitan el proceso de instalación encargándose de descargar e instalar todas las dependencias de un paquete antes de instalar el paquete.

En este ejercicio nos interesa programar el mecanismo básico detrás de un administrador de paquetes.

Representación de los datos

La herramienta cuenta con una base de datos que indica cuáles son todos los paquetes disponibles para descargar e instalar, y cuáles son las dependencias de cada paquete. Cada paquete puede estar ya instalado, o aún no instalado.

La información asociada a cada paquete se guarda en una fila. En la primera celda de la fila hay un número positivo de bolitas azules que indica el nombre del paquete. La presencia de una bolita roja en dicha celda indica si el paquete ya se encuentra instalado en el sistema. La cantidad de bolitas negras en esa celda indica el tamaño del archivo que se debe descargar para poder instalar ese paquete. Las demás celdas de la fila indican, con un número de bolitas verdes, los nombres de todos los paquetes de los que depende.

En el ejemplo siguiente, la base de datos contiene información sobre cuatro paquetes. El paquete #5 tiene tamaño 1 y depende de los paquetes #3 y #4. El paquete #3 tiene tamaño 8, no tiene ninguna dependencia, y ya se ecuentra instalado en el sistema. El paquete #4 tiene tamño 2 y depende de los paquetes #3 y #7. Por último, el paquete #7 tiene tamamño 9 y no tiene ninguna dependencia.

05_dependencias_tablero_1
GBB/1.0
size 4 5
head 0 0
cell 0 4 Azul 5 Negro 1
cell 1 4 Verde 3
cell 2 4 Verde 4
cell 0 3 Azul 3 Negro 8 Rojo 1
cell 0 2 Azul 4 Negro 2
cell 1 2 Verde 3
cell 2 2 Verde 7
cell 0 1 Azul 7 Negro 9
%%

Asumiremos que la base de datos está armada correctamente, es decir que los paquetes se definen una sola vez (no hay dos filas asociadas a un mismo paquete), no hay dependencias circulares, y todas las dependencias de un paquete representan algún paquete que también está definido en la base de datos. Además, supondremos que si un paquete está instalado, todas sus dependencias tambien están instaladas.

Ejercicio 1

Definir el procedimiento UbicarPaquete(nombrePaquete). Propósito: ubica el cabezal sobre la fila asociada al paquete cuyo nombre es nombrePaquete. Precondición: debe haber una fila asociada a dicho paquete. (Notar que nombrePaquete debe ser un número positivo). Ejemplo: UbicarPaquete(4). Resultado:

05_dependencias_tablero_2
GBB/1.0
size 4 5
head 0 2
cell 0 4 Azul 5 Negro 1
cell 1 4 Verde 3
cell 2 4 Verde 4
cell 0 3 Azul 3 Negro 8 Rojo 1
cell 0 2 Azul 4 Negro 2
cell 1 2 Verde 3
cell 2 2 Verde 7
cell 0 1 Azul 7 Negro 9
%%

Ejercicio 2

Definir la función estaInstalado(nombrePaquete). Propósito: denota verdadero si el paquete indicado se encuentra instalado en el sistema. Precondición: el paquete debe estar registrado en la base de datos. Ejemplo: estaInstalado(7) ~~> False, estaInstalado(3) ~~> True.

Ejercicio 3

Diremos que un paquete es instalable si no está instalado pero todas sus dependencias directas están instaladas. Definir la función esInstalable(nombrePaquete). Propósito: denota verdadero si el paquete indicado es instalable. Pregunta: ¿Cuál es la precondición? Ejemplo: esInstalable(7) ~~> True, esInstalable(2) ~~> False.

Ejercicio 4

Definir el procedimiento UbicarProximoPaqueteParaInstalar(nombrePaquete). Propósito: ubica el cabezal sobre la fila correspondiente a alguna dependencia instalable (directa o indirecta) del paquete indicado. Precondición: el paquete indicado debe existir en la base de datos y debe tener alguna dependencia instalable.

Ejemplo: UbicarProximoPaqueteParaInstalar(5) debe ubicar el cabezal en la fila sobre el próximo paquete se se debería instalar para llevar a cabo la instalación del paquete #5. Para ello notar que el paquete #4 depende de los paquetes #3 y #4. El paquete #3 ya está instalado, por lo que no es necesario instalarlo. El paquete #4 no está instalado y tiene dos dependencias: los paquetes #3 y #7. El paquete #3 ya está instalado, por lo que no es necesario instalarlo. El paquete #7 no está instalado aún, por lo que el resultado final debe ser:

05_dependencias_tablero_3
GBB/1.0
size 4 5
head 0 1
cell 0 4 Azul 5 Negro 1
cell 1 4 Verde 3
cell 2 4 Verde 4
cell 0 3 Azul 3 Negro 8 Rojo 1
cell 0 2 Azul 4 Negro 2
cell 1 2 Verde 3
cell 2 2 Verde 7
cell 0 1 Azul 7 Negro 9
%%

Nota: si todas las dependencias del paquete que se recibe como parámetro ya están instaladas, este es el próximo paquete a instalar.

Ejercicio 5

Definir el procedimiento Instalar(nombrePaquete). Propósito: instala el paquete indicado, y todas sus dependencias que no estén instaladas. Pregunta: ¿cuál es la precondición? Ejemplo: Instalar(4). Resultado:

05_dependencias_tablero_4
GBB/1.0
size 4 5
head 0 2
cell 0 4 Azul 5 Negro 1
cell 1 4 Verde 3
cell 2 4 Verde 4
cell 0 3 Azul 3 Negro 8 Rojo 1
cell 0 2 Azul 4 Negro 2 Rojo 1
cell 1 2 Verde 3
cell 2 2 Verde 7
cell 0 1 Azul 7 Negro 9 Rojo 1
%%

Ejercicio 6

Definir la función tamanyoDescargaParaInstalar(nombrePaquete). Propósito: denota el tamaño total de los paquetes que se deben descargar para instalar el paquete indicado. No se debe contemplar el tamaño de los paquetes ya instalados. Precondición: el paquete indicado debe existir en la base de datos. Ejemplo: tamanyoDescargaParaInstalar(5) ~~> 12. El 12 resulta de 9 (paquete #7) + 2 (paquete #4) + 1 (paquete #5).

 

Solución a los ejercicios 1, 2 y 3


/* Ejercicio 1 */

procedure UbicarPaquete(nombrePaquete)
// Propósito: ubica el cabezal sobre la fila asociada al
// paquete cuyo nombre es nombrePaquete.
// Precondición: debe haber una fila asociada a dicho paquete.
{
    IrAlOrigen()
    while (nombrePaqueteActual() /= nombrePaquete) {
        Mover(Norte)
    }
}

function nombrePaqueteActual()
// Propósito: denota el nombre del paquete actual.
{
    return (nroBolitas(Azul))
}

procedure IrAlOrigen()
// Procedure: ubica el cabezal sobre el extremo sudoeste
// del tablero.
{
    IrAlBorde(Sur)
    IrAlBorde(Oeste)
}

/* Ejercicio 2 */

function estaInstalado(nombrePaquete)
// Propósito: denota verdadero si el paquete indicado se encuentra
// instalado en el sistema.
// Precondición: el paquete debe estar registrado en la base de datos.
{
    UbicarPaquete(nombrePaquete)
    return (paqueteActualEstaInstalado())
}

function paqueteActualEstaInstalado()
// Propósito: denota verdadero si el paquete de la celda actual
// se encuentra instalado.
{
    return (hayBolitas(Rojo))
}

/* Ejercicio 3 */

function esInstalable(nombrePaquete)
// Propósito: denota verdadero si el paquete indicado es instalable,
// es decir, si no está instalado pero todas sus dependencias directas
// están instaladas.
// Precondición: el paquete debe estar registrado en la base de datos,
// y todas sus dependencias deben ser paquetes registrados en la base
// de datos.
{
    return (not estaInstalado(nombrePaquete) &&
            todasLasDependenciasInstaladas(nombrePaquete))
}

function dependenciaActual()
// Propósito: denota el nombre de la dependencia sobre la que
// se encuentra ubicado el cabezal.
// Precondición: debe haber una dependencia en la celda actual.
{
    return (nroBolitas(Verde))
}

function hayDependencia()
// Propósito: denota verdadero si hay una dependencia en
// la celda actual.
{
    return (hayBolitas(Verde))
}

function hayDependenciaAl(dir)
// Propósito: denota verdadero si hay una dependencia hacia
// la dirección dir.
// Precondición: debe poder moverse hacia la dirección dir.
{
    Mover(dir)
    return (hayDependencia())
}

function todasLasDependenciasInstaladas(nombrePaquete)
// Propósito: denota verdadero si todas las dependencias directas del
// paquete indicado están instaladas.
// Precondición: todas las dependencias del paquete deben ser paquetes
// registrados en la base de datos.
{
    todasInstaladas := True
    UbicarPaquete(nombrePaquete)
    while (puedeMover(Este) && hayDependenciaAl(Este)) {
        Mover(Este)
        todasInstaladas := todasInstaladas &&
                           estaInstalado(dependenciaActual()) 
    }
    return (todasInstaladas)
}

/* Programa */

program {
    return (esInstalable(7))
}
Publicado en Uncategorized | Deja un comentario

Funciones y alternativa condicional

El banco Sant&&else desea computarizar su anticuado sistema basado en conteo de porotos.

A ese efecto, el tablero de Gobstones se utilizará para representar cuentas corrientes. Una fila del tablero representa la historia de una cuenta. La celda ubicada en la columna 0 contiene una cierta cantidad de bolitas negras, indicando la cantidad total de transacciones (depósitos o extracciones) que se hicieron en esa cuenta. La cantidad de bolitas azules en la celda 0 indican quién es el titular de la cuenta.

Las celdas ubicadas en cada una de las columnas de 1 a N representan un depósito o una extracción. Una cierta cantidad de bolitas verdes representa el depósito de esa cantidad de centavos. Análogamente, una cierta cantidad de bolitas rojas representa la extracción de esa cantidad de centavos.

Ejercicio 1

Definir los procedimientos RegistrarDeposito(monto) y RegistrarExtraccion(monto) que registran, respectivamente, el depósito o la extracción del monto indicado en la cuenta correspondiente a la fila actual. Se asume que el cabezal se encuentra ubicado en la columna 0.

¿Cuáles son las precondiciones de estos procedimientos? Considerar que una cuenta nunca debería llegar a tener saldo negativo.

Ejemplo:

program {
// Registra la extracción de 4 centavos
// de la cuenta actual.
RegistrarExtraccion(4)
}

Tablero inicial:

04_if_y_funciones_tablero_1

GBB/1.0
size 6 2
head 0 1
cell 0 1 Negro 4 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 1
cell 3 1 Rojo 2
cell 4 1 Verde 5
%%

Tablero final:

04_if_y_funciones_tablero_2

GBB/1.0
size 6 2
head 0 1
cell 0 1 Negro 5 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 1
cell 3 1 Rojo 2
cell 4 1 Verde 5
cell 5 1 Rojo 4
%%

Ejercicio 2

Definir el procedimiento: CalcularSaldo().

Propósito: pone S bolitas azules en la columna N + 1. El número N representa, como antes, la cantidad de transacciones que se hicieron en esa cuenta. El número S representa el saldo de la cuenta al cabo de las N transacciones, y suponiendo que el saldo inicial de la cuenta era 0.

Asumir que el cabezal comienza en la celda 0. ¿Cuál sería la precondición de este procedimiento? Considerar que el saldo nunca puede ser negativo.

Ejemplo:

program {
// Calcula el saldo de la cuenta actual.
CalcularSaldo()
}

Tablero inicial:

04_if_y_funciones_tablero_3

GBB/1.0
size 6 2
head 0 1
cell 0 1 Negro 4 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 1
cell 3 1 Rojo 2
cell 4 1 Verde 5
%%

Tablero final:

04_if_y_funciones_tablero_4

GBB/1.0
size 6 2
head 0 1
cell 0 1 Negro 4 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 1
cell 3 1 Rojo 2
cell 4 1 Verde 5
cell 5 1 Azul 7
%%

Ejercicio 3

Un cliente sin demasiados recursos desea extraer 4 centavos de todas sus cuentas que tengan saldo suficiente.

Para realizar este tipo de operaciones en general, se pide definir el procedimiento RegistrarExtraccionesPosibles(nroCuentas, cliente, monto).
Propósito: registra las extracciones del monto en centavos indicado de todas aquellas cuentas cuyo titular sea el cliente dado, y que dispongan de saldo suficiente. El primer parámero nroCuentas indica la cantidad total de cuentas del banco. El cabezal se supone ubicado en el origen.

Ejemplo:

program {
// Los parámetros indican que:
// Hay 5 cuentas en total.
// La operación aplica a las cuentas del cliente 3.
// La extracción es por un monto de 4 centavos.
RegistrarExtraccionesPosibles(5, 3, 4)
}

Tablero inicial:

04_if_y_funciones_tablero_5

GBB/1.0
size 6 5
head 0 0
cell 0 0 Negro 1 Azul 3
cell 1 0 Verde 5

cell 0 1 Negro 2 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 5

cell 0 2 Negro 1 Azul 1
cell 1 2 Verde 5

cell 0 3 Negro 1 Azul 1
cell 1 3 Verde 5

cell 0 4 Negro 2 Azul 3
cell 1 4 Verde 2
cell 2 4 Verde 3
%%

Tablero final:

04_if_y_funciones_tablero_6

GBB/1.0
size 6 5
head 0 0
cell 0 0 Negro 2 Azul 3
cell 1 0 Verde 5
cell 2 0 Rojo 4

cell 0 1 Negro 2 Azul 3
cell 1 1 Verde 5
cell 2 1 Rojo 5

cell 0 2 Negro 1 Azul 1
cell 1 2 Verde 5

cell 0 3 Negro 1 Azul 1
cell 1 3 Verde 5

cell 0 4 Negro 3 Azul 3
cell 1 4 Verde 2
cell 2 4 Verde 3
cell 3 4 Rojo 4
%%
Publicado en Uncategorized | Deja un comentario

Yo de niño temía que el espejo

Ejercicio 1

Definir el procedimiento CopiarCeldaHacia(n, dir).
Propósito: copia el contenido de la celda actual a la celda ubicada n pasos hacia la dirección dir. El cabezal debe quedar ubicado en la celda donde se encontraba inicialmente.
¿Cuál es su precondición?

Ejemplo:

program {
    CopiarCeldaHacia(1, Norte)
    CopiarCeldaHacia(2, Este)
}

Tablero inicial:

expresiones_foreach_tablero_1

GBB/1.0
size 3 3
head 0 0
cell 0 0 Azul 1 Negro 2 Verde 3
%%

Tablero final:

expresiones_foreach_tablero_2

GBB/1.0
size 3 3
head 0 0
cell 0 0 Azul 1 Negro 2 Verde 3
cell 0 1 Azul 1 Negro 2 Verde 3
cell 2 0 Azul 1 Negro 2 Verde 3
%%

Ejercicio 2

Definir el procedimiento Reflejar(dir, longitud, dirRealidad, profundidad).
Propósito: Copia el fragmento del tablero según resultaría de reflejarlo a través de un espejo imaginario. Los parámetros son los siguientes:

  1. dir es la dirección hacia donde se extiende el espejo.
  2. longitud es un número que representa la longitud del espejo.
    Por ejemplo, si dir es Norte y longitud es 3, se trata de un espejo “parado” que se extiende desde la celda actual a lo largo de tres celdas hacia el Norte.

  3. dirRealidad es la direción hacia donde se encuentra el fragmento del tablero que se quiere reflejar. El fragmento de tablero se refleja hacia la dirección opuesto(dirRealidad). El parámetro dirRealidad debería ser perpendicular a dir.
  4. profundidad es un número que representa el alcance del espejo: solo se reflejan aquellas celdas que se encuentren a hasta profundidad celdas de distancia del espejo.

Usar el procedimiento CopiarCeldaHacia para definir Reflejar. ¿Cuál es la precondición de Reflejar? ¿Se cumple la precondición de CopiarCeldaHacia cada vez que se lo usa?

Ejemplo:

program {
    Reflejar(Norte, 3, Oeste, 4)
}

Tablero inicial:

Las bolitas azules indican dónde se ubicaría el espejo pero son solo indicativas.

expresiones_foreach_tablero_3

GBB/1.0
size 9 4
head 4 1
cell 4 1 Azul 1
cell 4 2 Azul 1
cell 4 3 Azul 1
cell 0 1 Verde 1
cell 1 1 Verde 1
cell 2 1 Verde 1
cell 3 1 Verde 1
cell 3 2 Verde 1
cell 3 3 Verde 1
cell 1 3 Negro 3 Rojo 3
%%

Tablero final:

expresiones_foreach_tablero_4

GBB/1.0
size 9 4
head 4 1
cell 4 1 Azul 1
cell 4 2 Azul 1
cell 4 3 Azul 1
cell 0 1 Verde 1
cell 1 1 Verde 1
cell 2 1 Verde 1
cell 3 1 Verde 1
cell 3 2 Verde 1
cell 3 3 Verde 1
cell 1 3 Negro 3 Rojo 3
cell 8 1 Verde 1
cell 7 1 Verde 1
cell 6 1 Verde 1
cell 5 1 Verde 1
cell 5 2 Verde 1
cell 5 3 Verde 1
cell 7 3 Negro 3 Rojo 3
%%
Publicado en Uncategorized | Deja un comentario

Pensar es olvidar diferencias

Funes

En el relato Funes, el memorioso, se describe a un personaje con memoria perfecta:

» No sólo le costaba comprender que el símbolo genérico perro abarcara tantos individuos dispares de diversos tamaños y diversa forma; le molestaba que el perro de las tres y catorce (visto de perfil) tuviera el mismo nombre que el perro de las tres y cuarto (visto de frente).

[…]

» Había aprendido sin esfuerzo el inglés, el francés, el portugués, el latín. Sospecho, sin embargo que no era muy capaz de pensar. Pensar es olvidar diferencias, es generalizar, abstraer. En el abarrotado mundo de Funes no había sino detalles, casi inmediatos.

En cada uno de los ejercicios siguientes, el objetivo es olvidar diferencias, es decir, definir un procedimiento general que use parámetros para expresar una solución abstracta al problema planteado. Supondremos que el tablero se encuentra inicialmente vacío, y que el cabezal se encuentra ubicado en la celda central del tablero. Por ejemplo, si el tablero es de 5×5, el cabezal se encontrará inicialmente en la celda (2,2).

Ejercicio 1

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_1

GBB/1.0
size 3 3
head 0 1
cell 0 1 Rojo 3
%%
franjas_tablero_2

GBB/1.0
size 3 3
head 0 1
cell 0 1 Verde 3
%%

Escribir el procedimiento y probarlo. (¡No alcanza con imaginarlo!)

Ejercicio 2

¿Se podría escribir un único procedimiento que generalice a los dos procedimientos siguientes, dependiendo de los argumentos que se le provean?

procedure PonerDosNegras()
// Propósito:
//   Pone dos bolitas negras en la celda donde está el cabezal.
//   El cabezal queda en la celda en la que estaba.
{
	Poner(Negro)
	Poner(Negro)
}

procedure PonerAzulYRoja()
// Propósito:
//   Pone una bolita azul y una roja en la celda donde está el cabezal.
//   El cabezal queda en la celda en la que estaba.
{
	Poner(Azul)
	Poner(Rojo)
}

Ejercicio 3

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_3

GBB/1.0
size 3 3
head 0 2
cell 0 2 Rojo 3
%%
franjas_tablero_4

GBB/1.0
size 3 3
head 0 0
cell 0 0 Rojo 3
%%

Ejercicio 4

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_5

GBB/1.0
size 3 3
head 2 2
cell 0 0 Negro 1
cell 0 1 Negro 1
cell 0 2 Negro 1
cell 1 0 Azul 1
cell 1 1 Azul 1
cell 1 2 Azul 1
cell 2 0 Negro 1
cell 2 1 Negro 1
cell 2 2 Negro 1
%%
franjas_tablero_6

GBB/1.0
size 3 3
head 2 2
cell 0 0 Verde 1
cell 0 1 Verde 1
cell 0 2 Verde 1
cell 1 0 Verde 1
cell 1 1 Verde 1
cell 1 2 Verde 1
cell 2 0 Verde 1
cell 2 1 Verde 1
cell 2 2 Verde 1
%%

Ejercicio 5

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_7

GBB/1.0
size 3 3
head 1 1
cell 0 1 Azul 3
cell 2 1 Rojo 1
%%
franjas_tablero_8

GBB/1.0
size 3 3
head 1 1
cell 1 2 Verde 3
cell 1 0 Negro 1
%%

Ejercicio 6

Escribir un único procedimiento procedure Cruz(colNorte, colEste, colSur, colOeste) que tenga como resultado los dos tableros que se exhiben. En el primer caso el procedimiento se usa así: Cruz(Azul, Negro, Rojo, Verde), mientras que en el segundo caso se usa así: Cruz(Negro, Rojo, Negro, Rojo).

franjas_tablero_9

GBB/1.0
size 7 7
head 3 3
cell 3 4 Azul 1
cell 3 5 Azul 1
cell 3 6 Azul 1
cell 4 3 Negro 1
cell 5 3 Negro 1
cell 6 3 Negro 1
cell 3 2 Rojo 1
cell 3 1 Rojo 1
cell 3 0 Rojo 1
cell 2 3 Verde 1
cell 1 3 Verde 1
cell 0 3 Verde 1
%%
franjas_tablero_10

GBB/1.0
size 7 7
head 3 3
cell 3 4 Negro 1
cell 3 5 Negro 1
cell 3 6 Negro 1
cell 4 3 Rojo 1
cell 5 3 Rojo 1
cell 6 3 Rojo 1
cell 3 2 Negro 1
cell 3 1 Negro 1
cell 3 0 Negro 1
cell 2 3 Rojo 1
cell 1 3 Rojo 1
cell 0 3 Rojo 1
%%

Ejercicio 7

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_11

GBB/1.0
size 3 3
head 2 2
cell 0 0 Rojo 1
cell 0 1 Rojo 1
cell 0 2 Rojo 1
cell 1 0 Azul 1
cell 1 1 Azul 1
cell 1 2 Azul 1
cell 2 0 Rojo 1
cell 2 1 Rojo 1
cell 2 2 Rojo 1
%%
franjas_tablero_12

GBB/1.0
size 3 3
head 2 0
cell 0 0 Rojo 1
cell 0 1 Azul 1
cell 0 2 Rojo 1
cell 1 0 Rojo 1
cell 1 1 Azul 1
cell 1 2 Rojo 1
cell 2 0 Rojo 1
cell 2 1 Azul 1
cell 2 2 Rojo 1
%%

Ejercicio 8

¿Se podría escribir un único procedimiento que pueda tener como resultado los dos tableros que se exhiben, dependiendo solamente de los argumentos que se le provean?

franjas_tablero_13

GBB/1.0
size 3 3
head 1 1
cell 0 0 Verde 1
cell 0 1 Verde 2
cell 0 2 Verde 3
cell 1 2 Verde 4
cell 2 2 Verde 5
cell 2 1 Verde 6
cell 2 0 Verde 7
cell 1 0 Verde 8
%%
franjas_tablero_14

GBB/1.0
size 3 3
head 1 1
cell 2 0 Verde 1
cell 2 1 Verde 2
cell 2 2 Verde 3
cell 1 2 Verde 4
cell 0 2 Verde 5
cell 0 1 Verde 6
cell 0 0 Verde 7
cell 1 0 Verde 8
%%

Ejercicio 9

Escribir un único procedimiento procedure Encrucijada(color) que tenga como resultado los dos tableros que se exhiben. En el primer caso el procedimiento se usa así: Encrucijada(Negro), mientras que en el segundo caso se usa así: Encrucijada(Azul).

franjas_tablero_15

GBB/1.0
size 7 7
head 3 3
cell 0 4 Negro 1
cell 1 4 Negro 1
cell 2 4 Negro 1
cell 2 5 Negro 1
cell 2 6 Negro 1
cell 4 4 Negro 1
cell 4 5 Negro 1
cell 4 6 Negro 1
cell 5 4 Negro 1
cell 6 4 Negro 1
cell 0 2 Negro 1
cell 1 2 Negro 1
cell 2 2 Negro 1
cell 2 1 Negro 1
cell 2 0 Negro 1
cell 4 0 Negro 1
cell 4 1 Negro 1
cell 4 2 Negro 1
cell 5 2 Negro 1
cell 6 2 Negro 1
%%
franjas_tablero_16

GBB/1.0
size 7 7
head 3 3
cell 0 4 Azul 1
cell 1 4 Azul 1
cell 2 4 Azul 1
cell 2 5 Azul 1
cell 2 6 Azul 1
cell 4 4 Azul 1
cell 4 5 Azul 1
cell 4 6 Azul 1
cell 5 4 Azul 1
cell 6 4 Azul 1
cell 0 2 Azul 1
cell 1 2 Azul 1
cell 2 2 Azul 1
cell 2 1 Azul 1
cell 2 0 Azul 1
cell 4 0 Azul 1
cell 4 1 Azul 1
cell 4 2 Azul 1
cell 5 2 Azul 1
cell 6 2 Azul 1
%%

Ejercicio 10

Escribir un único procedimiento procedure Diagonal(dir, dirOpuesta) que tenga como resultado los dos tableros que se exhiben. En el primer caso el procedimiento se usa así: Diagonal(Este, Oeste), mientras que en el segundo caso se usa así: Diagonal(Oeste, Este).

franjas_tablero_17

GBB/1.0
size 7 7
head 3 3
cell 0 0 Rojo 1
cell 1 1 Rojo 1
cell 2 2 Rojo 1
cell 3 3 Rojo 1
cell 4 4 Rojo 1
cell 5 5 Rojo 1
cell 6 6 Rojo 1
%%
franjas_tablero_18

GBB/1.0
size 7 7
head 3 3
cell 0 6 Rojo 1
cell 1 5 Rojo 1
cell 2 4 Rojo 1
cell 3 3 Rojo 1
cell 4 2 Rojo 1
cell 5 1 Rojo 1
cell 6 0 Rojo 1
%%
Publicado en Uncategorized | Deja un comentario

Los enigmas de la esfinge

Edipo y la esfinge

Para los antiguos egipcios y griegos, las esfinges eran criaturas con cabeza humana y cuerpo de león. Se dice que la esfinge mataba a quienes no podían resolver su enigma:

Cuadrúpedo en la aurora, alto en el día
y con tres pies errando por el vano
ámbito de la tarde […]

Si adaptáramos la figura de la esfinge a nuestro tiempo, quizá nos encontraríamos con enigmas como los siguientes. Cada enigma consta de un programa en Gobstones incompleto, que se debe completar para que describa un efecto que concuerde con los tableros iniciales y finales especificados.

En todos los enigmas siguientes, el tablero inicial es un tablero vacío de 4 filas por 4 columnas, y el cabezal se encuentra ubicado en el origen (es decir, la celda en el extremo sudoeste del tablero).

Enigma 1

Tablero final esperado

man1_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Azul 3
cabezal columna 0 fila 0
fin tablero

Esqueleto del programa


program {
    A()
    A()
    A()
}

procedure A() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuál sería un mejor nombre para el procedimiento A?

Enigma 2

Tablero final esperado

man2_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 1 0 Rojo 1
celda 2 0 Rojo 1
celda 3 0 Rojo 1
cabezal columna 3 fila 0
fin tablero

Esqueleto del programa


program {
    B()
    B()
    B()
}

procedure B() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuál es el propósito del procedimiento B?
  2. ¿El procedimiento B es total o parcial?
  3. ¿Cuál sería un mejor nombre para el procedimiento B?

Enigma 3

Tablero final esperado

man3_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Rojo 1
celda 1 0 Azul 1
celda 1 1 Rojo 1
celda 2 1 Azul 1
celda 2 2 Rojo 1
celda 3 2 Azul 1
cabezal columna 3 fila 3
fin tablero

Esqueleto del programa


program {
    C()
}

procedure C() {
    D()
    D()
    D()
}

procedure D() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuáles son los propósitos de los procedimientos C y D?
  2. El procedimiento D es parcial (¿por qué?)
  3. ¿El procedimiento C es total o parcial?

Enigma 4

Tablero final esperado

man4_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 1 Negro 1
celda 0 2 Negro 1
celda 0 3 Negro 1
celda 1 1 Negro 1
celda 1 2 Negro 1
celda 1 3 Negro 1
cabezal columna 2 fila 0
fin tablero

Esqueleto del programa


program {
    E()
    E()
}

procedure E() {
    F()
    F()
    F()
    /* COMPLETAR */
}

procedure F() {
    Mover(Norte)
    Poner(Negro)
}

Preguntas

  1. ¿Cuál es el propósito del procedimiento E?
  2. ¿Qué condiciones tienen que cumplirse para que
    el procedimiento E pueda llevar a cabo su propósito?

  3. ¿Cuál sería un mejor nombre para el procedimiento E?

Enigma 5

Tablero final esperado

man5_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Azul 1 Negro 1 Rojo 1 Verde 1
celda 1 1 Azul 1 Negro 1 Rojo 1 Verde 1
celda 2 2 Azul 1 Negro 1 Rojo 1 Verde 1
celda 3 3 Azul 1 Negro 1 Rojo 1 Verde 1
cabezal columna 3 fila 3
fin tablero

Esqueleto del programa


program {
    G()
    H()
    G()
    H()
    G()
    H()
    G()
}

procedure G() {
    /* COMPLETAR */
}

procedure H() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuáles son los propósitos de los procedimientos G y H?
  2. ¿Qué condiciones tienen que cumplirse para que
    el procedimiento H pueda llevar a cabo su propósito?

  3. ¿Cuál sería un mejor nombre para el procedimiento G?

Enigma 6

Tablero final esperado

man6_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Rojo 2
celda 0 1 Rojo 2
celda 0 2 Rojo 2
celda 1 0 Rojo 2
celda 1 1 Rojo 2
celda 1 2 Rojo 2
celda 2 0 Verde 2
celda 2 1 Verde 2
celda 2 2 Verde 2
celda 3 0 Verde 2
celda 3 1 Verde 2
celda 3 2 Verde 2
cabezal columna 0 fila 3
fin tablero

Esqueleto del programa


program {
    I()
    I()
    I()
}

procedure I() {
    J()
    J()
    Mover(Norte)
}

procedure J() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuáles son los propósitos de los procedimientos I y J?
  2. ¿Cuáles serían mejores nombres para I y J?

Pista: notar que el program usa tres veces el procedimiento I. Identificar cuál es el elemento del tablero que se repite tres veces.

Enigma 7

Tablero final esperado

man7_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 1 Rojo 2
celda 0 2 Rojo 2
celda 0 3 Rojo 2
celda 1 0 Rojo 2
celda 1 1 Rojo 2
celda 1 2 Rojo 2
celda 2 0 Verde 2
celda 2 1 Verde 2
celda 2 2 Verde 2
celda 3 1 Verde 2
celda 3 2 Verde 2
celda 3 3 Verde 2
cabezal columna 0 fila 3
fin tablero

Esqueleto del programa


program {
    K()
    K()
    K()
}

procedure K() {
    L()
    L()
    Mover(Norte)
}

procedure L() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuáles son los propósitos de los procedimientos K y L?

Pista: comparar con el enigma anterior.

Enigma 8

Tablero final esperado

man8_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Verde 64
cabezal columna 0 fila 0
fin tablero

Esqueleto del programa


program {
    M()
    M()
}

procedure M() {
    N()
    N()
}

procedure N() {
    O()
    O()
}

procedure O() {
    P()
    P()
}

procedure P() {
    Q()
    Q()
}

procedure Q() {
    /* COMPLETAR */
}

Preguntas

  1. ¿Cuáles son los propósitos de los procedimientos M, N, O, P y Q?
  2. ¿Cuáles serían mejores nombres para los procedimientos M, N, O, P y Q?
  3. ¿Los procedimientos M, N, O, P y Q son totales o parciales?

Enigma 9

Tablero final esperado

man9_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Azul 1 Negro 1 Rojo 1 Verde 1
celda 0 1 Azul 1 Negro 1 Rojo 1 Verde 1
celda 0 2 Azul 1 Negro 1 Rojo 1 Verde 1
celda 0 3 Azul 1 Negro 1 Rojo 1 Verde 1
celda 1 0 Azul 1 Negro 1 Rojo 1 Verde 1
celda 1 1 Azul 1 Negro 1 Rojo 1 Verde 1
celda 1 2 Azul 1 Negro 1 Rojo 1 Verde 1
celda 1 3 Azul 1 Negro 1 Rojo 1 Verde 1
celda 2 0 Azul 1 Negro 1 Rojo 1 Verde 1
celda 2 1 Azul 1 Negro 1 Rojo 1 Verde 1
celda 2 2 Azul 1 Negro 1 Rojo 1 Verde 1
celda 2 3 Azul 1 Negro 1 Rojo 1 Verde 1
celda 3 0 Azul 1 Negro 1 Rojo 1 Verde 1
celda 3 1 Azul 1 Negro 1 Rojo 1 Verde 1
celda 3 2 Azul 1 Negro 1 Rojo 1 Verde 1
celda 3 3 Azul 1 Negro 1 Rojo 1 Verde 1
cabezal columna 0 fila 3
fin tablero

Esqueleto del programa


program {
    LlenarElTablero()   
}

procedure LlenarElTablero() {
    /* COMPLETAR */
}

/* Usar el procedimiento LlenarCelda. */
procedure LlenarCelda() {
    Poner(Azul)
    Poner(Negro)
    Poner(Rojo)
    Poner(Verde)
}

/* Definir procedimientos adicionales si es necesario. */
/* COMPLETAR */

Enigma 10

Tablero final esperado

man10_tablero4_salida
comienzo tablero
tamaño columna 4 fila 4
celda 0 0 Verde 1
celda 0 1 Verde 1
celda 0 2 Verde 1
celda 0 3 Verde 1
celda 1 0 Verde 2
celda 1 1 Verde 2
celda 1 2 Verde 2
celda 1 3 Verde 2
celda 2 0 Verde 3
celda 2 1 Verde 3
celda 2 2 Verde 3
celda 2 3 Verde 3
celda 3 0 Verde 4
celda 3 1 Verde 4
celda 3 2 Verde 4
celda 3 3 Verde 4
cabezal columna 0 fila 3
fin tablero

Esqueleto del programa

program {
    Enumerar()
}

procedure Enumerar() {
    /* COMPLETAR */
}

/* Definir procedimientos adicionales si es necesario. */

/* COMPLETAR */
Publicado en Uncategorized | Deja un comentario

En busca de los lentes correctos

En este ejercicio, ayudaremos a un oftalmólogo a encontrar el par de anteojos adecuado para su paciente.

El tablero de Gobstones modelará el consultorio del oculista. En la celda del origen (0,0) habrá bolitas de color verde, que representarán los ojos del paciente. La cantidad de bolitas verdes en esa celda es un número que indica el tipo de visión que posee. En el resto del tablero puede haber bolitas de color negro, que representan distintos símbolos. La cantidad de bolitas negras es otro número, que indica cuál es el símbolo que hay en ese lugar del consultorio.

No conocemos exactamente lo que estos números significan, pero contamos con la siguiente fórmula, según lo indicado por el oculista:

function letraQueVeElPaciente(ojo, lente, distancia, letra)
// Propósito:
//  Recibe los siguientes parámetros:
//    ojo       : un número que representa el tipo de
//                ojo del paciente
//    lente     : un número que representa el tipo de
//                lente que se está probando el paciente
//    distancia : distancia desde el paciente hasta el
//                símbolo que está mirando
//    letra     : un número que representa el símbolo que está
//                mirando el paciente
//  Devuelve un número que representa el símbolo
//  que el paciente afirma estar viendo.
{
    t := (ojo mod 11 + 1) * (ojo div 11 + 1)
    r := ((t - lente) ^ 2 + 1) * distancia
    return (((r + 1) * letra) div (distancia + 1))
}

Asumiendo que en el origen hay bolitas de color verde (los ojos del paciente) y en el resto del tablero hay bolitas de color negro (símbolos), y que no hay bolitas de otros colores en ningún lugar del tablero, programar las siguientes operaciones:

Ejercicio 1 procedure ProbarLentes(lente) que le pruebe al paciente los lentes del tipo indicado. El procedimiento debe visitar todas las celdas del tablero que contengan símbolos (i.e. bolitas de color negro), y anotar, con bolitas de color rojo, en cada una de dichas celdas, lo que manifiesta ver el paciente.

Ejercicio 2 function graduacionCorrecta(lente) que denota el valor verdadero si los lentes del tipo indicado son adecuados para el paciente. Los lentes son adecuados si los símbolos que manifiesta ver el paciente coinciden con lo que efectivamente hay en el consultorio.

Ejercicio 3 function lentesCorrectosParaElPaciente(). Esta función denota un número que representa el tipo de lentes que le corresponden al paciente.

Publicado en Uncategorized | 1 Comentario