[ATBS2nd]Chương 1 - Python cơ bản - Phần 24

Chào các bạn,
Chúng ta tiến đến phần cuối của việc thao tác với chuỗi trong Python qua một chương trình ngắn và các bài tập thực hành.
Chương trình ngắn: Pig Latin
Pig Latin là một ngôn ngữ tạo ra những từ tiếng Anh ngớ ngẩn. Nếu một từ bắt đầu bằng một nguyên âm, từ yay được thêm vào cuối của nó. Nếu một từ bắt đầu bằng cụm phụ âm hoặc phụ âm (như ch hoặc gr), thì phụ âm hoặc cụm đó được di chuyển đến cuối từ theo sau là ay.
Hãy viết một chương trình Pig Latin sẽ tạo ra một cái gì đó như thế này:

Enter the English message to translate into Pig Latin:
My name is AL SWEIGART and I am 4,000 years old.
Ymay amenay isyay ALYAY EIGARTSWAY andyay Iyay amyay 4,000 yearsyay oldyay.

Chương trình này hoạt động bằng cách thay đổi một chuỗi bằng các phương thức được giới thiệu trong phần này. Nhập mã nguồn sau vào trình soạn thảo văn bản và lưu tệp dưới dạng pigLat.py:

# English to Pig Latin
print('Enter the English message to translate into Pig Latin:')
message = input()
VOWELS = ('a', 'e', 'i', 'o', 'u', 'y')
pigLatin = [] # A list of the words in Pig Latin.
for word in message.split():
	# Separate the non-letters at the start of this word:
	prefixNonLetters = ''
	while len(word) > 0 and not word[0].isalpha():
		prefixNonLetters += word[0]
		word = word[1:]
	if len(word) == 0:
		pigLatin.append(prefixNonLetters)
		continue
	
	# Separate the non-letters at the end of this word:
	suffixNonLetters = ''
	while not word[-1].isalpha():
		suffixNonLetters += word[-1]
		word = word[:-1]
	
	# Remember if the word was in uppercase or title case.
	wasUpper = word.isupper()
	wasTitle = word.istitle()
	word = word.lower() # Make the word lowercase for translation.
	
	# Separate the consonants at the start of this word:
	prefixConsonants = ''
	while len(word) > 0 and not word[0] in VOWELS:
		prefixConsonants += word[0]
		word = word[1:]

	# Add the Pig Latin ending to the word:
	if prefixConsonants != '':
		word += prefixConsonants + 'ay'
	else:
		word += 'yay'

	# Set the word back to uppercase or title case:
	if wasUpper:
		word = word.upper()
	if wasTitle:
		word = word.title()
	# Add the non-letters back to the start or end of the word.
	pigLatin.append(prefixNonLetters + word + suffixNonLetters)

# Join all the words back together into a single string:
print(' '.join(pigLatin))

Chúng ta sẽ phân tích từng đoạn code

# English to Pig Latin
print('Enter the English message to translate into Pig Latin:')
message = input()
VOWELS = ('a', 'e', 'i', 'o', 'u', 'y')

Đầu tiên, chúng ta yêu cầu người dùng nhập văn bản tiếng Anh để dịch sang Pig Latin. Ngoài ra, chúng ta tạo một hằng giữ mọi chữ cái nguyên âm chữ thường (và y) dưới dạng một chuỗi các chuỗi. Điều này sẽ được sử dụng sau này trong chương trình của chúng ta.
Tiếp theo, chúng ta sẽ tạo ra biến pigLatin để lưu trữ các từ khi chúng tôi dịch chúng sang Pig Latin:

pigLatin = [] # A list of the words in Pig Latin.
for word in message.split():
	# Separate the non-letters at the start of this word:
	prefixNonLetters = ''
	while len(word) > 0 and not word[0].isalpha():
		prefixNonLetters += word[0]
		word = word[1:]
	if len(word) == 0:
		pigLatin.append(prefixNonLetters)
		continue

