El juego de simón

Vamos a combinar en esta aplicación la utilización de gráficos, uso del teclado o el ratón y, por supuesto, el sonido. De esta forma realizaremos un divertimento sonoro y visual, que nos permitirá adentrarnos en la utilización de efectos sonoros sencillos utilizando la orden beep.

Uno de los aspectos a destacar de este ejemplo es el interés de utilizar campos de texto para guardar información que se comparte entre diferentes objetos y que el desarrollador puede ver cómo evoluciona mientras avanza. Terminado el desarollo se habrán de ocultar de la vista del usuario, claro.

Si no conoce el juego al que me refiero, le diré que es un pequeño objeto de forma circular en el que hay dispuestos una serie de botones. Estos botones tienen asociados un sonido diferente y su pulsación viene reforzada por un elemento visual: se iluminan mientras suena la nota asociada. El juego consiste consiste en repetir una secuencia sonora que se le propone al usuario. Para realizar esa secuencia de sonidos, al usuario se le muestra la "interpretación automática" de la misma y se espera que él la repita actuando sobre los botones. Si se realiza con éxito, la complejidad de la secuencia se incrementa (generalmente añadiendo una nota más a la misma secuencia) y se repite el ciclo.

Tenemos pues que diseñar un interfaz, unos objetos que muestren el cambio de estado al ser pulsados y que emitan una nota al tiempo, generar una secuencia y comprobar que el usuario la repite con exactitud.

La primera versión corresponde a la Figura 8-8, este es el primer planteamiento básico ...

Figura 8-8. Aplicación simón: primera tarjeta del desarrollo de la misma.

#
# Botón "Inicialitza"
#
on mouseUp
  set cursor to busy
  put "abcd" into fld "Sequencia proposta"
  put empty into fld "Sequencia llegida"
  put 1 into fld "numero"
end mouseUp

#
# Grupo "totsElsControls"
#
on mouseUp
  put the short name of target after fld "Sequencia llegida"
  put the last character of fld "Sequencia llegida" && character (fld "numero") of fld "Sequencia proposta"
  if (the last character of fld "Sequencia llegida" is not character (fld "numero") of fld "Sequencia proposta")
  then
    answer "Ecccccccc!"
    send "mouseUp" to btn "Inicialitza"
    #put 0 into fld "numero"
  else
    if fld "numero" is the length of fld "Sequencia proposta"
    then
      answer "Sequencia completa en exit!"
      send "mouseUp" to btn "Inicialitza"
    else
      add 1 to fld "numero"
    end if
  end if
  
end mouseUp

#
# Campo de texto ">"
#
on mouseUp
  go to next card
end mouseUp
                      

La segunda versión (Figura 8-9) corresponde a la incorporación de un corpus de secuencias a repetir. Para ello se han añadido dos controles más...

Figura 8-9. Aplicación simón: segunda tarjeta del desarrollo de la misma.

Al probar este código, como yo, seguramente habrá notado la necesidad de volver a un estado incial que también se ejecute de forma automática al llegar a esta tarjeta. A mi se me ocurre que aprovechando que se puede situar código en la tarjeta ...

#
# La tarjeta "Segon versió"
#
on openCard
  put 1 into fld "numero"
  put 0 into fld "nSequencia"
  send "mouseUp" to btn "Inicialitza"
end openCard

on mouseUp
  send "openCard" to me
end mouseUp
                      

Para que el código que ya tenemos de los controles se adpte a estos cambios hay que hacer un par de retoques:

#
# Botón "Inicialitza"
#
on mouseUp
  set cursor to busy
  add 1 to fld "nSequencia"
  if (fld "nSequencia" > the number of lines of fld "Sequencies precalculaes")
  then
    answer "Has acabat un nivell!"
  else
    put (line (fld "nSequencia") of fld "Sequencies precalculaes") into fld "Sequencia proposta"
    put empty into fld "Sequencia llegida"
    put 1 into fld "numero"
  end if
end mouseUp

#
# Grupo "totsElsControls"
#
on mouseUp
  put the short name of target after fld "Sequencia llegida"
  put the last character of fld "Seqüència llegida" &&\
          character (fld "numero") of fld "Sequencia proposta"
  if (the last character of fld "Seqüència llegida" is not\
       character (fld "numero") of fld "Sequencia proposta")
  then
    answer "Ecccccccc!"
    # Ara, en conter de inicialitzar una sequencia, cal inicialitzar la llista de sequencies ...
    send "mouseUp" to this cd
    send "mouseUp" to btn "Inicialitza"
    
    #put 0 into fld "numero"
  else
    if fld "numero" is the length of fld "Sequencia proposta"
    then
      answer "Seqüència completà en éxit!"
      send "mouseUp" to btn "Inicialitza"
    else
      add 1 to fld "numero"
    end if
  end if
  
end mouseUp
                      

Llega la hora de introducir el sonido y, entonces, me doy cuenta que el usuario ha tenido pocas posibilidades de acostumbrarse a la correspondencia entre objeto pulsado y sonido que emite, o simplemente quiere dedicarse a la interpretación con este "instrumento" o yo qué se, pero no quiere enfrentarse a repetir una secuencia. Que se pueda probar el sonido que hace cada elemento, sería interesante disponer de una versión reducida ...

