Geekflare cuenta con el apoyo de nuestra audiencia. Podemos ganar comisiones de afiliados comprando enlaces en este sitio.
Comparte en:

Cree una aplicación de tabla de multiplicar de Python con OOP

Cree una aplicación Python con OOP
Escáner de seguridad de aplicaciones web Invicti – la única solución que ofrece verificación automática de vulnerabilidades con Proof-Based Scanning™.

En este artículo, creará un  Aplicación de tablas de multiplicar, utilizando el poder de la programación orientada a objetos (OOP) en Python.

Practicarás los conceptos principales de OOPy cómo usarlos en una aplicación completamente funcional.

Python es un lenguaje de programación multiparadigma, lo que significa que nosotros como desarrolladores podemos elegir la mejor opción para cada situación y problema. Cuando hablamos de Programación Orientada a Objetos, nos referimos a uno de los paradigmas más utilizados para construir aplicaciones escalables, en las últimas décadas.

The basics of OOP

Vamos a echar un vistazo rápido al concepto más importante de POO en Python, las clases.

A clase es una plantilla en la que definimos la estructura y el comportamiento de los objetos. Esa plantilla nos permite crear Instancias, que no son más que objetos individuales hechos siguiendo la composición de la clase.

Una clase de libro simple, con los atributos de título y color, se definiría de la siguiente manera.

class Book:
    def __init__(self, title, color):
        self.title = title
        self.color = color

Si queremos crear instancias del libro de la clase, debemos llamar a la clase y pasar argumentos a la misma.

# Instance objects of Book class
blue_book = Book("The blue kid", "Blue")
green_book = Book("The frog story", "Green")

Una buena representación de nuestro programa actual sería:

Clase.png

Lo asombroso es que cuando comprobamos el tipo de libro Azul y libro Verde  instancias, obtenemos "Libro".

# Printing the type of the books

print(type(blue_book))
# <class '__main__.Book'>
print(type(green_book))
# <class '__main__.Book'>

Después de tener estos conceptos muy claros, podemos comenzar a construir el proyecto 😃.

Project statement

Mientras trabaja como desarrolladores / programadores, la mayor parte del tiempo no se dedica a escribir código, según la pila de noticias solo dedicamos un tercio de nuestro tiempo a escribir o refactorizar código.

Pasamos los otros dos tercios leyendo el código de otros y analizando el problema estamos trabajando en.

Entonces, para este proyecto, generaré una declaración de problema y analizaremos cómo crear nuestra aplicación a partir de ella. Como resultado, estamos haciendo el proceso completo, desde pensar en la solución hasta aplicarla con código.

Una maestra de primaria quiere un juego para probar las habilidades de multiplicación de los estudiantes de 8 a 10 años.

El juego debe tener un sistema de vidas y puntos, donde el estudiante comienza con 3 vidas y debe alcanzar una cierta cantidad de puntos para ganar. El programa debe mostrar un mensaje de "perder" si el estudiante agota toda su vida.

El juego debe tener dos modos, multiplicaciones aleatorias y multiplicaciones de tablas.

El primero debe darle al alumno una multiplicación aleatoria del 1 al 10, y debe responder correctamente para ganar un punto. Si eso no ocurre, el estudiante pierde un live y el juego continúa. El alumno solo gana cuando alcanza los 5 puntos.

El segundo modo debe mostrar una tabla de multiplicar del 1 al 10, donde el estudiante debe ingresar el resultado de la multiplicación respectiva. Si el alumno falla 3 veces pierde, pero si completa dos mesas, el juego termina.

Sé que los requisitos pueden ser un poco mayores, pero te prometo que los resolveremos en este artículo 😁.

Divide and conquer

La habilidad más importante en la programación es la resolución de problemas. Esto se debe a que necesita tener un plan antes de comenzar a comenzar. piratear el código.

Siempre sugiero tomar el problema más grande y dividirlo en otros más pequeños que puedan resolverse de manera fácil y eficiente.

Así que si necesitas crear un juego, comience por dividirlo en las partes más importantes. Estos subproblemas serán mucho más fáciles de resolver.

