Tháp Hà Nội Python tuple
Cho đến nay, cuốn sách này đã dạy cho bạn các kỹ thuật để viết mã Pythonic có thể đọc được. Hãy áp dụng những kỹ thuật này vào thực tế bằng cách xem mã nguồn của hai trò chơi dòng lệnh. Tháp Hà Nội và Four-in-a-Row Show Các dự án này ngắn và dựa trên văn bản để giữ cho phạm vi của chúng nhỏ, nhưng chúng thể hiện các nguyên tắc mà cuốn sách này phác thảo cho đến nay. Tôi đã định dạng mã bằng công cụ Đen được mô tả trong “Đen. Trình định dạng mã kiên quyết” ở trang 53. Tôi chọn tên biến theo hướng dẫn ở Chương 4. Tôi đã viết mã theo phong cách Pythonic, như được mô tả trong Chương 6. Ngoài ra, tôi đã viết nhận xét và chuỗi tài liệu như được mô tả trong Chương 11. Bởi vì các chương trình nhỏ và chúng ta chưa đề cập đến lập trình hướng đối tượng (OOP), nên tôi đã viết hai dự án này mà không có các lớp mà bạn sẽ tìm hiểu thêm trong các Chương 15 đến 17 Chương này trình bày mã nguồn đầy đủ cho hai dự án này cùng với phân tích chi tiết về mã. Những giải thích này không giải thích nhiều về cách thức hoạt động của mã (hiểu cơ bản về cú pháp Python là tất cả những gì cần thiết cho điều đó), nhưng tại sao mã được viết theo cách của nó. Tuy nhiên, các nhà phát triển phần mềm khác nhau có ý kiến khác nhau về cách viết mã và những gì họ cho là Pythonic. Bạn hoàn toàn có thể đặt câu hỏi và phê bình mã nguồn trong các dự án này Sau khi đọc qua một dự án trong cuốn sách này, tôi khuyên bạn nên tự gõ mã và chạy chương trình một vài lần để hiểu cách chúng hoạt động. Sau đó cố gắng thực hiện lại các chương trình từ đầu. Mã của bạn không nhất thiết phải khớp với mã trong chương này, nhưng việc viết lại mã sẽ cho bạn cảm giác về việc ra quyết định và đánh đổi thiết kế mà lập trình yêu cầu Tháp Hà NộiCâu đố Tháp Hà Nội sử dụng một chồng đĩa có kích thước khác nhau. Các đĩa có lỗ ở tâm, vì vậy bạn có thể đặt chúng trên một trong ba cực (Hình 14-1). Để giải câu đố, người chơi phải di chuyển chồng đĩa sang một trong các cực khác. Có ba hạn chế
Hình 14-1. Một bộ xếp hình Tháp Hà Nội vật lý Giải câu đố này là một vấn đề khoa học máy tính phổ biến được sử dụng để dạy các thuật toán đệ quy. Chương trình của chúng tôi sẽ không giải được câu đố này; . Bạn có thể tìm thêm thông tin về Tháp Hà Nội tại https. // vi. wikipedia. org/wiki/Tower_of_Hanoi Đầu raChương trình Tháp Hà Nội hiển thị các tòa tháp dưới dạng nghệ thuật ASCII bằng cách sử dụng các ký tự văn bản để biểu thị các đĩa. Nó có thể trông thô sơ so với các ứng dụng hiện đại, nhưng cách tiếp cận này giúp việc triển khai trở nên đơn giản, bởi vì chúng tôi chỉ cần các lệnh gọi 5 và 6 để tương tác với người dùng. Khi bạn chạy chương trình, đầu ra sẽ giống như sau. Văn bản người chơi nhập được in đậm
Với n đĩa, cần tối thiểu 2n – 1 nước đi để giải Tháp Hà Nội. Vì vậy, tháp năm đĩa này cần 31 bước. AC, AB, CB, AC, BA, BC, AC, AB, CB, CA, BA, CB, AC, AB, CB, AC, BA, BC, AC, BA, CB, CA, BA, BC, AC, . Nếu bạn muốn thử thách lớn hơn để tự mình giải quyết, bạn có thể tăng biến 7 trong chương trình từ 8 lên 9Mã nguồnMở một tệp mới trong trình chỉnh sửa hoặc IDE của bạn và nhập mã sau. Lưu với tên towerofhanoi. py
Chạy chương trình này và chơi một vài trò chơi để biết chương trình này làm gì trước khi đọc phần giải thích về mã nguồn. Để kiểm tra lỗi chính tả, hãy sao chép và dán nó vào công cụ tìm khác biệt trực tuyến tại https. // phát minh với trăn. com/ngoài/khác biệt/ Viết mãChúng ta hãy xem xét kỹ hơn mã nguồn để xem nó tuân theo các mẫu và phương pháp hay nhất được mô tả trong cuốn sách này như thế nào Chúng tôi sẽ bắt đầu ở đầu chương trình
Chương trình bắt đầu với một nhận xét nhiều dòng đóng vai trò là chuỗi tài liệu cho mô-đun 0. Hàm 1 tích hợp sẽ sử dụng thông tin này để mô tả mô-đun 0Bạn có thể thêm nhiều từ hơn, thậm chí cả các đoạn thông tin vào chuỗi tài liệu của mô-đun nếu bạn cần. Tôi chỉ viết một lượng nhỏ ở đây vì chương trình rất đơn giản Sau chuỗi tài liệu mô-đun là các câu lệnh 2
Định dạng đen những câu lệnh này dưới dạng các câu lệnh riêng biệt chứ không phải là một câu lệnh duy nhất, chẳng hạn như 3. Điều này làm cho việc thêm hoặc xóa các mô-đun đã nhập dễ dàng nhìn thấy hơn trong các hệ thống kiểm soát phiên bản, chẳng hạn như Git, giúp theo dõi các thay đổi mà lập trình viên thực hiệnTiếp theo, chúng tôi xác định các hằng số chương trình này sẽ cần ________số 8Chúng tôi xác định những thứ này ở gần đầu tệp để nhóm chúng lại với nhau và biến chúng thành các biến toàn cầu. Chúng tôi đã viết tên của họ bằng chữ viết hoa 4 để đánh dấu họ là hằng sốHằng số 7 cho biết câu đố có bao nhiêu đĩa. Biến 6 là một ví dụ về danh sách chứa tháp đã giải. nó chứa mọi đĩa có đĩa lớn nhất ở dưới cùng và đĩa nhỏ nhất ở trên cùng. Chúng tôi tạo giá trị này từ giá trị 7 và đối với năm đĩa, đó là 8Lưu ý rằng không có gợi ý loại nào trong tệp này. Lý do là chúng ta có thể suy ra kiểu của tất cả các biến, tham số và giá trị trả về từ mã. Ví dụ: chúng tôi đã gán hằng số 7 giá trị số nguyên 8. Từ đó, các trình kiểm tra kiểu, chẳng hạn như Mypy, sẽ suy ra rằng 7 chỉ nên chứa các số nguyênChúng tôi xác định hàm 32 mà chương trình gọi ở gần cuối tệp 3Các chức năng cũng có thể có các tài liệu. Lưu ý chuỗi tài liệu cho 32 bên dưới câu lệnh 34. Bạn có thể xem chuỗi tài liệu này bằng cách chạy 35 và 36 từ trình bao tương tácTiếp theo, chúng tôi viết một nhận xét mô tả rộng rãi cấu trúc dữ liệu mà chúng tôi sử dụng để biểu thị tòa tháp, bởi vì nó tạo thành cốt lõi của cách thức hoạt động của chương trình này 9Chúng tôi sử dụng danh sách 6 làm ngăn xếp, một trong những cấu trúc dữ liệu đơn giản nhất trong phát triển phần mềm. Ngăn xếp là một danh sách có thứ tự các giá trị được thay đổi chỉ thông qua việc thêm (còn gọi là đẩy) hoặc loại bỏ (còn gọi là bật lên) các giá trị khỏi đỉnh ngăn xếp. Cấu trúc dữ liệu này đại diện hoàn hảo cho tòa tháp trong chương trình của chúng tôi. Chúng ta có thể biến danh sách Python thành ngăn xếp nếu chúng ta sử dụng phương thức 38 để đẩy và phương thức 39 để bật và tránh thay đổi danh sách theo bất kỳ cách nào khác. Chúng tôi sẽ coi phần cuối của danh sách là phần trên cùng của ngăn xếpMỗi số nguyên trong danh sách 90 đại diện cho một đĩa có kích thước nhất định. Ví dụ: trong một trò chơi có năm đĩa, danh sách 8 sẽ đại diện cho một chồng đĩa đầy đủ từ đĩa lớn nhất ( 8) ở dưới cùng đến đĩa nhỏ nhất ( 93) ở trên cùngLưu ý rằng nhận xét của chúng tôi cũng cung cấp các ví dụ về ngăn xếp tháp hợp lệ và không hợp lệ Bên trong hàm 32, chúng tôi viết một vòng lặp vô hạn để chạy một lượt trò chơi giải đố của chúng tôi 8Trong một lượt, người chơi xem trạng thái hiện tại của các tòa tháp và bắt đầu di chuyển. Sau đó, chương trình cập nhật cấu trúc dữ liệu 90. Chúng tôi đã ẩn chi tiết của các nhiệm vụ này trong các hàm 96 và 97. Các tên hàm mô tả này cho phép hàm 32 cung cấp một cái nhìn tổng quan về chức năng của chương trìnhCác dòng tiếp theo kiểm tra xem người chơi đã giải được câu đố hay chưa bằng cách so sánh tòa tháp hoàn chỉnh trong 6 với 80 và 81 6Chúng tôi không so sánh nó với 82, bởi vì cột đó bắt đầu bằng một tòa tháp đã hoàn thành; . Lưu ý rằng chúng tôi sử dụng lại 6 để tạo các tòa tháp bắt đầu và kiểm tra xem người chơi có giải được câu đố hay không. Bởi vì 6 là một hằng số, chúng tôi có thể tin tưởng rằng nó sẽ luôn có giá trị mà chúng tôi đã gán cho nó ở phần đầu của mã nguồnĐiều kiện chúng ta sử dụng tương đương nhưng ngắn hơn 85, một thành ngữ Python mà chúng ta đã đề cập trong Chương 6. Nếu điều kiện này là 86, người chơi đã giải được câu đố và chúng tôi kết thúc chương trình. Nếu không, chúng tôi quay lại cho một lượt khácHàm 97 yêu cầu người chơi di chuyển đĩa và xác thực việc di chuyển theo luật chơi 0Chúng tôi bắt đầu một vòng lặp vô hạn tiếp tục lặp cho đến khi một câu lệnh 88 khiến việc thực thi rời khỏi vòng lặp và chức năng hoặc một cuộc gọi 89 kết thúc chương trình. Phần đầu tiên của vòng lặp yêu cầu người chơi di chuyển bằng cách chỉ định từ và đến thápLưu ý lệnh 60 nhận đầu vào bàn phím từ trình phát. Cuộc gọi 61 chấp nhận đầu vào văn bản từ trình phát bằng cách đưa ra lời nhắc 62. Biểu tượng này cho biết người chơi nên nhập nội dung nào đó. Nếu chương trình không đưa ra lời nhắc, người chơi có thể nghĩ rằng chương trình đã bị đóng băng trong giây látChúng tôi gọi phương thức 63 trên chuỗi được trả về từ 6 để nó trả về dạng chữ hoa của chuỗi. Điều này cho phép người chơi nhập nhãn tháp chữ hoa hoặc chữ thường, chẳng hạn như 65 hoặc 66 cho tháp A. Đổi lại, phương thức 67 của chuỗi chữ hoa được gọi, trả về một chuỗi không có bất kỳ khoảng trắng nào ở hai bên trong trường hợp người dùng vô tình thêm khoảng trắng khi di chuyển. Sự thân thiện với người dùng này giúp người chơi sử dụng chương trình của chúng tôi dễ dàng hơn một chútVẫn ở hàm 97, chúng ta kiểm tra đầu vào mà người dùng nhập vào 1Nếu người dùng nhập vào 69 (trong bất kỳ trường hợp nào, hoặc thậm chí có dấu cách ở đầu hoặc cuối chuỗi, do các cuộc gọi đến 63 và 67), chương trình sẽ kết thúc. Chúng tôi có thể đã thực hiện 97 trả lại 69 để chỉ ra cho người gọi rằng nó nên gọi 89, thay vì để 97 gọi 89. Nhưng điều này sẽ làm phức tạp giá trị trả về của 97. nó sẽ trả về một bộ gồm hai chuỗi (đối với nước đi của người chơi) hoặc một chuỗi 69. Hàm trả về giá trị của một kiểu dữ liệu đơn lẻ dễ hiểu hơn hàm có thể trả về giá trị của nhiều kiểu có thể. Tôi đã thảo luận điều này trong “Các giá trị trả về phải luôn có cùng kiểu dữ liệu” ở trang 177Giữa ba tòa tháp, chỉ có thể kết hợp sáu tòa tháp. Mặc dù thực tế là chúng tôi đã mã hóa cứng tất cả sáu giá trị trong điều kiện kiểm tra di chuyển, nhưng mã này dễ đọc hơn nhiều so với mã như 09 10. Với những trường hợp này, phương pháp mã hóa cứng là đơn giản nhấtNói chung, việc mã hóa cứng các giá trị như 11, 12 và các giá trị khác dưới dạng giá trị ma thuật được coi là thông lệ không tốt, chỉ có giá trị miễn là chương trình có ba cực. Nhưng mặc dù chúng tôi có thể muốn điều chỉnh số lượng đĩa bằng cách thay đổi hằng số 7, nhưng rất khó có khả năng chúng tôi sẽ thêm nhiều cột hơn vào trò chơi. Viết ra mọi di chuyển cực có thể trên dòng này là tốtChúng tôi tạo hai biến mới, 14 và 15, làm tên mô tả cho dữ liệu. Chúng không phục vụ mục đích chức năng, nhưng chúng làm cho mã dễ đọc hơn 16 và 17 2Tiếp theo, chúng tôi kiểm tra xem các tòa tháp đã chọn có cấu thành một động thái hợp pháp hay không 3Nếu không, một câu lệnh 18 khiến việc thực hiện quay trở lại phần đầu của vòng lặp, câu lệnh này sẽ yêu cầu người chơi nhập lại nước đi của họ. Lưu ý rằng chúng tôi kiểm tra xem 15 có trống không; . Hai điều kiện đầu tiên này đảm bảo rằng vào thời điểm điều kiện thứ ba được chọn, 21 và 22 sẽ không bị trống hoặc gây ra lỗi 23. Chúng tôi đã ra lệnh cho các điều kiện này theo cách để ngăn chặn 23 hoặc kiểm tra bổ sungĐiều quan trọng là chương trình của bạn phải xử lý mọi thông tin nhập không hợp lệ từ người dùng hoặc các trường hợp lỗi tiềm ẩn. Người dùng có thể không biết phải nhập gì hoặc họ có thể mắc lỗi chính tả. Tương tự, các tệp có thể bị mất bất ngờ hoặc cơ sở dữ liệu có thể bị sập. Các chương trình của bạn cần phải linh hoạt trong các trường hợp ngoại lệ; Nếu không có điều kiện nào trước đó là 86, thì 97 trả về 20 4Trong Python, các câu lệnh 88 luôn trả về một giá trị duy nhất. Mặc dù câu lệnh 88 này có vẻ như trả về hai giá trị, nhưng Python thực sự trả về một bộ gồm hai giá trị, tương đương với 30. Các lập trình viên Python thường bỏ qua dấu ngoặc đơn trong ngữ cảnh này. Các dấu ngoặc đơn không định nghĩa một tuple nhiều như các dấu phẩyLưu ý rằng chương trình chỉ gọi hàm 97 một lần từ hàm 32. Hàm này không cứu chúng tôi khỏi mã trùng lặp, đây là mục đích phổ biến nhất để sử dụng một. Không có lý do gì chúng ta không thể đặt tất cả mã trong 97 vào hàm 32. Nhưng chúng ta cũng có thể sử dụng các hàm như một cách để sắp xếp mã thành các đơn vị riêng biệt, đó là cách chúng ta đang sử dụng 97. Làm như vậy sẽ ngăn hàm 32 trở nên quá dài và khó sử dụngHàm 96 hiển thị các đĩa trên tháp A, B và C trong đối số 90 5Nó dựa vào hàm 39 mà chúng ta sẽ trình bày tiếp theo, để hiển thị từng đĩa trong tháp. Vòng lặp 40 kiểm tra mọi đĩa có thể để tìm tháp và vòng lặp 41 kiểm tra tháp A, B và CHàm 96 gọi 39 để hiển thị mỗi đĩa ở một chiều rộng cụ thể hoặc nếu 44 được thông qua, cực không có đĩa 6Chúng tôi hiển thị các nhãn A, B và C trên màn hình. Người chơi cần thông tin này để phân biệt giữa các tòa tháp và để củng cố rằng các tòa tháp được dán nhãn A, B và C chứ không phải 1, 2 và 3 hoặc Trái, Giữa và Phải. Tôi đã chọn không sử dụng 1, 2 và 3 cho các nhãn tháp để ngăn người chơi nhầm lẫn các số này với các số được sử dụng cho kích thước của đĩa Chúng tôi đặt biến 45 thành số khoảng trống để đặt giữa mỗi nhãn, điều này lần lượt dựa trên 7, bởi vì càng nhiều đĩa trong trò chơi, khoảng cách giữa các cực càng rộng. Thay vì sử dụng chuỗi f, như trong 47, chúng tôi sử dụng phương thức chuỗi 48. Điều này cho phép chúng tôi sử dụng cùng một đối số 45 bất cứ nơi nào 50 xuất hiện trong chuỗi được liên kết, tạo ra mã ngắn hơn và dễ đọc hơn so với phiên bản chuỗi fHàm 39 hiển thị một đĩa đơn cùng với chiều rộng của nó. Nếu không có đĩa, nó chỉ hiển thị cực 7Chúng tôi đại diện cho một đĩa bằng cách sử dụng một khoảng trống ở đầu, một số ký tự 52 bằng với chiều rộng của đĩa, hai ký tự cho chiều rộng (bao gồm cả dấu gạch dưới nếu chiều rộng là một chữ số), một chuỗi ký tự 52 khác, và sau đó là khoảng trống ở cuối . Để chỉ hiển thị cột trống, tất cả những gì chúng ta cần là khoảng trống ở đầu, hai ký tự ống và khoảng trống ở cuối. Kết quả là, chúng tôi sẽ cần sáu cuộc gọi đến 39 với sáu đối số khác nhau cho 55 để hiển thị tòa tháp sau 8Lưu ý cách các hàm_______296 và 39 phân chia trách nhiệm hiển thị các tòa tháp. Mặc dù 96 quyết định cách diễn giải cấu trúc dữ liệu đại diện cho từng tháp, nhưng nó dựa vào 39 để thực sự hiển thị từng đĩa của tháp. Chia chương trình của bạn thành các chức năng nhỏ hơn như thế này giúp kiểm tra từng phần dễ dàng hơn. Nếu chương trình hiển thị các đĩa không chính xác, vấn đề có thể xảy ra ở 39. Nếu các đĩa xuất hiện không đúng thứ tự, có thể sự cố nằm ở 96. Dù bằng cách nào, phần mã bạn phải gỡ lỗi sẽ nhỏ hơn nhiềuĐể gọi hàm 32, chúng tôi sử dụng một thành ngữ Python phổ biến 9Python tự động đặt biến 63 thành 64 nếu người chơi chạy towerofhanoi. chương trình py trực tiếp. Nhưng nếu ai đó nhập chương trình dưới dạng mô-đun bằng cách sử dụng 35, thì 63 sẽ được đặt thành 67. Dòng 68 sẽ gọi hàm 32 nếu ai đó chạy chương trình của chúng ta, bắt đầu trò chơi Tháp Hà Nội. Nhưng nếu chúng ta chỉ muốn nhập chương trình dưới dạng một mô-đun để chúng ta có thể gọi các chức năng riêng lẻ trong đó để kiểm tra đơn vị, thì điều kiện này sẽ là 70 và 32 sẽ không được gọiBốn trong một hàngFour-in-a-Row là một trò chơi thả gạch dành cho hai người chơi. Mỗi người chơi cố gắng tạo một hàng gồm bốn ô của họ, theo chiều ngang, chiều dọc hoặc đường chéo. Nó tương tự như trò chơi bảng Connect Four và Four Up. Trò chơi sử dụng bảng đứng 7 x 6 và các ô xếp rơi xuống khoảng trống thấp nhất trong một cột. Trong trò chơi Bốn người trong một hàng của chúng tôi, hai người chơi là X và O sẽ đấu với nhau, trái ngược với một người chơi đấu với máy tính Đầu raKhi bạn chạy chương trình Four-in-a-Row trong chương này, đầu ra sẽ như thế này 0Cố gắng tìm ra nhiều chiến lược tinh tế mà bạn có thể sử dụng để có được bốn ô liên tiếp trong khi ngăn chặn đối thủ của bạn làm điều tương tự Mã nguồnMở một tệp mới trong trình chỉnh sửa hoặc IDE của bạn, nhập mã sau và lưu dưới dạng Fourinarow. py 1Chạy chương trình này và chơi một vài trò chơi để biết chương trình này làm gì trước khi đọc phần giải thích về mã nguồn. Để kiểm tra lỗi chính tả, hãy sao chép và dán nó vào công cụ tìm khác biệt trực tuyến tại https. // phát minh với trăn. com/ngoài/khác biệt/ Viết mãHãy xem mã nguồn của chương trình, như chúng ta đã làm với chương trình Tháp Hà Nội. Một lần nữa, tôi đã định dạng mã này bằng Màu đen với giới hạn dòng là 75 ký tự Chúng tôi sẽ bắt đầu ở đầu chương trình 2Chúng tôi bắt đầu chương trình với một chuỗi tài liệu, nhập mô-đun và gán liên tục, như chúng tôi đã làm trong chương trình Tháp Hà Nội. Chúng tôi xác định các hằng số 72 và 73 để chúng tôi không phải sử dụng các chuỗi 74 và 75 trong suốt chương trình, giúp dễ bắt lỗi hơn. Nếu chúng ta nhập lỗi đánh máy trong khi sử dụng các hằng số, chẳng hạn như 76, Python sẽ tăng 77, ngay lập tức chỉ ra vấn đề. Nhưng nếu chúng tôi mắc lỗi đánh máy với ký tự 74, chẳng hạn như 79 hoặc 80, thì lỗi có thể không rõ ràng ngay lập tức. Như đã giải thích trong “Magic Numbers” ở trang 71, việc sử dụng hằng số thay vì giá trị chuỗi trực tiếp không chỉ cung cấp mô tả mà còn cảnh báo sớm cho bất kỳ lỗi chính tả nào trong mã nguồn của bạnCác hằng số không nên thay đổi trong khi chương trình chạy. Nhưng lập trình viên có thể cập nhật giá trị của chúng trong các phiên bản tương lai của chương trình. Vì lý do này, chúng tôi ghi chú cho các lập trình viên biết rằng họ nên cập nhật các hằng số 81 và 82, được mô tả sau, nếu họ thay đổi giá trị của 83 3Tiếp theo, chúng ta tạo hằng số 82 4Chúng tôi sẽ sử dụng hằng số này sau để đảm bảo người chơi chọn một cột hợp lệ. Lưu ý rằng nếu chúng tôi đã từng đặt 83 thành một giá trị khác với 86, chúng tôi sẽ phải thêm nhãn vào hoặc xóa nhãn khỏi bộ dữ liệu 82. Tôi có thể tránh điều này bằng cách tạo ra giá trị của 82 dựa trên 83 với mã như thế này. 90. Nhưng 82 không có khả năng thay đổi trong tương lai, vì trò chơi Bốn hàng một tiêu chuẩn được chơi trên bàn cờ 7 x 6, vì vậy tôi quyết định viết ra một giá trị bộ dữ liệu rõ ràngChắc chắn rồi, mã hóa cứng này có mùi mã, như được mô tả trong “Số ma thuật” ở trang 71, nhưng nó dễ đọc hơn mã thay thế. Ngoài ra, câu lệnh 92 cảnh báo chúng tôi về việc thay đổi 83 mà không cập nhật 82Như với Tháp Hà Nội, chương trình Four-in-a-Row sử dụng nghệ thuật ASCII để vẽ bảng trò chơi. Các dòng sau đây là một câu lệnh gán đơn với một chuỗi nhiều dòng 5Chuỗi này chứa dấu ngoặc nhọn ( 95) mà phương thức chuỗi 48 sẽ thay thế bằng nội dung của bảng. (Hàm 97, được giải thích sau, sẽ xử lý việc này. ) Bởi vì bảng bao gồm bảy cột và sáu hàng, chúng tôi sử dụng bảy cặp dấu ngoặc nhọn 95 trong mỗi sáu hàng để đại diện cho mọi vị trí. Lưu ý rằng giống như 82, về mặt kỹ thuật, chúng tôi đang mã hóa cứng bảng để tạo một số cột và hàng đã đặt. Nếu chúng tôi thay đổi 83 hoặc 01 thành số nguyên mới, chúng tôi cũng sẽ phải cập nhật chuỗi nhiều dòng trong 81Chúng tôi có thể đã viết mã để tạo 81 dựa trên các hằng số 83 và 01, như vậy 6Nhưng mã này không thể đọc được như một chuỗi nhiều dòng đơn giản và dù sao thì chúng tôi cũng không thể thay đổi kích thước của bảng trò chơi, vì vậy chúng tôi sẽ sử dụng chuỗi nhiều dòng đơn giản Chúng tôi bắt đầu viết hàm 32, hàm này sẽ gọi tất cả các hàm khác mà chúng tôi đã tạo cho trò chơi này 7Chúng tôi cung cấp cho hàm 32 một chuỗi tài liệu, có thể xem được bằng hàm 1 tích hợp. Hàm 32 cũng chuẩn bị bảng trò chơi cho một trò chơi mới và chọn người chơi đầu tiênBên trong hàm 32 là một vòng lặp vô hạn 8Mỗi lần lặp của vòng lặp này bao gồm một lượt duy nhất. Đầu tiên, chúng tôi hiển thị bảng trò chơi cho người chơi. Thứ hai, người chơi chọn một cột để thả một ô vào và thứ ba, chúng tôi cập nhật cấu trúc dữ liệu bảng trò chơi Tiếp theo, chúng tôi đánh giá kết quả di chuyển của người chơi 9Nếu người chơi thực hiện một nước đi chiến thắng, 11 trả về 86 và trò chơi kết thúc. Nếu người chơi lấp đầy bàn cờ và không có người chiến thắng, 13 trả về 86 và trò chơi kết thúc. Lưu ý rằng thay vì gọi 89, chúng ta có thể sử dụng một câu lệnh 16 đơn giản. Điều này có thể khiến việc thực thi thoát ra khỏi vòng lặp 17 và vì không có mã nào trong hàm 32 sau vòng lặp này, nên hàm sẽ quay trở lại lệnh gọi 32 ở cuối chương trình, khiến chương trình kết thúc. Nhưng tôi đã chọn sử dụng 89 để các lập trình viên đọc mã hiểu rõ rằng chương trình sẽ kết thúc ngay lập tứcNếu trò chơi chưa kết thúc, các dòng sau sẽ đặt 21 cho người chơi khác 00Lưu ý rằng tôi có thể biến câu lệnh 22 thành một câu lệnh 23 đơn giản mà không cần điều kiện. Nhưng hãy nhớ lại nguyên lý Zen của Python rằng rõ ràng hơn là ẩn ý. Mã này nói rõ ràng rằng nếu bây giờ đến lượt người chơi O, thì tiếp theo sẽ đến lượt người chơi X. Phương án thay thế sẽ chỉ nói rằng nếu bây giờ không đến lượt người chơi X, thì sẽ đến lượt người chơi X tiếp theo. Mặc dù các câu lệnh 24 và 23 phù hợp tự nhiên với các điều kiện Boolean, nhưng các giá trị 72 và 73 không giống như 86 và 70. 30 không giống như 73. Do đó, thật hữu ích khi trực tiếp kiểm tra giá trị của 21Ngoài ra, tôi có thể đã thực hiện các hành động tương tự trong một lớp lót 01Dòng này sử dụng thủ thuật từ điển được đề cập trong “Sử dụng từ điển thay vì câu lệnh 33” trên trang 101. Nhưng giống như nhiều câu nói đơn lẻ, nó không dễ đọc như câu lệnh 24 và 22 trực tiếpTiếp theo, chúng ta định nghĩa hàm 36 02Hàm này trả về một từ điển đại diện cho một bảng Four-in-a-Row. Nó có bộ dữ liệu 37 cho các phím (trong đó ________ 738 và ________ 739 là số nguyên) và ký tự ________ 740, ________ 741 hoặc 42 cho ô xếp ở mỗi vị trí trên bảng. Chúng tôi lưu trữ các chuỗi này lần lượt trong 72, 73 và 45Trò chơi Four-in-a-Row của chúng tôi khá đơn giản, vì vậy sử dụng từ điển để đại diện cho bảng trò chơi là một kỹ thuật phù hợp. Tuy nhiên, chúng ta có thể đã sử dụng cách tiếp cận OOP để thay thế. Chúng ta sẽ khám phá OOP trong Chương 15 đến 17 Hàm 97 lấy cấu trúc dữ liệu bàn trò chơi cho đối số 47 và hiển thị bàn cờ trên màn hình bằng cách sử dụng hằng số 81 03Nhớ lại rằng 81 là một chuỗi nhiều dòng với một số cặp dấu ngoặc. Khi chúng ta gọi phương thức 48 trên 81, các dấu ngoặc này sẽ được thay thế bằng các đối số được truyền cho 48Biến 53 sẽ chứa danh sách các đối số này. Chúng tôi bắt đầu bằng cách gán cho nó một danh sách trống. Giá trị đầu tiên trong 53 sẽ thay thế cặp dấu ngoặc nhọn đầu tiên trong 81, giá trị thứ hai sẽ thay thế cặp thứ hai, v.v. Về cơ bản, chúng tôi đang tạo một danh sách các giá trị từ từ điển 47 04Các vòng lặp 57 lồng nhau này lặp qua mọi hàng và cột có thể có trên bảng, nối thêm chúng vào danh sách trong 53. Khi các vòng lặp này kết thúc, chúng tôi chuyển các giá trị trong danh sách 53 dưới dạng các đối số riêng lẻ cho phương thức 48 bằng cách sử dụng tiền tố dấu sao 61. Phần “Sử dụng 61 để tạo các hàm biến thiên” trên trang 167 đã giải thích cách sử dụng cú pháp này để xử lý các giá trị trong danh sách dưới dạng các đối số hàm riêng biệt. mã 63 tương đương với 64. Chúng ta cần dấu sao vì phương thức 48 yêu cầu một đối số cho mỗi cặp dấu ngoặc nhọn, không phải một đối số danh sáchTiếp theo, chúng ta viết hàm 97 05Chức năng bắt đầu với một vòng lặp vô hạn chờ người chơi thực hiện một nước đi hợp lệ. Đoạn mã này giống hàm 97 trong chương trình Tháp Hà Nội. Lưu ý rằng cuộc gọi 5 khi bắt đầu vòng lặp 17 sử dụng chuỗi f để chúng tôi không phải thay đổi thông báo nếu chúng tôi cập nhật 83Chúng tôi kiểm tra xem phản hồi của người chơi có phải là một cột không; 06Chúng ta có thể viết điều kiện xác thực đầu vào này là 72, nhưng sẽ đơn giản hơn nếu chỉ sử dụng 73Tiếp theo, chúng ta cần tìm ra hàng nào mà một ô rơi trong cột đã chọn của người chơi sẽ rơi xuống 07Bảng hiển thị các nhãn cột 93 đến 86 trên màn hình. Nhưng các chỉ mục 37 trên bảng sử dụng chỉ mục dựa trên 0, vì vậy chúng nằm trong khoảng từ 0 đến 6. Để giải quyết sự khác biệt này, chúng tôi chuyển đổi các giá trị chuỗi 77 thành 78 thành các giá trị số nguyên 44 thành 9Các chỉ mục hàng bắt đầu từ 44 ở đầu bảng và tăng lên 9 ở cuối bảng. Chúng tôi kiểm tra hàng trên cùng trong cột đã chọn để xem nó có bị chiếm dụng không. Nếu vậy, cột này đã đầy hoàn toàn và câu lệnh 18 di chuyển việc thực hiện trở lại điểm bắt đầu của vòng lặp để yêu cầu người chơi thực hiện một nước đi khácNếu cột không đầy, chúng ta cần tìm không gian trống thấp nhất để ô tiếp đất 08Vòng lặp 57 này bắt đầu ở chỉ mục hàng dưới cùng, 85 hoặc 9 và di chuyển lên cho đến khi tìm thấy khoảng trống đầu tiên. Sau đó, hàm trả về các chỉ mục của khoảng trống thấp nhấtBất cứ khi nào bàn cờ đầy, trò chơi kết thúc với tỷ số hòa 09Hàm 13 sử dụng một cặp vòng lặp 57 lồng nhau để lặp lại mọi vị trí trên bảng. Nếu nó tìm thấy một khoảng trống duy nhất, thì bảng chưa đầy và hàm trả về 70. Nếu quá trình thực thi diễn ra qua cả hai vòng lặp, hàm 13 không tìm thấy khoảng trống nào, do đó, nó trả về 86Hàm 11 kiểm tra xem người chơi có thắng trò chơi không 0Hàm này trả về 86 nếu 94 xuất hiện bốn lần liên tiếp theo chiều ngang, chiều dọc hoặc đường chéo. Để biết điều kiện có được đáp ứng hay không, chúng ta phải kiểm tra từng bộ bốn ô liền kề trên bàn cờ. Chúng tôi sẽ sử dụng một loạt các vòng lặp 57 lồng nhau để làm điều nàyBộ dữ liệu 37 đại diện cho một điểm bắt đầu. Chúng tôi kiểm tra điểm bắt đầu và ba dấu cách ở bên phải của nó để tìm chuỗi 94. Nếu không gian bắt đầu là 37, thì không gian bên phải của nó sẽ là 99, v.v. Chúng tôi sẽ lưu các ô trong bốn khoảng trống này vào các biến ________ 1000, ________ 1001, ______ 1002 và ________ 1003. Nếu tất cả các biến này có cùng giá trị như 94, thì chúng tôi đã tìm thấy bốn biến liên tiếp và hàm 11 trả về 86Trong “Biến có hậu tố số” ở trang 76, tôi đã đề cập rằng các tên biến có hậu tố số liên tiếp (như 000 đến 003 trong trò chơi này) thường là một mùi mã cho biết bạn nên sử dụng một danh sách duy nhất thay thế. Nhưng trong bối cảnh này, những tên biến này là tốt. Chúng ta không cần thay thế chúng bằng một danh sách, bởi vì chương trình Bốn hàng liên tiếp sẽ luôn yêu cầu chính xác bốn trong số các biến ô xếp này. Hãy nhớ rằng mùi mã không nhất thiết chỉ ra vấn đề; . Trong trường hợp này, việc sử dụng một danh sách sẽ làm cho mã của chúng ta phức tạp hơn và nó sẽ không mang lại bất kỳ lợi ích nào, vì vậy chúng ta sẽ sử dụng 000, 001, 002 và 003Chúng tôi sử dụng quy trình tương tự để kiểm tra các ô xếp bốn hàng dọc 1Tiếp theo, chúng tôi kiểm tra các ô xếp bốn hàng theo kiểu đường chéo đi xuống và sang phải; 2Mã này tương tự như kiểm tra bốn hàng ngang, vì vậy tôi sẽ không lặp lại lời giải thích ở đây. Nếu tất cả các kiểm tra cho các ô bốn hàng liên tiếp không tìm thấy bất kỳ ô nào, hàm trả về ________ 670 để cho biết rằng ________ 794 không phải là người chiến thắng trên bảng này 3Nhiệm vụ duy nhất còn lại là gọi hàm 32 9Một lần nữa, chúng tôi sử dụng một thành ngữ Python phổ biến sẽ gọi 32 nếu Fourinarow. py được chạy trực tiếp nhưng không chạy nếu fourinarow. py được nhập dưới dạng mô-đunTóm lượcTrò chơi xếp hình Tháp Hà Nội và trò chơi Bốn người trong một hàng là những chương trình ngắn, nhưng bằng cách làm theo các cách thực hành trong cuốn sách này, bạn có thể đảm bảo rằng mã của chúng có thể đọc được và dễ gỡ lỗi. Các chương trình này tuân theo một số thông lệ tốt. chúng đã được định dạng tự động bằng Màu đen, sử dụng chuỗi tài liệu để mô tả mô-đun và chức năng, đồng thời đặt các hằng số ở gần đầu tệp. Chúng giới hạn các biến, tham số hàm và hàm trả về giá trị cho một kiểu dữ liệu duy nhất nên gợi ý kiểu, mặc dù là một dạng tài liệu bổ sung hữu ích, là không cần thiết Trong Tháp Hà Nội, chúng tôi biểu diễn ba tòa tháp dưới dạng từ điển với các khóa 66, 018 và 019 có giá trị là danh sách các số nguyên. Điều này hoạt động, nhưng nếu chương trình của chúng tôi lớn hơn hoặc phức tạp hơn, thì sẽ là một ý tưởng hay khi biểu diễn dữ liệu này bằng một lớp. Các lớp và kỹ thuật OOP không được sử dụng trong chương này vì tôi không đề cập đến OOP cho đến Chương 15 đến 17. Nhưng hãy nhớ rằng việc sử dụng một lớp cho cấu trúc dữ liệu này là hoàn toàn hợp lệ. Các tòa tháp hiển thị dưới dạng nghệ thuật ASCII trên màn hình, sử dụng các ký tự văn bản để hiển thị từng đĩa của các tòa thápTrò chơi Four-in-a-Row sử dụng nghệ thuật ASCII để hiển thị một đại diện của bảng trò chơi. Chúng tôi hiển thị điều này bằng cách sử dụng một chuỗi nhiều dòng được lưu trữ trong hằng số 81. Chuỗi này có 42 cặp dấu ngoặc nhọn 95 để hiển thị từng khoảng trống trên bảng 7 nhân 6. Chúng tôi sử dụng dấu ngoặc nhọn để phương thức chuỗi 48 có thể thay thế chúng bằng ô tại không gian đó. Bằng cách này, rõ ràng hơn cách chuỗi 81 tạo ra bảng trò chơi khi nó xuất hiện trên màn hìnhMặc dù cấu trúc dữ liệu của chúng khác nhau nhưng hai chương trình này có nhiều điểm tương đồng. Cả hai đều hiển thị cấu trúc dữ liệu của họ trên màn hình, yêu cầu trình phát nhập dữ liệu, xác thực dữ liệu nhập đó và sau đó sử dụng dữ liệu đó để cập nhật cấu trúc dữ liệu của họ trước khi lặp lại từ đầu. Nhưng có nhiều cách khác nhau mà chúng ta có thể viết mã để thực hiện những hành động này. Điều làm cho mã có thể đọc được cuối cùng là ý kiến chủ quan hơn là thước đo khách quan về mức độ tuân thủ chặt chẽ của nó đối với một số danh sách quy tắc. Mã nguồn trong chương này cho thấy rằng mặc dù chúng ta nên luôn xem xét lại bất kỳ mã nào có mùi, nhưng không phải tất cả các mã có mùi đều cho thấy sự cố mà chúng ta cần khắc phục. Khả năng đọc mã quan trọng hơn là tuân theo chính sách “mã không có mùi” cho các chương trình của bạn một cách thiếu suy nghĩ Làm cách nào để tạo Tháp Hà Nội bằng Python?Chương trình Python/ Mã nguồn . # Tạo hàm đệ quy def tower_of_hanoi(đĩa, nguồn, phụ, đích) nếu (đĩa == 1) print('Chuyển đĩa 1 từ thanh {} sang thanh {}. '. định dạng (nguồn, đích)) trở lại # tự gọi hàm tower_of_hanoi(đĩa - 1, nguồn, đích, phụ trợ) Tháp Hà Nội có thể được giải quyết mà không cần đệ quy không?Có. Nó có thể được lập trình mà không cần đệ quy và không cần ngăn xếp (hoặc ngăn xếp mô phỏng) .
Công thức của Tháp Hà Nội là gì?Số nước đi tối thiểu cần thiết để giải câu đố Tháp Hà Nội là 2n − 1, trong đó n là số đĩa
Chúng ta có thể giải bài toán Tháp Hà Nội bằng phương pháp lặp không?Phương pháp tiếp cận lặp lại cho Tower Of Hanoi
. till n becomes 1 we will put a variable into stack which makes a track of source, auxiliary and destination pole. Nếu n trở thành 1 thì chúng ta sẽ lấy biến ra khỏi ngăn xếp và in ra. |