Chúng ta cần mỗi từ là một chuỗi riêng của nó, vì vậy chúng ta gọi message.split () để lấy danh sách các từ dưới dạng các chuỗi riêng biệt. Chuỗi ‘My name is AL SWEIGART and I am 4,000 years old.’’ sẽ khiến split() trả lại [‘My’, ‘name’, ‘is’, ‘AL’, ‘SWEIGART’, ‘and’, ‘I’, ‘am’, ‘4,000’, ‘years’, ‘old.’].
Chúng ta cần xóa bất kỳ chữ cái nào khỏi đầu và cuối của mỗi chuỗi không phải là kí tự để các chuỗi như ‘old.’ dịch sang ‘oldyay.’ thay vì ‘old.yay’. Chúng tôi sẽ lưu những chữ cái này vào một biến có tên là prefixNonLetters.

# Separate the non-letters at the end of this word:
	suffixNonLetters = ''
	while not word[-1].isalpha():
		suffixNonLetters += word[-1]
		word = word[:-1]

Một vòng lặp gọi isalpha() trên ký tự đầu tiên trong từ sẽ xác định xem chúng ta có nên xóa một ký tự khỏi một từ và nối nó với cuối của chuỗi trong prefixNonLetters hay không. Nếu toàn bộ từ được tạo từ các ký tự không phải chữ cái, như ‘4.000’, chúng ta chỉ cần thêm nó vào danh sách pigLatin và tiếp tục từ tiếp theo để dịch. Chúng ta cũng cần lưu các kí tự không phải chữ cái ở cuối chuỗi từ. Mã này tương tự như vòng lặp trước.
Tiếp theo, chúng tôi sẽ đảm bảo chương trình ghi nhớ nếu từ đó được viết hoa hoặc viết tiêu đề để chúng tôi có thể khôi phục từ đó sau khi dịch từ này sang Pig Latin:

# Remember if the word was in uppercase or title case.
	wasUpper = word.isupper()
	wasTitle = word.istitle()
	word = word.lower() # Make the word lowercase for translation.

Đối với phần còn lại của mã trong vòng lặp for, chúng tôi sẽ làm việc với phiên bản chữ thường. Để chuyển đổi một từ như sweigart sang eigart-sway, chúng ta cần loại bỏ tất cả các phụ âm từ đầu từ:

# Separate the consonants at the start of this word:
	prefixConsonants = ''
	while len(word) > 0 and not word[0] in VOWELS:
		prefixConsonants += word[0]
		word = word[1:]

Chúng tôi sử dụng một vòng lặp tương tự như vòng lặp đã loại bỏ các kí tự không phải là chữ bắt đầu từ, ngoại trừ bây giờ chúng tôi đang loại bỏ các phụ âm và lưu trữ chúng vào một biến có tên là prefixConsonants. Nếu có bất kỳ phụ âm nào ở đầu từ, thì bây giờ chúng ở trong prefixConsonants và chúng ta nên nối biến đó và chuỗi ‘ay’ vào cuối từ. Mặt khác, chúng ta có thể giả sử từ bắt đầu bằng nguyên âm và chúng ta chỉ cần ghép từ ‘yay’:

# Add the Pig Latin ending to the word:
	if prefixConsonants != '':
		word += prefixConsonants + 'ay'
	else:
		word += 'yay'

Hãy nhớ lại rằng chúng ta đặt word thành phiên bản chữ thường với word = word.lower (). Nếu word ban đầu là chữ hoa hoặc trường hợp tiêu đề, mã này sẽ chuyển đổi từ trở lại trường hợp ban đầu:

# Set the word back to uppercase or title case:
	if wasUpper:
		word = word.upper()
	if wasTitle:
		word = word.title()

Vào cuối vòng lặp for, chúng tôi nối thêm từ đó, cùng với bất kỳ tiền tố không phải là chữ viết tắt hoặc hậu tố ban đầu, vào danh sách pigLatin:

# Add the non-letters back to the start or end of the word.
	pigLatin.append(prefixNonLetters + word + suffixNonLetters)

# Join all the words back together into a single string:
print(' '.join(pigLatin))