En ese momento, puede tener la claridad de cómo ejecutar e integrar todo con el código.

Así que hagamos un gráfico de cómo se vería el juego.

divide y conquistar.png

Este gráfico establece las relaciones entre los objetos de nuestra aplicación. Como puede ver, los dos objetos principales son Multiplicación aleatoria y Multiplicación de tablas. Y lo único que comparten son los atributos Puntos y  Vive.

Teniendo toda esta información en mente, entremos en el código.

Creating the Parent game class

Cuando trabajamos con programación orientada a objetos, buscamos la forma más limpia de evitar la repetición de código. Se llama SECO (no te repitas).

Nota: Este objetivo no está relacionado con escribir menos líneas de código (la calidad del código no debe medirse por ese aspecto) sino abstraer las más utilizadas lógica.

Según la idea anterior, la clase padre de nuestra aplicación debe establecer la estructura y el comportamiento deseado de las otras dos clases.

Veamos cómo se haría.

class BaseGame:

    # Lenght which the message is centered
    message_lenght = 60
    
    description = ""    
        
    def __init__(self, points_to_win, n_lives=3):
        """Base game class

        Args:
            points_to_win (int): the points the game will need to be finished 
            n_lives (int): The number of lives the student have. Defaults to 3.
        """
        self.points_to_win = points_to_win

        self.points = 0
        
        self.lives = n_lives

    def get_numeric_input(self, message=""):

        while True:
            # Get the user input
            user_input = input(message) 
            
            # If the input is numeric, return it
            # If it isn't, print a message and repeat
            if user_input.isnumeric():
                return int(user_input)
            else:
                print("The input must be a number")
                continue     
             
    def print_welcome_message(self):
        print("PYTHON MULTIPLICATION GAME".center(self.message_lenght))

    def print_lose_message(self):
        print("SORRY YOU LOST ALL OF YOUR LIVES".center(self.message_lenght))

    def print_win_message(self):
        print(f"CONGRATULATION YOU REACHED {self.points}".center(self.message_lenght))
        
    def print_current_lives(self):
        print(f"Currently you have {self.lives} lives\n")

    def print_current_score(self):
        print(f"\nYour score is {self.points}")

    def print_description(self):
        print("\n\n" + self.description.center(self.message_lenght) + "\n")

    # Basic run method
    def run(self):
        self.print_welcome_message()
        
        self.print_description()

Vaya, esta parece una clase bastante grande. Déjame explicarlo en profundidad.

Primero que nada, entendamos el atributos de clase y el constructor.

Constructor-juego-base.png

Básicamente, atributos de clase, son variables creadas dentro de la clase, pero fuera del constructor o de cualquier método.

Aunque la atributos de instancia son variables creadas solo dentro del constructor.

La principal diferencia entre estos dos es el alcance. es decir, los atributos de clase son accesibles tanto desde un objeto de instancia como desde la clase. Por otro lado, los atributos de instancia solo son accesibles desde un objeto de instancia.

game = BaseGame(5)

# Accessing game message lenght class attr from class
print(game.message_lenght) # 60

# Accessing the message_lenght class attr from class
print(BaseGame.message_lenght)  # 60

# Accessing the points instance attr from instance
print(game.points) # 0

# Accesing the points instance attribute from class
print(BaseGame.points) # Attribute error

Otro artículo puede profundizar en este tema. Mantente en contacto para leerlo.

El get_numeric_input La función se utiliza para evitar que el usuario proporcione una entrada que no sea numérica. Como puede notar, este método está diseñado para preguntar al usuario hasta que obtenga una entrada numérica. Lo usaremos más adelante en las clases del niño.

Entrada-juego-base.png

La impresión métodos nos permite guardar la repetición de imprimir lo mismo cada vez que ocurre un evento en el juego.

Por último, pero no menos importante, el corrida El método es solo una envoltura que el Multiplicación aleatoria y Multiplicación de tablas Las clases utilizarán para interactuar con el usuario y hacer que todo sea funcional.

Base-juego-ejecutar.png

Creating the child’s classes

Una vez que hemos creado esa clase principal, que establece la estructura y algunas de las funciones de nuestra aplicación, es hora de crear las clases reales del modo de juego, utilizando el poder de herencia.

Clase de multiplicación aleatoria

Esta clase ejecutará el "primer modo" de nuestro juego. Va a utilizar el azar módulo por supuesto, que nos dará la posibilidad de pedir al usuario operaciones aleatorias del 1 al 10. Aquí es un excelente artículo sobre los módulos aleatorios (y otros módulos importantes) 😉.

import random # Module for random operations
class RandomMultiplication(BaseGame):

    description = "In this game you must answer the random multiplication correctly\nYou win if you reach 5 points, or lose if you lose all your lives"

    def __init__(self):
        # The numbers of points needed to win are 5
        # Pass 5 "points_to_win" argument
        super().__init__(5)

    def get_random_numbers(self):

        first_number = random.randint(1, 10)
        second_number = random.randint(1, 10)

        return first_number, second_number
        
    def run(self):
        
        # Call the upper class to print the welcome messages
        super().run()
        

        while self.lives > 0 and self.points_to_win > self.points:
            # Gets two random numbers
            number1, number2 = self.get_random_numbers()

            operation = f"{number1} x {number2}: "

            # Asks the user to answer that operation 
            # Prevent value errors
            user_answer = self.get_numeric_input(message=operation)

            if user_answer == number1 * number2:
                print("\nYour answer is correct\n")
                
                # Adds a point
                self.points += 1
            else:
                print("\nSorry, your answer is incorrect\n")

                # Substracts a live
                self.lives -= 1
            
            self.print_current_score()
            self.print_current_lives()
            
        # Only get executed when the game is finished
        # And none of the conditions are true
        else:
            # Prints the final message
            
            if self.points >= self.points_to_win:
                self.print_win_message()
            else:
                self.print_lose_message()

Aquí hay otra clase masiva 😅. Pero como dije antes, no es el número de líneas que toma, es lo legible y eficiente que es. Y lo mejor de Python es que permite a los desarrolladores crear código limpio y legible como si estuvieran hablando en inglés normal.

Esta clase tiene una cosa que puede confundirte, pero la explicaré de la manera más simple posible.

    # Parent class
    def __init__(self, points_to_win, n_lives=3):
        "...
    # Child class
    def __init__(self):
        # The numbers of points needed to win are 5
        # Pass 5 "points_to_win" argument
        super().__init__(5)

El constructor de la clase secundaria está llamando al súper función que, al mismo tiempo, se refiere a la clase principal (BaseGame). Básicamente le dice a Python:

¡Complete el atributo "points_to_win" de la clase principal con 5!

No es necesario poner yo, dentro de  super().__init__() part solo porque estamos llamando a super dentro del constructor, y resultaría en redundante.

También estamos usando el súper función en el método de ejecución, y veremos qué está sucediendo en ese fragmento de código.

    # Basic run method
    # Parent method
    def run(self):
        self.print_welcome_message()
        
        self.print_description()
    def run(self):
        
        # Call the upper class to print the welcome messages
        super().run()
        
        .....

Como puede observar el método de ejecución en la clase principal, imprima el mensaje de bienvenida y descripción. Pero es una buena idea mantener esa funcionalidad y también agregar otras adicionales en las clases secundarias. De acuerdo con eso, usamos súper  para ejecutar todo el código del método padre antes de ejecutar la siguiente pieza.

La otra parte de la función de ejecución es bastante sencilla. Pide al usuario un número con el mensaje de la operación que debe responder. Luego se compara el resultado con la multiplicación real y si son iguales se suma un punto, si no se quitan 1 vida.

Vale la pena decir que estamos usando bucles while-else. Esto excede el alcance de este artículo, pero publicaré uno al respecto en unos días.

Finalmente, obtener_números_aleatorios, usa la función random.randint, que devuelve un número entero aleatorio dentro del rango especificado. Luego devuelve una tupla de dos enteros aleatorios.

Clase de multiplicación aleatoria

El "segundo modo", debe mostrar el juego en formato de tabla de multiplicar, y asegurarse de que el usuario responde correctamente al menos 2 tablas.

Para ese propósito, usaremos nuevamente el poder de súper y modificar el atributo de la clase padre puntos_para_ganar a 2.

class TableMultiplication(BaseGame):

    description = "In this game you must resolve the complete multiplication table correctly\nYou win if you solve 2 tables"
    
    def __init__(self):
        # Needs to complete 2 tables to win
        super().__init__(2)

    def run(self):

        # Print welcome messages
        super().run()

        while self.lives > 0 and self.points_to_win > self.points:
            # Gets two random numbers
            number = random.randint(1, 10)            

            for i in range(1, 11):
                
                if self.lives <= 0:
                    # Ensure that the game can't continue 
                    # if the user depletes the lives

                    self.points = 0
                    break 
                
                operation = f"{number} x {i}: "

                user_answer = self.get_numeric_input(message=operation)

                if user_answer == number * i:
                    print("Great! Your answer is correct")
                else:
                    print("Sorry your answer isn't correct") 

                    self.lives -= 1

            self.points += 1
            
        # Only get executed when the game is finished
        # And none of the conditions are true
        else:
            # Prints the final message
            
            if self.points >= self.points_to_win:
                self.print_win_message()
            else:
                self.print_lose_message()

Como puede darse cuenta, solo estamos modificando el método de ejecución de esta clase. Esa es la magia de la herencia, escribimos una vez la lógica que usamos en varios lugares y nos olvidamos de ella 😅.

En el método de ejecución, usamos un bucle for para obtener los números del 1 al 10 y construimos la operación que se muestra al usuario.

Una vez más, si las vidas se agotan o se alcanzan los puntos necesarios para ganar, el ciclo while se romperá y se mostrará el mensaje de ganar o perder.

SÍ, creamos los dos modos del juego, pero hasta ahora si ejecutamos el programa no pasará nada.

Así que finalicemos el programa implementando la opción de modo y creando instancias de las clases dependiendo de esa elección.

Choice implementation

El usuario podrá elegir qué modo quiere jugar. Entonces veamos cómo implementarlo.

if __name__ == "__main__":

    print("Select Game mode")

    choice = input("[1],[2]: ")

    if choice == "1":
        game = RandomMultiplication()
    elif choice == "2":
        game = TableMultiplication()
    else:
        print("Please, select a valid game mode")
        exit()

    game.run()

Primero, le pedimos al usuario que elija entre los modos 1 o 2. Si la entrada no es válida, el script deja de ejecutarse. Si el usuario selecciona el primer modo, el programa ejecutará el Multiplicación aleatoria modo de juego, y si selecciona el segundo, el Multiplicación de tablas se ejecutará el modo.

Así es como se vería.

juego.png

Para concluir

Felicitaciones, solo construir una aplicación Python con Programación Orientada a Objetos.

Todo el código está disponible en el Repositorio de Github.

En este artículo aprendiste a:

  • Usa constructores de clases de Python
  • Crea una aplicación funcional con OOP
  • Usa la superfunción en clases de Python
  • Aplicar los conceptos básicos de herencia
  • Implementar atributos de clase e instancia

Feliz codificación 👨‍💻

A continuación, explore algunos de los mejor IDE de Python para una mejor productividad.

Gracias a nuestros patrocinadores
Más lecturas interesantes sobre el desarrollo
Impulse su negocio
Algunas de las herramientas y servicios para ayudar a que su negocio crezca.
  • Invicti utiliza Proof-Based Scanning™ para verificar automáticamente las vulnerabilidades identificadas y generar resultados procesables en cuestión de horas.
    Prueba Invicti
  • Web scraping, proxy residencial, administrador de proxy, desbloqueador web, rastreador de motores de búsqueda y todo lo que necesita para recopilar datos web.
    Prueba Brightdata
  • Semrush es una solución de marketing digital todo en uno con más de 50 herramientas en SEO, redes sociales y marketing de contenido.
    Prueba Semrush
  • Intruder es un escáner de vulnerabilidades en línea que encuentra debilidades de ciberseguridad en su infraestructura, para evitar costosas filtraciones de datos.
    Intente Intruder