Tin tức và phân tích của tất cả các thiết bị di động

Xây dựng ứng dụng bảng cửu chương trong python sử dụng OOP

Trong bài viết này, bạn sẽ xây dựng một ứng dụng bảng cửu chương bằng cách sử dụng sức mạnh của lập trình hướng đối tượng (OOP) trong Python.

Bạn sẽ thực hành các khái niệm chính về OOP và cách sử dụng chúng trong một ứng dụng đầy đủ chức năng.

Python là ngôn ngữ lập trình đa mô hình, có nghĩa là với tư cách là lập trình viên, chúng ta có thể chọn tùy chọn tốt nhất cho từng tình huống và vấn đề. Khi chúng ta nói về lập trình hướng đối tượng, chúng ta muốn nói đến một trong những mô hình được sử dụng nhiều nhất để phát triển các ứng dụng có thể mở rộng trong những thập kỷ gần đây.

Khái niệm cơ bản về OOP

Chúng ta sẽ xem nhanh khái niệm OOP quan trọng nhất trong Python, đó là các lớp.

Một lớp là một khuôn mẫu nơi chúng ta xác định cấu trúc và hành vi của các đối tượng. Mẫu này cho phép chúng tôi tạo các Trường hợp không gì khác hơn là các đối tượng riêng lẻ được tạo theo thành phần lớp.

Một lớp sách đơn giản với các thuộc tính tiêu đề và màu sắc sẽ được định nghĩa như sau.

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

Nếu chúng ta muốn tạo các thể hiện của lớp sách, chúng ta cần gọi lớp đó và truyền đối số cho nó.

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

Một đại diện tốt cho chương trình hiện tại của chúng tôi sẽ là:

Điều tuyệt vời là khi chúng tôi kiểm tra loại đối tượng blue_book và green_book, chúng tôi nhận được “Sách”.

# Printing the type of the books

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

Sau khi hiểu rõ ràng về các khái niệm này, chúng ta có thể tiến hành xây dựng dự án 😃.

Tuyên bố thiết kế

Làm việc với tư cách là lập trình viên/nhà phát triển, phần lớn thời gian của chúng tôi không dành để viết mã cho một ngăn xếp mới mà chúng tôi chỉ dành một phần ba thời gian để viết hoặc tái cấu trúc mã.

Hai phần ba còn lại dành để đọc mã của người khác và phân tích vấn đề mà chúng tôi đang giải quyết.

Vì vậy, đối với dự án này, tôi sẽ tạo một bản mô tả vấn đề và chúng tôi sẽ phân tích cách tạo ứng dụng của chúng tôi từ đó. Do đó, chúng tôi thực hiện toàn bộ quy trình, từ suy nghĩ về giải pháp đến áp dụng nó vào mã.

Một giáo viên tiểu học muốn có một trò chơi để kiểm tra kỹ năng nhân của học sinh từ 8 lên đến 10 năm.

Trò chơi phải có một hệ thống cuộc sống và điểm mà học sinh bắt đầu với 3 cuộc sống và phải đạt được một số điểm nhất định để giành chiến thắng. Chương trình phải hiển thị thông báo “thua cuộc” nếu học sinh kiệt sức cả đời.

Trò chơi phải có hai chế độ, phép nhân ngẫu nhiên và phép nhân theo bảng.

Việc đầu tiên nên cung cấp cho học sinh một phép nhân ngẫu nhiên từ 1 đến 10 và anh ấy / cô ấy phải trả lời đúng để ghi điểm. Nếu không, học sinh sẽ mất mạng và trò chơi tiếp tục. Học sinh chỉ thắng khi ghi điểm 5 điểm.

Chế độ thứ hai phải hiển thị bảng cửu chương từ 1 đến 10, trong đó học sinh phải nhập kết quả của phép nhân tương ứng. Nếu học sinh thất bại 3 nhiều lần, anh ta thua, nhưng nếu anh ta hoàn thành hai bàn, trò chơi kết thúc.

Tôi biết rằng các yêu cầu có thể cao hơn một chút, nhưng tôi hứa rằng trong bài viết này, chúng tôi sẽ giải quyết chúng 😁.

Phân chia và chinh phục

Kỹ năng quan trọng nhất trong lập trình là giải quyết vấn đề. Điều này là do bạn cần có kế hoạch trước khi bắt đầu hack mã.

Tôi luôn khuyên bạn nên giải quyết một vấn đề lớn hơn và chia nó thành những vấn đề nhỏ hơn để có thể giải quyết một cách dễ dàng và hiệu quả.