Sau khi vòng lặp này kết thúc, chúng ta kết hợp danh sách các chuỗi thành một chuỗi bằng cách gọi phương thức join(). Chuỗi đơn này được truyền để print() để hiển thị Pig Latin của chúng ta trên màn hình.
Tổng kết
Văn bản là một dạng dữ liệu phổ biến và Python đi kèm với nhiều phương thức chuỗi hữu ích để xử lý văn bản được lưu trữ trong các giá trị chuỗi. Bạn sẽ sử dụng các phương thức lập chỉ mục, cắt và phương thức chuỗi trong hầu hết mọi chương trình Python bạn viết. Các chương trình bạn đang viết bây giờ dường như không quá phức tạp. Họ không có giao diện đồ họa với hình ảnh và văn bản đầy màu sắc. Cho đến nay, bạn có thể hiển thị văn bản với print() và cho phép người dùng nhập văn bản với input(). Tuy nhiên, người dùng có thể nhanh chóng nhập số lượng lớn văn bản thông qua bảng tạm. Khả năng này cung cấp một con đường hữu ích để viết các chương trình thao túng số lượng lớn văn bản. Các chương trình dựa trên văn bản này có thể không có cửa sổ hoặc đồ họa hào nhoáng, nhưng chúng có thể hoàn thành rất nhiều công việc hữu ích một cách nhanh chóng.
Bạn có thể không nghĩ rằng mình có đủ kiến ​​thức về Python để làm những việc như tải xuống các trang web, cập nhật bảng tính hoặc gửi tin nhắn văn bản, nhưng đó là nơi mà các module Python xuất hiện! Các module này, được viết bởi các lập trình viên khác, cung cấp các chức năng giúp bạn dễ dàng thực hiện tất cả những điều này. Vì vậy, hãy để học cách viết các chương trình thực tế để thực hiện các tác vụ tự động hữu ích.
Câu hỏi

  1. Kí tự escape là gì?

  2. Kí tự escape \n và \t thể hiện điều gì?

  3. Bạn có thể thể hiện một dấu \ trong chuỗi như thế nào?

  4. Chuỗi “Howl’s Moving Castle” là hợp lệ. Tại sao chuỗi như vậy đặt trong dấu nháy đơn là không hợp lệ?

  5. Nếu bạn không muốn đặt \n trong chuỗi. Bạn làm cách nào để thể hiện xuống hàng trong chuỗi?

  6. Những biểu thức sau có giá trị như thế nào?
    • ‘Hello, world!’[1]
    • ‘Hello, world!’[0:5]
    • ‘Hello, world!’[:5]
    • ‘Hello, world!’[3:]

  7. Những biểu thức sau có giá trị như thế nào?
    • ‘Hello’.upper()
    • ‘Hello’.upper().isupper()
    • ‘Hello’.upper().lower()

  8. Những biểu thức sau có giá trị như thế nào?
    • ‘Remember, remember, the fifth of November.’.split()
    • ‘-’.join(‘There can be only one.’.split())

  9. Những phương thức chuỗi có thể điều chỉ bên trái, bên phải, và ở giữa của chuỗi.

  10. Bạn có thể loại bỏ kí tự trống ở đầu và cuối chuỗi như thế nào?

Bài tập thực hành
Table Printer
Viết hàm có tên printTable() lấy danh sách các chuỗi và hiển thị nó trong một bảng được tổ chức tốt với mỗi cột được căn lề đúng. Giả sử rằng tất cả các danh sách biến trong sẽ chứa cùng một số chuỗi. Ví dụ: giá trị có thể trông như thế này:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
			['Alice', 'Bob', 'Carol', 'David'],
			['dogs', 'cats', 'moose', 'goose']]

Hàm printTable() sẽ in ra như sau

  apples  Alice  dogs
 oranges    Bob  cats
cherries  Carol moose
  banana  David goose

