Escribe programas interactivos en Python

Anteriormente hemos estado haciendo programas ejecutables en Python que aceptaban parámetros por línea de comandos, es decir, en el momento de invocarlos le pasábamos todos los datos que necesitaban para comenzar a ejecutarse.

Este tipo de programas son muy adecuados para crear utilidades para el usuario cuando está usando un terminal, o cuando quiere integrarlos en otro sistema mayor que tenga la posibilidad de invocar estas utilidades. Sin embargo, en otras ocasiones es necesario dotar al programa de la capacidad de ser interactivo, como a la hora de pedir confirmación al usuario y recibir una respuesta (el clásico “¿Desea borrar el fichero? [S/n]”), o incluso llegar a crear nuestros propios intérpretes de órdenes.

En este artículo veremos lo sencillo que es creando un juego interactivo que proponga al usuario adivinar un número entre cero y un parámetro que recibirá por línea de comandos.

Cosas que debes repasar:

Obtener datos de modo interactivo

En Python 3 la entrada de datos se lleva a cabo mediante la función estándar input() , que permite escribir un mensaje a mostrar por la pantalla invitando al usuario a responder a una pregunta. En el momento de ejecutar input() el programa se detendrá, mostrando la frase que le hemos pasado como parámetro, y se quedará a la espera de una respuesta del usuario que podrá introducir por teclado, terminando su respuesta mediante la tecla intro (↵). Una vez lo haga, la función devolverá como resultado el texto introducido por el usuario pero sin el carácter de retorno de carro final.

Haz la prueba tú mismo escribiendo en IDLE (el entorno de desarrollo de Python 3) lo siguiente:

x = input ("Dime tu nombre: ")

Verás que IDLE imprime ese mensaje pero no vuelve a mostrar el cursor de Python: está esperando a que introduzcas texto. Introduce tu nombre y pulsa la tecla intro (↵): en ese momento, IDLE volverá a mostrar el cursor que permite escribir sentencias en Python. Escribe ahora:

print ("Hola", x)

y observa el resultado.

Funcionamiento de la función input() de Python 3
Funcionamiento de la función input() de Python 3

En Python 2 existen dos funciones: raw_input(), que tiene exactamente el mismo comportamiento que hemos visto con la función input() de Python 3, e input(). Input en Python 2 es una función algo peliaguda porque además de recoger la entrada por teclado del usuario la interpreta como una sentencia en Python. No se debe usar porque puede dar lugar a que el usuario introduzca código malintencionado en nuestro programa. Siempre debemos usar raw_input() en Python 2 o input() en Python 3 y realizar la interpretación de datos en nuestro programa, de forma muy controlada y calculada.

En cualquier caso, yo recomiendo usar siempre Python 3 ya que es la versión que está actualmente evolucionando y por lo tanto será donde aprovechemos los avances en el lenguaje. Python 2 ya solamente recibe actualizaciones de seguridad y de mantenimiento: no evoluciona.

¡Adivina el número!

Vamos a hacer un programa ejecutable que acepte por línea de comandos un número arbitrario. Con ese número, el programa propondrá adivinar al usuario, de modo interactivo, un número obtenido al azar entre el 0 y el número obtenido por línea de comandos. Para facilitar la tarea, el programa irá contestando si el usuario se ha pasado por lo alto, si se ha quedado corto y, por supuesto, si ha acertado.

Para obtener un número al azar entre otros dos usaremos la función random() del módulo random, que ofrece un número entre 0 y 1, con decimales. Esos decimales los redondearemos con round() y el resultado lo convertiremos a entero mediante int().

Para empezar, introduciremos el bloque que interpretará el parámetro por línea de comando. Lo que haré será tratar de interpretar el primer parámetro como un número mayor que 0. Si no se introduce un número, o éste es menor que 0, el programa termina. Si no se introduce ningún parámetro el programa tomará como valor por defecto el 100. El código es el siguiente:

import sys

try:
    arg = sys.argv[1]
    techo = int (arg)
    if (techo < 0):
        print ("Error 1: el número introducido, " + arg + " es menor que 0.")
        exit (1) # Error de línea de comandos.
except (IndexError):
    techo = 100 # por defecto
except (ValueError):
    print("Error 2: el parámetro introducido, '"+ arg + "', no es un número.")
    exit(2) # Error de línea de comandos.

El paso siguiente es generar un primer número secreto entre 0 y el techo  introducido por línea de comandos. Para eso:

  • Importaremos el módulo random dándole un nombre opcionalmente, tras la línea que importa el módulo sys:
import sys
import random as generador
...
  • Hecho esto, al final de lo que llevamos de programa generaremos un primer número secreto: multiplicaremos el restultado de generador.random() por el número máximo, recibido por línea de comandos, y lo convertiremos a un número entero redondéandolo y aplicándole la conversión de tipos.
secreto = int (round (techo * generador.random()))

A continuación hay que escribir la mecánica del juego. Lo que haremos será un bucle que:

  1. Pedirá un intento al usuario.
  2. Si el intento es válido (un número entre 0 y el techo  introducido por línea de comandos), lo comparará con el secreto.
  3. Informará al usuario del resultado y, si ha acertado, ofrecerá la oportunidad de jugar otra vez, generando un nuevo número secreto.