Vì vậy, nếu bạn muốn tạo một trò chơi, hãy bắt đầu bằng cách chia nó thành những phần quan trọng nhất. Các bài toán con này sẽ dễ giải quyết hơn nhiều.

Đó là khi bạn có thể hiểu rõ về cách thực thi và tích hợp mọi thứ vào mã của mình.

Vì vậy, hãy vẽ sơ đồ trò chơi sẽ như thế nào.

Đồ họa này hiển thị các mối quan hệ giữa các đối tượng trong ứng dụng của chúng tôi. Như bạn có thể thấy, hai đối tượng chính là phép nhân ngẫu nhiên và phép nhân bảng. Và điểm chung duy nhất của chúng là thuộc tính Points và Life.

Với tất cả thông tin này trong tâm trí, chúng ta hãy lấy mã.

Tạo một lớp trò chơi Parent

Khi chúng tôi làm việc với lập trình hướng đối tượng, chúng tôi tìm kiếm cách rõ ràng nhất để tránh lặp lại mã. Nó được gọi là DRY (đừng lặp lại chính mình).

Lưu ý: mục tiêu này không liên quan đến việc viết ít dòng mã hơn (không thể đo lường chất lượng mã theo khía cạnh này), mà liên quan đến việc trừu tượng hóa logic được sử dụng phổ biến nhất.

Theo ý tưởng trước đó, lớp cha của ứng dụng của chúng ta phải xác định cấu trúc và hành vi mong muốn của hai lớp còn lại.

Hãy xem nó sẽ được thực hiện như thế nào.

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} livesn")

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

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

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

Wow, đó có vẻ là một lớp học khá lớn. Hãy để tôi giải thích nó một cách sâu sắc.

Trước hết, hãy hiểu các thuộc tính của lớp và hàm tạo.

Về cơ bản các thuộc tính lớp là các biến được tạo bên trong lớp nhưng bên ngoài hàm tạo hoặc bất kỳ phương thức nào.

Trong khi các thuộc tính thể hiện là các biến chỉ được tạo bên trong hàm tạo.

Sự khác biệt chính giữa hai là phạm vi. tức là các thuộc tính lớp có thể truy cập được từ cả đối tượng thể hiện và lớp. Mặt khác, các thuộc tính thể hiện chỉ có thể truy cập được từ đối tượng thể hiện.

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

Một bài viết khác có thể đi sâu vào chủ đề này. Hãy kết nối để đọc nó.

Hàm get_numeric_input được sử dụng để ngăn người dùng nhập bất kỳ dữ liệu nào không phải là số. Như bạn có thể thấy, phương pháp này được thiết kế để tiếp tục hỏi người dùng cho đến khi họ nhận được số. Chúng tôi sẽ sử dụng nó sau này trong các lớp học của trẻ.

Các phương pháp in giúp chúng tôi không phải lặp lại cùng một bản in mỗi khi xảy ra sự kiện trong trò chơi.

Cuối cùng, phương thức run chỉ là một trình bao bọc mà các lớp nhân ngẫu nhiên và bảng nhân sẽ sử dụng để tương tác với người dùng và làm cho mọi thứ hoạt động.

Tạo lớp con

Bây giờ chúng ta đã tạo lớp cha này để xác định cấu trúc và một số chức năng của ứng dụng, đã đến lúc xây dựng các lớp chế độ trò chơi thực tế bằng cách sử dụng sức mạnh của tính kế thừa.

lớp nhân ngẫu nhiên

Lớp này sẽ chạy “chế độ đầu tiên” của trò chơi của chúng tôi. Tất nhiên, nó sẽ sử dụng một mô-đun ngẫu nhiên, mô-đun này sẽ cung cấp cho chúng tôi khả năng cung cấp cho người dùng các thao tác ngẫu nhiên từ 1 đến 10. Đây là một bài viết xuất sắc về ngẫu nhiên (và các mô-đun quan trọng khác) 😉.

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

    description = "In this game you must answer the random multiplication correctlynYou 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 correctn")
                
                # Adds a point
                self.points += 1
            else:
                print("nSorry, your answer is incorrectn")

                # 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()

Đây là một lớp đại chúng khác 😅. Nhưng như tôi đã nói trước đây, vấn đề không phải là số lượng dòng mà nó cần, mà là mức độ dễ đọc và hiệu quả của nó. Và điều tốt nhất về Python là nó cho phép các lập trình viên tạo ra mã rõ ràng và dễ đọc như thể họ đang nói tiếng Anh bình thường.

Các lớp này có một điều có thể làm bạn bối rối, nhưng tôi sẽ giải thích nó một cách đơn giản nhất có thể.

    # 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)