Gợi ý: trước tiên mã của bạn sẽ phải tìm chuỗi dài nhất trong mỗi
danh sách bên trong sao cho toàn bộ cột có thể đủ rộng để phù hợp với tất cả các chuỗi. Bạn có thể lưu trữ chiều rộng tối đa của mỗi cột dưới dạng danh sách các số nguyên. Hàm printTable () có thể bắt đầu bằng colWidths = [0] * len (tableData), sẽ tạo một danh sách chứa cùng số 0 giá trị với số lượng danh sách bên trong trong tableData. Theo cách đó, colWidths [0] có thể lưu trữ độ rộng của chuỗi dài nhất trong bảngData [0], colWidths [1] có thể lưu trữ độ rộng của chuỗi dài nhất trong tableData [1], v.v. Sau đó, bạn có thể tìm giá trị lớn nhất trong danh sách colWidths để tìm ra chiều rộng số nguyên nào sẽ truyền cho phương thức chuỗi rjust ().
Zombie Dice Bots
Trò chơi lập trình là một thể loại trò chơi mà thay vì chơi trò chơi trực tiếp, người chơi viết các chương trình bot để chơi trò chơi một cách tự động. Tôi đã tạo ra một trò chơi giả lập Zombie Dice, cho phép các lập trình viên thực hành các kỹ năng của họ trong khi tạo ra các AI chơi trò chơi. Các bot Dice Zombie có thể đơn giản hoặc cực kỳ phức tạp và rất phù hợp cho một bài tập trong lớp hoặc một thử thách lập trình cá nhân.
Zombie Dice là một trò chơi súc sắc nhanh chóng, vui nhộn từ Steve Jackson Games. Người chơi là những thây ma cố gắng ăn càng nhiều bộ não con người càng tốt mà không bị bắn ba lần. Có một cốc gồm 13 con xúc xắc với bộ não, bước chân và biểu tượng súng ngắn trên mặt. Các biểu tượng súc sắc được tô màu và mỗi màu có khả năng khác nhau cho mỗi sự kiện xảy ra. Mỗi con súc sắc đều có hai mặt với bước chân, nhưng súc sắc có biểu tượng màu xanh lá cây có nhiều mặt hơn với bộ não, xúc xắc biểu tượng màu đỏ có nhiều súng ngắn hơn và xúc xắc biểu tượng màu vàng có sự phân chia đồng đều bộ não và súng ngắn. Thực hiện các thao tác sau trên mỗi lượt người chơi:

  1. Đặt tất cả 13 con xúc xắc vào cốc. Người chơi rút ngẫu nhiên ba con xúc xắc từ chiếc cốc và sau đó cuộn chúng lại. Người chơi luôn cuộn đúng ba viên xí ngầu.

  2. Họ đặt sang một bên và đếm bất kỳ bộ não nào (con người có bộ não ăn) và súng ngắn (con người đã chiến đấu trở lại). Tích lũy ba khẩu súng ngắn tự động kết thúc lượt chơi của người chơi với điểm 0 (bất kể họ có bao nhiêu bộ não). Nếu chúng có từ 0 đến 2 khẩu súng ngắn, họ có thể tiếp tục lăn nếu họ muốn. Họ cũng có thể chọn kết thúc lượt của họ và thu thập một điểm cho mỗi bộ não.

  3. Nếu người chơi quyết định tiếp tục lăn, họ phải lục lại tất cả súc sắc bằng bước chân. Hãy nhớ rằng người chơi phải luôn lăn ba viên xí ngầu; họ phải rút nhiều xúc xắc ra khỏi cốc nếu họ có ít hơn ba bước chân để lăn. Một người chơi có thể tiếp tục gieo xúc xắc cho đến khi họ nhận được ba khẩu súng ngắn, mất tất cả mọi thứ, hoặc tất cả 13 con xúc xắc đã được tung ra. Người chơi không được quay lại chỉ một hoặc hai con xúc xắc và không thể dừng quay giữa chừng.

  4. Khi ai đó đạt 13 bộ não, những người chơi còn lại kết thúc vòng đấu. Người có nhiều bộ não nhất sẽ chiến thắng. Nếu có một trận hòa, các người chơi hòa nhau sẽ chơi một vòng đấu cuối cùng.

Zombie Dice có một cơ chế trò chơi may mắn của bạn: bạn càng quay lại xúc xắc, bạn càng có nhiều bộ não, nhưng cuối cùng bạn sẽ tích lũy được ba khẩu súng ngắn và mất tất cả. Khi một người chơi đạt 13 điểm, những người chơi còn lại sẽ có thêm một lượt (để có khả năng bắt kịp) và trò chơi kết thúc. Người chơi với số điểm cao nhất sẽ chiến thắng. Bạn có thể tìm thấy các quy tắc hoàn chỉnh tại https://github.com/asweigart/zombiedice/.
Cài đặt module zombiedice bằng pip bằng cách đánh vào command line pip install zoombiedice. Bạn có thể chạy bản demo của trình mô phỏng với một số bot được tạo sẵn bằng cách chạy phần sau trong trình vỏ tương tác:

>>> import zombiedice
>>> zombiedice.demo()
Zombie Dice Visualization is running. Open your browser to http://
localhost:51810 to view it.
Press Ctrl-C to quit.