Esta prodría ser l'opció per defecte a l'inici hasta que fas "Iniciar Juego" ... De hecho nuestra aplicación no tiene previsto un punto de partida ... Esto hay que resolverlo ya. ¡Aunque hay que hace notar que es un error de la etapa de diseño inicial! Bueno, pues desde la "Message Box", ejecutamos:

clone this card
                      

A esta copia de la tarjeta le podemos quitar todo lo referido a las secuencias, sólo dejamos el botón > para ir a la tarjeta siguiente. Aprovechando que estamos aquí, vamos a crear la tarjeta de presentación, podemos crear una nueva tarjeta, pero aprovechando

Aprovechando que estamos aquí, vamos a crear la tarjeta de presentación, podemos hacerlo desde cero, pero yo opto por clonar la tarjeta actual, recuperando la orden con las flechas del teclado en la "Message Box"

Figura 8-10. Aplicación simón: incorporando y reordenando dos nuevas tarjetas sobre la marcha.

a)b)

c)d)

Ahora hemos de recolocar las tarjetas que hemos creado, para ello desde las propiedades de la pila ... de la "Menu Bar" Edit|Stack properties..., el botón Componentes nos pemite seleccionar una tarjeta y resituarla en el orden de la pila mediante las flechas de la parte inferior. Hemos de pasar de la situación de la Figura 8-10c a la Figura 8-10d.

Volviendo a la etapa en que nos encontramos, estábamos a punto de poner audio a nuestra aplicación y mira dónde nos hemos ido. Volvamos pues a la tarjeta que habíamos clonado. Incluimos un nuevo botón que llamaremos accio. Este recibirá la "tecla" pulsada y se encargará de ejecutar la acción correspondiente a cada pulsación de los botones. En nuestro caso ...

#
# Botón "accio"
#
local elsControls="a b c d"
local freqencies="440 880 1760 2520"

on fesAlgo qui
  --      add 1 to fld "numero"
  set the beepPitch to \
      the word  (wordOffset(qui, "a b c d")) of "440 500 600 700"
  --            the word  (wordOffset(qui, "a b c d")) of "440 500 600 700"
  --            the word  (wordOffset(qui, elsControls)) of frequencies
  beep 1
end fesAlgo


#
# Grupo "totsElsControlsDeProva"
#
on mouseUp
  send ("fesAlgo" && the short name of target) to btn "accio"
end mouseUp

                      

Debido al código introducido en la tarjeta, cada vez que lleguemos a ella se incializan todos los controles, ahora por facilitar las pruebas podríamos hacer que en cualquier momento pulsando sobre ella también se desencadene esta acción. Después habrá que acordarse de quitarlo o, al menos, comentarlo. Añadamos tres líneas al código de la tarjeta, que con esto vale por el momento:

#
# La tarjeta "Segon versió"
#
...

on mouseUp
  send "openCard" to me
end mouseUp
                      

La tercera versión (Figura 8-11d) es el ensayo de las diferentes interfaces gráficas que se podrían incorporar ...

Figura 8-11. Aplicación simón: tercera tarjeta del desarrollo de la misma.

#
#
#
local i

on mouseUp
  set cursor to busy
  add 1 to fld "nSequencia"
  if (fld "nSequencia" > the number of lines of fld "Sequencies precalculaes")
  then
    answer "Has acabat un nivell!"
  else
    put (line (fld "nSequencia") of fld "Sequencies precalculaes") into fld "Sequencia proposta"
    put empty into fld "Sequencia llegida"
    put 1 into fld "numero"
    repeat with i = 1 to the length of fld "Sequencia proposta"
      send ("fesAlgo" && char i of fld "Sequencia proposta") to btn "accio"
      wait 200 milliseconds
    end repeat
  end if
end mouseUp

#
#
#
local elsControls="a b c d", freqencies="440 500 600 700"

on mouseUp
  put the short name of target after fld "Sequencia llegida"
  put the last character of fld "Sequencia llegida" && character (fld "numero") of fld "Sequencia proposta"
  if (the last character of fld "Sequencia llegida" is not character (fld "numero") of fld "Sequencia proposta")
  then
    answer "Ecccccccc!"
    # Ara, en conter de inicialitzar una sequencia, cal inicialitzar la llista de sequencies ...
    send "mouseUp" to this cd    
  else
    send ("fesAlgo" && the short name of target) to btn "accio"
    if fld "numero" is the length of fld "Sequencia proposta"
    then
      answer "Sequencia completa en exit!"
      send "mouseUp" to btn "Inicialitza"
    else
      send ("fesAlgo" && the short name of target) to btn "accio"
      add 1 to fld "numero"
    end if
  end if
  
end mouseUp
                      

La cuarta versión (Figura 8-12d) es el ensayo de las diferentes interfaces gráficas que se podrían incorporar ...

Aviso

No es moment de fer ací una cosa complicà, ja es vorà més complexe al aplegar al tema de gràfics!

Figura 8-12. Aplicación simón: cuarta tarjeta del desarrollo de la misma.

#
#
#

#
#
#
                      

Para terminar, comentar que el desarrollo no está cerrado: