Tập lệnh Blackjack bằng Python
Gần đây, tôi đã có một bài kiểm tra python và thật không may, tôi đã thất bại. Tôi sẽ làm lại bài kiểm tra của mình và giáo viên đã cho tôi mẹo để làm việc hiệu quả và sạch sẽ hơn. Để thực hành điều này, tôi đã thực hiện một trò chơi blackjack khoảng 2 tuần trước với python và gửi nó cho anh ta để kiểm tra. anh ấy vẫn chưa trả lời và bài kiểm tra của tôi là vào tuần tới. Bất cứ ai có thể xem qua và có thể chỉ ra những điều cần cải thiện? làm ơn, tôi thực sự muốn vượt qua bài kiểm tra này.
import itertools
import random as rd
from time import sleep as s
#making 3 decks with playing cards and assign them 2 to 14
cards1 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards2 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards3 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
#shuffle deck
rd.shuffle(cards)
def blackjack(cards):
money = 10
while True:
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
if money < bet:
print('you dont have that much money....')
else:
playing = True
#draw first card and remove it from the deck
fcard = rd.choice(cards)
cards.remove(fcard)
first_point, first_name = fcard
#check if first card is 11 points or more (to change back to 10 points unless it's ace)
if first_point == 11:
first_point = 10
first_name = str('Jack'+' of '+first_name)
elif first_point == 12:
first_point = 10
first_name = str('Queen'+' of '+first_name)
elif first_point == 13:
first_point = 10
first_name = str('King'+' of '+first_name)
elif first_point == 14:
first_point = 11
first_name = str('Ace'+' of '+first_name)
#show the first drawn card
print(first_point, first_name)
s(0.7)
#draw second card and remove it from the deck
scard = rd.choice(cards)
cards.remove(scard)
second_point, second_name = scard
#checking second card for the same
if second_point == 11:
second_point = 10
second_name = str('Jack'+' of '+second_name)
elif second_point == 12:
second_point = 10
second_name = str('Queen'+' of '+second_name)
elif second_point == 13:
second_point = 10
second_name = str('King'+' of '+second_name)
elif second_point == 14:
second_point = 11
second_name = str('Ace'+' of '+second_name)
#show second card
print(second_point, second_name)
s(0.7)
points = first_point + second_point
#check if first 2 cards make a blackjack
if points == 21:
print('Blackjack!')
bet *= 2
print('you won', bet, 'money')
money += bet
playing = False
print(points, 'points out of 21')
if money == 0:
print('you are broke!')
exit()
#after the first 2 cards i need to determine if the player wants more cards
while playing:
card = input('press enter to draw a card or type x to stop')
if card != 'x':
a = rd.choice(cards)
x, y = a
#going through the same checking system as the first 2 cards
if x == 11:
y = str('Jack'+' of '+second_name)
x = 10
elif x == 12:
y = str('Queen'+' of '+second_name)
x = 10
elif x == 13:
y = str('King'+' of '+second_name)
x = 10
elif x == 14:
y = str('Ace'+' of '+second_name)
x = 11
print(x, y)
s(0.7)
cards.remove(a)
points += x
if points > 21:
print('BUST')
points = 0
playing = False
#if the player has x as input the player stops drawing
elif card == 'x':
playing = False
print(points, 'points')
#let the dealer do the same card drawing
result = dealer_draw(cards)
print('you scored: ', points, '\n', 'the bank scored: ', result)
s(0.7)
#compare obtained points with the dealer's points
if points > result:
print('you win!')
money += bet
elif points == result:
print('draw')
elif points < result:
print('you lose')
money -= bet
elif points == 0 and result == 0:
print('you lose')
money -= bet
def dealer_draw(cards):
#2 empty prints to maintain clear overview
print()
print()
a = 0
#first 2 cards (same as for the player until.....)
cd1 = rd.choice(cards)
cards.remove(cd1)
points_first, name_first = cd1
if points_first == 11:
name_first = str('Jack'+' of '+name_first)
points_first = 10
elif points_first == 12:
name_first = str('Queen'+' of '+name_first)
points_first = 10
elif points_first == 13:
name_first = str('King'+' of '+name_first)
points_first = 10
elif points_first == 14:
name_first = str('Jack'+' of '+name_first)
points_first = 11
print(points_first, name_first)
s(0.7)
cd2 = rd.choice(cards)
cards.remove(cd2)
points_second, name_second = cd2
if points_second == 11:
name_second = str('Jack'+' of '+name_second)
points_second = 10
elif points_second == 12:
name_second = str('Queen'+' of '+name_second)
points_second = 10
elif points_second == 13:
name_second = str('King'+' of '+name_second)
points_second = 10
elif points_second == 14:
name_second = str('Ace'+' of '+name_second)
points_second = 11
print(points_second, name_second)
s(0.7)
#..... here (scroll up)
full_points = points_first + points_second
a += full_points
#have the minimal bank draw set at 16
while a < 16:
print("bank's total = ", a)
s(0.7)
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
if add_number == 11:
full_name = str('Jack'+' of '+full_name)
add_number = 10
elif add_number == 12:
full_name = str('Queen'+' of '+full_name)
add_number = 10
elif add_number == 13:
full_name = str('King'+' of '+full_name)
add_number = 10
elif add_number == 14:
full_name = str('Ace'+' of '+full_name)
add_number = 11
print(add_number, full_name)
s(0.7)
a += add_number
print("bank's total = ", a)
s(0.7)
#check if bank scored more than 21 and if so, return 0
if a > 21:
return 0
else:
return a
blackjack(cards)
Mọi ý kiến đều được hoan nghênh nhưng xin lưu ý rằng đây là ngôn ngữ lập trình đầu tiên của tôi và tôi vẫn còn rất nhiều điều để học hỏi. Cảm ơn!
Trả lời
Tôi xin lỗi nhưng kiến thức của tôi về trò chơi bài là gỉ. Xin vui lòng sửa cho tôi nếu có gì đó sai!
Luôn bắt đầu vào không hợp lệ
Giả sử rằng người dùng sẽ nhập một thứ gì đó, được nhắc cho anh ta từ dòng mã này
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
chọn số tiền để đặt cược:
Bây giờ, những gì nếu người dùng vô tình bước vào E . Trong trường hợp này, chương trình của bạn sẽ không thành công vì nó yêu cầu đầu vào ở dạng số nguyên. Đây là lý do tại sao bạn nên luôn bắt đầu vào không hợp lệ bằng cách sử dụng Thử và Ngoại trừ trong Python
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
Bằng cách này, nếu người dùng đã nhập
chọn số tiền là: Tôi thích python
Nó sẽ cung cấp cho người dùng
Đâu vao không hợp lệ! Vui lòng nhập một số
Không thoát sau khi đầu vào không hợp lệ / không hợp lệ
Trong chương trình của bạn, nếu người dùng đặt cược nhiều hơn số tiền anh ta có, chương trình sẽ dừng lại. Nó sẽ không phát lại, tại sao điều này lại xảy ra?
Bạn nên yêu cầu người dùng nhập lại thông tin đầu vào hợp lệ, để bất kỳ sai sót nào của họ sẽ không dẫn đến việc chấm dứt chương trình ngay lập tức
while True:
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
continue
if bet > money:
print("Bet placed higher than balance!")
continue
break
Điều tốt nhất cần làm bây giờ là chuyển nó sang một chức năng riêng biệt được gọi là take_input(), để blackjack()chức năng của bạn có thể vẫn sạch và giờ đây việc lấy đầu vào thật dễ dàng
bet = take_input()
Có, bạn đã viết thêm một vài dòng mã. Nhưng bây giờ bạn biết chương trình của bạn sẽ làm điều đúng đắn khi Exceptions xảy ra.
Đơn giản hóa mã - 1
first_name = str('Jack'+' of '+first_name)
Giống như
first_name = "Jack of " + first_name
Bạn không cần phải chuyển đổi thành strnhư first_namelà một chuỗi.
Điều tương tự cũng áp dụng cho các dòng sau mà tôi đã trích xuất từ mã của bạn.
first_name = str('Queen'+' of '+first_name)
first_name = str('King'+' of '+first_name)
first_name = str('Ace'+' of '+first_name)
Tránh những con số ma thuật
Lấy ví dụ này
if first_point == 11:
first_point = 10
first_name = str('Jack'+' of '+first_name)
elif first_point == 12:
first_point = 10
first_name = str('Queen'+' of '+first_name)
elif first_point == 13:
first_point = 10
first_name = str('King'+' of '+first_name)
elif first_point == 14:
first_point = 11
first_name = str('Ace'+' of '+first_name)
10, 11, 12... được gọi là con số kỳ diệu . Tôi đã phải suy nghĩ trong lúc để hiểu những gì họ đang làm ở đây cho đến khi cuối cùng tôi hiểu rằng họ là những quân bài.
Cách tốt để giải quyết vấn đề này là sử dụng enums của Python .
from enum import Enum
class Card(Enum):
jack = 11
queen = 12
king = 13
....
Sửa các giá trị nếu chúng sai.
Giờ đây, chuỗi if-else của bạn trông rõ ràng hơn rất nhiều đối với người đọc
if first_point == Card.jack.value:
...
elif first_point == Card.queen.value:
...
elif first_point = Card.king.value:
....
Một điểm cộng nữa là nếu bạn muốn thay đổi giá trị của vua từ xsang thì sao y. Bạn sẽ đi đến hàng trăm nơi để tìm nơi bạn có thể đã sử dụng hằng số trong ngữ cảnh cho nhà vua?
ở đây bạn có thể đặt king.valuethành bất cứ thứ gì bạn muốn.
import sleep as s
import sleep as ss(0.5)Điều này cũng khiến tôi bối rối ngay từ đầu, tôi phải tìm hiểu sý nghĩa của nó. skhông có ý nghĩa gì cả, nó chỉ gây nhầm lẫn cho bất kỳ ai đọc mã của bạn. Tuy nhiên, sleeprõ ràng ngụ ý rằng bạn muốn ... Ngủ! Luôn sử dụng những cái tên có ý nghĩa
Chia công việc thành các chức năng
Hiện tại, blackjack()chức năng của bạn đang lộn xộn với rất nhiều tác vụ cần được chuyển sang các chức năng riêng của chúng. Cũng giống như chúng ta đã chuyển thủ tục nhập vào một take_input()hàm riêng biệt , bạn có thể tạo nhiều hàm có ý nghĩa như draw_new_card()vậy có thể trả về một lá bài mới từ bộ bài.
Mã của bạn là KHÔ hay ƯỚT
Xin lỗi kiến thức của tôi về trò chơi bài
Bạn có thủ tục
- rút thẻ
- kiểm tra xem thẻ có
>=11 điểm không - in điểm và tên
Sau đó, tại sao lặp lại điều tương tự một lần nữa cho thẻ thứ hai? Bạn đã viết điều tương tự hai lần. Một lần cho thẻ đầu tiên và tiếp theo cho thẻ thứ hai. bạn đã lặp lại chính mình. Cách tốt nhất là lặp lại yếu tố thành một hàm. Vì vậy, tất cả những gì bạn cần làm là
def new_card():
card = draw_new_card()
point, name = card
process_card(point, name)
return point, name
# in the blackjack function #
first_point, first_name = new_card()
print(first_point, first_name)
sleep(0.5)
second_point, second_name = new_card()
print(second_point, second_name)
......
Bạn có thể thấy rằng việc sử dụng các hàm đã giúp ích rất nhiều.
Quy ước đặt tên
Chỉ để củng cố quan điểm của @Aryan Parekh: Không sử dụng các từ viết tắt vô nghĩa, ví dụ:
import random as rd
from time import sleep as s
Không có lợi ích gì, bạn đã làm cho mã khó đọc và khó hiểu hơn. Vì vậy: sử dụng random.choice(cards)thay vì: rd.choice(cards). random.choice là tự giải thích.
Mã tốt phải trực quan, bắt đầu với các quy ước đặt tên phù hợp. Ngay cả khi bạn lười biếng, bạn nên sử dụng các tên dài hơn và mô tả nhiều hơn, IDE của bạn dù sao cũng nên có tính năng tự động hoàn thành.
Bạn có các biến như a, cd2, x, y khiến tôi nhớ đến món spaghetti Basic từ những năm 80. Tôi hoàn toàn mê game bài nên tôi không thể bình luận nhiều về thuật toán nhưng tôi có thể bình luận về mã.
May mắn thay, bạn đưa ra một số nhận xét.
Tính nhất quán
Bạn sử dụng hàm lựa chọn một vài lần nhưng với các tên biến rất khác nhau:
a = rd.choice(cards)
x, y = a
và sau đó:
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
Tôi nghĩ rằng cần có sự nhất quán hơn ở đây. Nếu bạn sử dụng lại một số câu lệnh, bạn cũng có thể sử dụng các tên biến tương tự ở nơi khác hoặc ít nhất là bám vào một số mẫu đặt tên có ý nghĩa. draw là một cái tên có ý nghĩa. Nhưng add_number thực sự trông giống như một tên hàm, vì vậy tôi sẽ gọi nó là card_number hoặc một cái gì đó tương tự (mặc dù bạn đang sử dụng hiệu quả biến đó để tăng giá trị khác).
Sự lặp lại
Có sự lặp lại trong mã của bạn, ví dụ:
#making 3 decks with playing cards and assign them 2 to 14
cards1 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards2 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards3 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
Trước hết, một số câu lệnh là thừa:
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
Vì bạn đang nối ba danh sách nên đối tượng kết quả cũng là một đối tượng danh sách. Vì vậy, cards = cards1 + cards2 + cards3là đủ và mang lại kết quả tương tự.
Các thẻ 1/2 hoàn toàn giống nhau, vì vậy bạn lặp lại chính xác điều đó 3 lần liên tiếp. Điều này rõ ràng là sai và có thể được đơn giản hóa. Bạn chỉ cần viết:
cards2 = cards1
cards3 = cards1
mặc dù điều đó không thanh lịch nhưng ít nhất bạn tránh được sự lặp lại và phạm vi của bạn được khai báo chỉ một lần.
Một cách tốt hơn:
cards = list(itertools.product(range(2, 15), ['spade', 'heart', 'diamond', 'club'])) *3
Như vậy, bạn đã lặp lại trình tự của mình ba lần và tạo một danh sách mới. Vì bạn đang sử dụng itertools, bạn cũng có thể sử dụng itertools.repeat, nó cung cấp cho bạn một trình tạo, trong khi * ncung cấp cho bạn một danh sách, điều này rất ổn ở đây.
Kết nối
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
if add_number == 11:
full_name = str('Jack'+' of '+full_name)
add_number = 10
full_name là một chuỗi, vì vậy bạn có thể nối tất cả các mục này một cách an toàn. Hoặc tốt hơn, hãy sử dụng chuỗi F (Python> = 3.6):
full_name = f"Jack of {full_name}"