lunes, 27 de mayo de 2013

Corolario I


Un juego en Perl

Como corolario de la Parte I de "Perl for newbies" vamos a programar un juego muy simple. Se trata de adivinar qué número está pensando la computadora. Se le pide al usuario que adivine el número y le informamos si acertó o si su número es mayor o menor. Manos a la obra!

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero',"\n";
my $miNumero= 5;
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   print 'Dime que numero estoy pensando',"\n";
   my $numero= <>;
   chomp($numero);
   if ($miNumero==$numero){
      print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!',"\n";
   } elsif($miNumero<$numero) {
      print 'No. Mi numero es menor que ', $numero, "\n";
   } else {
      print 'No. Mi numero es mayor que ', $numero, "\n";
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Las posibles salidas del programa son:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
5
Si! Acertaste! Mi numero es el 5!!!
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
9
No. Mi numero es menor que 9
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
no
Esta bien, no quieres adivinar mi numero
Gracias por jugar conmigo
---------------------------------------------------------------------------
Usamos el operador x para imprimir una cantidad fija de caracteres, en este caso '*' y '-'. También usamos <> para recibir la respuesta del usuario, chomp() para limpiarla, print para enviarle mensajes y la estructura de control if para tomar decisiones según el valor ingresado. El problema es que el usuario puede arriesgar una sola vez el valor, además ya sabemos que el número elegido será el 5 así que el juego se torna algo monótono y aburrido. Deberíamos darle al usuario un número distinto cada vez y la oportunidad de adivinarlo con cierta cantidad de intentos, digamos 3. Hagamos las modificaciones para que quede mejor este juego.

Modificaciones

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
my $miNumero;
if ('si'eq@respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Usamos la función rand() para obtener un número aleatorio entre 0 y el argumento, en este caso 10, y aunque el número aleatorio podría ser el 0 nunca va a ser 10, pero como son números de coma flotante también usamos la función int() para que nos deje la parte entera del número. Usamos un bucle for que va de 1 a 3 gracias al operador .. que nos devuelve un arreglo de números consecutivos. Usamos last para salir del bucle cuando el usuario adivina el número. Pero el programa no funciona como queremos. Cuando el usuario escribe 'si' el programa termina sin informarnos nada anormal. Para que Perl nos dé más información sobre los posibles errores tenemos que usar dos pragmas muy útiles: strict y warnings. Veamos la diferencia. Cuando agregamos al comienzo del programa
use strict;
use warnings;
Nos informa lo siguiente:
Global symbol "@respuesta" requires explicit package name at adivina2.pl
Global symbol "$miNumeroo" requires explicit package name at adivina2.pl
Hay dos errores de tipeo, primero el @ en la variables $respuesta, luego la 'o' repetida al final de $miNumero. Corregimos y nos dice lo siguiente:
"my" variable $miNumero masks earlier declaration in same scope at adivina2.pl
Parece que declaramos dos veces la misma variable. Borramos la segunda declaración que es la incorrecta en este caso y corremos el programa. Funciona!
use warnings;
use strict;

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print  "Mi numero era el $miNumero \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumero \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Y esta es mi jugada:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero del 0 al 9
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
7
No. Mi numero es menor que 7
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Dime que numero estoy pensando
4    
No. Mi numero es mayor que 4
Mi numero era el 5  
Gracias por jugar conmigo
---------------------------------------------------------------------------

Más modificaciones

Podríamos seguir modificando el programa. Por ejemplo dejar que el usuario elija cuantos intentos puede tener, o que luego de un juego el usuario pueda seguir jugando en vez de terminar el programa, o que el programa elija un número de 2 cifras, o que en vez de elegir un número aleatorio sea una letra aleatoria. Cómo podemos asignar una letra aleatoria a una variable?
my $letra= ('a'..'z')[rand(26)];