Khi chạy bạn mở một web browser và truy nhập vào sẽ hiện ra hình sau


Bạn sẽ tạo bot bằng cách viết một lớp với phương thức Turn (), đó là
được gọi bởi trình giả lập khi nó bot của bạn lần lượt tung xúc xắc. Các lớp nằm ngoài phạm vi của cuốn sách này, vì vậy mã lớp đã được thiết lập cho bạn trong chương trình myzombie.py, nằm trong tệp ZIP có thể tải xuống cho cuốn sách này tại https://nostarch.com/automatestuff2/. Viết một phương thức về cơ bản giống như viết một hàm và bạn có thể sử dụng mã Turn () trong chương trình myZombie.py làm mẫu. Bên trong phương thức Turn () này, bạn sẽ gọi hàm zombiedice .roll () thường xuyên như bạn muốn bot của mình tung xúc xắc.
• Một bot, sau cuộn đầu tiên, quyết định ngẫu nhiên nếu nó sẽ tiếp tục hoặc dừng lại
• Một bot ngừng lăn sau khi nó đã lăn hai bộ não
• Một bot dừng lăn sau khi nó đã lăn hai khẩu súng ngắn
• Một bot ban đầu quyết định nó sẽ lắc xí ngầu một đến bốn lần, nhưng sẽ dừng lại sớm nếu nó lăn hai khẩu súng ngắn
• Một con bot ngừng lăn sau khi nó lăn nhiều súng hơn so với não
Nếu bạn thấy mình chơi trò chơi này trong thế giới thực, bạn sẽ có lợi ích của hàng ngàn trò chơi mô phỏng cho bạn biết rằng một trong những chiến lược tốt nhất là chỉ cần dừng lại khi bạn bắn hai phát súng ngắn. Nhưng bạn luôn có thể thử vận may của mình. . .
Người dịch: Hungdh

Thông báo: Phần này là phần cuối cùng về Python cơ bản trong cuốn sách ATBS2nd, chúng tôi sẽ dừng việc dịch một thời gian để chúng ta có thể tìm hiểu kĩ hơn Python cơ bản và giải các bài tập của phần này cũng như tìm các bài toán tương tự để tiếp tục học hỏi.

3 Likes

Bài giải của mình cho PrintTable.

# This is simple program about print table

tableData = [['apples', 'oranges', 'cherries', 'banana'],

             ['Alice', 'Bob', 'Carol', 'David'],

             ['dogs', 'cats', 'moose', 'goose']]

colWidths = [0] * len(tableData)

for i in range(len(tableData)):

    colWidths[i] = max(tableData[i], key=len)

maxlenString = max(colWidths, key=len)

lenMaxString = len(maxlenString)

for i in range(0, 4):

    for j in range(len(tableData)):

        print(tableData[j][i].rjust(lenMaxString, " "), end=" ")

    print()
2 Likes

Trong lúc dịch bài, chúng ta có thể uyển chuyển sửa lại code đúng chuẩn PEP-8 ko? Để nguyên văn vầy sợ ghi dấu vào đầu các bạn trẻ. Khó sửa.

2 Likes

Chào Quân,
Cảm ơn bạn đã góp ý nhưng ngay trong chính cuốn sách tác giả đã viết về PEP 8 và lý giải cách đặt tên biến và hàm theo ý tác giả như sau
This book uses camelcase for variable names instead of underscores; that is, variables lookLikeThis instead of looking_like_this. Some experienced programmers may point out that the official Python code style, PEP 8, says that underscores should be used. I unapologetically prefer camelcase and point to the “A Foolish Consistency Is the Hobgoblin of Little Minds” section in PEP 8 itself:
Consistency with the style guide is important. But most importantly: know when to be inconsistent—sometimes the style guide just doesn’t apply. When in doubt, use your best judgment.

Nên chúng tôi thiết nghĩ việc tôn trọng tác giả cũng là một phần trong nguyên tắc của người dịch.
Chúng tôi biết việc học và sử dụng chuẩn quốc tế sẽ đem lại thói quen tốt cho người học và đọc nhưng việc tôn trọng nguyên tác cũng là một phần của việc chúng tôi tôn trọng tác giả.
Cảm ơn bạn đã góp ý.

3 Likes