Hàm tạo của lớp con gọi một siêu hàm cũng tham chiếu đến lớp cha (BaseGame). Về cơ bản, nó nói với Python:

Điền giá trị vào thuộc tính “points_to_win” của lớp cha 5!

Không cần thiết phải đặt self trong phần super().__init__() chỉ vì chúng ta đang gọi super bên trong hàm tạo, điều này sẽ gây ra sự dư thừa.

Chúng ta cũng sử dụng hàm super trong phương thức run và chúng ta sẽ xem điều gì xảy ra trong đoạn mã này.

    # 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()
        
        .....

Như bạn có thể thấy phương thức run trong lớp cha, hãy in thông báo chào mừng và mô tả. Nhưng bạn nên giữ chức năng này cũng như thêm các chức năng bổ sung vào các lớp con. Theo đó, chúng tôi sử dụng super để chạy tất cả mã của phương thức gốc trước khi chạy mục tiếp theo.

Phần thứ hai của chức năng rune khá đơn giản. Hỏi người dùng một số với thông báo về hoạt động mà anh ta phải trả lời. Sau đó, kết quả được so sánh với phép nhân thực tế và nếu chúng bằng nhau, một điểm sẽ được cộng nếu chúng không trả lời 1 đời sống.

Điều đáng nói là chúng ta sử dụng vòng lặp while-else. Điều này nằm ngoài phạm vi của bài viết này, nhưng tôi sẽ đăng nó trong vài ngày tới.

Cuối cùng, get_random_numbers sử dụng hàm random.randint, hàm này trả về một số nguyên ngẫu nhiên từ một phạm vi đã chỉ định. Sau đó, nó trả về một bộ gồm hai số nguyên ngẫu nhiên.

lớp nhân ngẫu nhiên

“Chế độ thứ hai” phải hiển thị trò chơi ở định dạng bảng nhân và đảm bảo rằng người dùng trả lời đúng ít nhất 2 máy tính bảng.

Để làm điều này, chúng ta sẽ sử dụng lại siêu năng lực và sửa đổi thuộc tính point_to_win của lớp cha thành 2.

class TableMultiplication(BaseGame):

    description = "In this game you must resolve the complete multiplication table correctlynYou 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()

Như bạn có thể thấy, chúng tôi chỉ sửa đổi phương thức chạy của lớp này. Đây là sự kỳ diệu của sự kế thừa, chúng tôi viết logic một lần mà chúng tôi sử dụng ở nhiều nơi và quên nó đi 😅.

Trong phương thức run, chúng ta sử dụng vòng lặp for để lấy các số từ 1 đến 10 và chúng tôi đã xây dựng thao tác được hiển thị cho người dùng.

Một lần nữa, nếu hết số mạng hoặc đạt đến số điểm cần thiết để giành chiến thắng, vòng lặp while sẽ bị ngắt và thông báo thắng hoặc thua sẽ được hiển thị.

CÓ, chúng tôi đã tạo hai chế độ trò chơi, nhưng cho đến nay, nếu chúng tôi chạy chương trình, sẽ không có gì xảy ra.

Vì vậy, hãy kết thúc chương trình bằng cách thực hiện lựa chọn chế độ và khởi tạo các lớp tùy thuộc vào lựa chọn đó.

Hiện thực hóa sự lựa chọn

Người dùng sẽ có thể chọn ở chế độ nào anh ta muốn chơi. Vì vậy, hãy xem làm thế nào để thực hiện nó.

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()

Đầu tiên, chúng tôi yêu cầu người dùng chọn giữa các chế độ 1 hoặc 2. Nếu đầu vào không hợp lệ, tập lệnh sẽ ngừng hoạt động. Nếu người dùng chọn chế độ thứ nhất thì chương trình sẽ chạy chế độ trò chơi Nhân ngẫu nhiên, nếu người dùng chọn chế độ thứ hai thì chương trình sẽ chạy chế độ nhân mảng.

Đây là những gì nó sẽ trông như thế nào.

Đăng kí

Xin chúc mừng, bạn vừa xây dựng một ứng dụng python hướng đối tượng.

Tất cả mã có sẵn trong kho lưu trữ Github.

Trong bài viết này, bạn đã học được:

  • Sử dụng hàm tạo lớp python
  • Tạo một ứng dụng chức năng với OOP
  • Sử dụng các hàm siêu trong các lớp python
  • Áp dụng các khái niệm kế thừa cơ bản
  • Thực hiện các thuộc tính lớp và cá thể

Mã hóa vui vẻ 👨‍💻

Sau đó khám phá các IDE Python tốt nhất để tăng năng suất của bạn.