Para convertir esto en realidad escribiremos un bucle sobre una variable booleana (cuyo valor puede ser True  o False ), que modificaremos sólo si el jugador decide abandonar el juego. El resto del código es sencillo de escribir si se tiene en cuenta lo aprendido hasta ahora en la serie de Python.

continuar = True
while continuar:
    
    # Captura de la entrada
    s_intento = input ("Adivina el número entre 0 y " + str(techo) + ":")

    # Control de errores: formato numérico y fuera de rango.
    # Variable para controlar el error en la entrada del usuario
    error = False
    try:
        intento = int (s_intento)        
        if intento > techo or intento < 0:
            print ("Intento incorrecto: debe ser un número entre 0 y " + str(techo))
            error = True
    except (ValueError):
        error = True
        print ("Error: '" + s_intento + "' no es un número")
    

    # Si no se han detectado errores, se evalúa el intento del jugador.
    if not error:

        # Vemos si ha acertado, quedado por arriba o por abajo.
        if intento == secreto:

            # Vemos si quiere jugar de nuevo.
            respuesta = ''
            while respuesta.lower() not in ['s', 'n']:
                respuesta = input ("¡Has acertado!, ¿quieres jugar otra vez? [s/n]")
            if respuesta.lower() == "s":
                print ("Generando nuevo número secreto")
                secreto = int (round (techo * generador.random()))
            else:
                continuar = False # Esto detiene el juego.
        
        elif intento < secreto:
            print ("Te has quedado corto, prueba con un número más alto")
        else:
            print ("Te has pasado: prueba con un número más bajo")

El código fuente completo quedará como sigue:

import sys
import random as generador

try:
    arg = sys.argv[1]
    techo = int (arg)
    if (techo < 0):
        print ("Error 1: el número introducido, " + arg + " es menor que 0.")
        exit (1)
except (IndexError):
    techo = 100 # por defecto
except (ValueError):
    print("Error 2: el parámetro introducido, '"+ arg + "', no es un número.")
    exit(2) # Error de línea de comandos.


secreto = int (round (techo * generador.random()))

continuar = True
while continuar:
    
    # Captura de la entrada
    s_intento = input ("Adivina el número entre 0 y " + str(techo) + ":")

    # Control de errores: formato numérico y fuera de rango.
    # Variable para controlar el error en la entrada del usuario
    error = False
    try:
        intento = int (s_intento)        
        if intento > techo or intento < 0:
            print ("Intento incorrecto: debe ser un número entre 0 y " + str(techo))
            error = True
    except (ValueError):
        error = True
        print ("Error: '" + s_intento + "' no es un número")
    

    # Si no se han detectado errores, se evalúa el intento del jugador.
    if not error:

        # Vemos si ha acertado, quedado por arriba o por abajo.
        if intento == secreto:

            # Vemos si quiere jugar de nuevo.
            respuesta = ''
            while respuesta.lower() not in ['s', 'n']:
                respuesta = input ("¡Has acertado!, ¿quieres jugar otra vez? [s/n]")
            if respuesta.lower() == "s":
                print ("Generando nuevo número secreto")
                secreto = int (round (techo * generador.random()))
            else:
                continuar = False # Esto detiene el juego.
        
        elif intento < secreto:
            print ("Te has quedado corto, prueba con un número más alto")
        else:
            print ("Te has pasado: prueba con un número más bajo")
        
exit(0) # código de no error.

Ejecución del programa

Este programa, así escrito, puede ser guardado en un fichero (por ejemplo, adivina.py) y es ejecutable directamente en IDLE pulsando F5 en la ventana de edición:

Ejecución en el propio IDLE usando F5 desde el editor de programas
Ejecución en el propio IDLE usando F5 desde el editor de programas

También se puede ejecutar en Windows desde el símbolo de sistema, que puedes encontrar pulsando [Tecla de Windows] + R y escribiendo cmd. Una vez en el símbolo del sistema deberás ejecutarlo anteponiendo la ruta completa al intérprete de Python, o python si has seguido todas las instrucciones del final del artículo que trataba la línea de comandos.

Ejecución en Windows
Ejecución en Windows

Para poderlo ejecutar en tu PC con Linux o en la Raspberry Pi, deberás escribir al principio de todo, como primera línea, #!/usr/bin/python3 ; en el Mac OS X deberás escribir por su parte algo similar (puede cambiar la versión de Python) a #!<strong>/Library/Frameworks/Python.framework/Versions/3.4/bin/python3</strong>. En cualquier caso, puedes obtener la ruta del ejecutable de Python 3, que sería lo que va después del signo de admiración, ejecutando en un terminal which python3. Para ejecutarlo en cualquiera de estas tres alternativas recuerda darle permisos de ejecución al fichero donde guardes el programa (por ejemplo, adivina.py) con la sentencia chmod +x adivina.py desde el terminal.


Podéis dejarme cualquier comentario en esta misma entrada, o enviándome cualquier comentario a tavés del formulario de contacto y la dirección de correo que allí os indico. Recordad también que PItando está tanto en twitter, como en Facebook, y en Google+ también podéis seguir mis publicaciones, incluyendo las del podcast (iTunesiVooxRSS).

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *