二十一点是一种在赌场玩的纸牌游戏。该游戏的参与者不是相互竞争,而是与赌场指定的庄家竞争。在本文中,我们将从头开始创建玩家和庄家之间可以在终端上玩的二十一点游戏。
二十一点规则
我们将为从未玩过二十一点的读者提供一套简短的规则。Blackjack 的神奇数字是 21。将发给玩家的所有牌的值相加,如果总和超过 21,玩家就会爆牌并立即输掉。
如果玩家得到的点数正好是 21,则该玩家将战胜庄家。否则,为了获胜,闲家的牌总和必须大于庄家的牌总和。
每张花牌的固定值为 10,而 A 可以根据玩家获胜的机会计算为 1 或 11。其余卡片的价值由其数量决定。
二十一点游戏中的发牌流程如下:
- 一张牌面朝上发给玩家(每个人都可以看到)。
- 庄家给自己发一张所有人都能看到的牌。
- 另一张牌面朝上发给玩家。
- 庄家为自己发一张面朝下的牌。
- 玩家必须决定是否保留当前的牌组或获得另一张牌。
- 如果玩家决定击牌,则会发另一张牌。
- 如果玩家决定停牌,则庄家会亮出他隐藏的牌。
- 庄家无权决定是跟牌还是停牌。一般规则是,如果庄家的牌总数小于 17 点,则庄家需要继续打更多的牌。
- 一旦庄家的牌总数达到 17 点或以上,庄家就必须停牌。
- 根据最终牌的总和决定胜负。
一旦理解了规则,二十一点游戏的编程就会变得简单。从头开始创建基于终端的游戏需要三个主要组成部分:游戏设计、游戏逻辑和玩家交互管理。
二十一点游戏演示
用 Python 设计二十一点
首先,我们将致力于游戏的设计。我们的工作是在终端上有效地显示一系列卡片,如下图所示。
我们需要一个打印卡片序列并且与卡片数量无关的函数。此外,它必须提供在需要时打印隐藏卡片的功能。
下面的代码解决了我们的问题。
# Function to print the cards def print_cards(cards, hidden): s = "" for card in cards: s = s + "\t ________________" if hidden: s + = "\t ________________" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: if card.value = = '10' : s = s + "\t| {} |" . format (card.value) else : s = s + "\t| {} |" . format (card.value) if hidden: s + = "\t| |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| {} |" . format (card.suit) if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: if card.value = = '10' : s = s + "\t| {} |" . format (card.value) else : s = s + "\t| {} |" . format (card.value) if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t|________________|" if hidden: s + = "\t|________________|" print (s) print () |
每张卡的详细信息都存储为卡对象。该print_cards()
函数的第二个参数是一个布尔值,指示是否显示隐藏的卡牌。
创建卡片
在类和对象的帮助下,我们可以创建一组花色和值来表示“扑克牌”。在二十一点中,一张牌具有三个属性:它的花色、它的代表值和它的分数值。
所有上述属性均保留在以下卡类别中。
# The Card Class definition class Card: def __init__( self , suit, value, card_value): # Suit of the Card like Spades and Clubs self .suit = suit # Representing Value of the Card like A for Ace, K for King self .value = value # Score Value for the Card like 10 for King self .card_value = card_value |
使用上面的类,我们可以创建一副包含 52 个 Card 对象的合适的牌。
一些基本价值观
每个纸牌游戏都需要基本值,例如花色类型、纸牌类型以及每张纸牌的值。
# The type of suit suits = [ "Spades" , "Hearts" , "Clubs" , "Diamonds" ] # The suit value suits_values = { "Spades" : "\u2664" , "Hearts" : "\u2661" , "Clubs" : "\u2667" , "Diamonds" : "\u2662" } # The type of card cards = [ "A" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "J" , "Q" , "K" ] # The card value cards_values = { "A" : 11 , "2" : 2 , "3" : 3 , "4" : 4 , "5" : 5 , "6" : 6 , "7" : 7 , "8" : 8 , "9" : 9 , "10" : 10 , "J" : 10 , "Q" : 10 , "K" : 10 } |
这里需要注意的一件事是,A 最初被标记为 11 点牌。该策略背后的想法是,每当闲家/庄家的分数似乎超过 21 点时,我们就可以将 Ace(如果发牌)的分数减少到 1。
我们稍后将在本文中看到减少的实现。
生成一副扑克牌
一副普通的扑克牌由 52 张牌组成,每张牌都有不同的花色和点数组合。使用上述基本值和卡片类别,我们生成一副卡片。
# The deck of cards deck = [] # Loop for every type of suit for suit in suits: # Loop for every type of card in a suit for card in cards: # Adding card to the deck deck.append(Card(suits_values[suit], card, cards_values[card])) |
实际上,二十一点游戏涉及多个牌组,因此上述循环集可以重复用于填充多个牌组。
新创建的牌组将传递给执行游戏的函数。
blackjack_game(deck) |
让我们了解玩家和基于计算机的荷官之间的二十一点游戏单次迭代背后的游戏逻辑。
声明重要的游戏变量
在任何时刻,我们都需要以下游戏变量:
- 发给玩家和庄家的牌列表。
- 每方的牌值之和。
# Function for a single game of blackjack def blackjack_game(deck): global cards_values # Cards for both dealer and player player_cards = [] dealer_cards = [] # Scores for both dealer and player player_score = 0 dealer_score = 0 |
当我们设计游戏逻辑时,这些游戏变量就会发挥作用。
Python 二十一点游戏逻辑
整个游戏逻辑围绕着发牌和玩家选择击牌或站立。当我们处理好以上两件事后,我们这一天就完成了。
发牌第一阶段:强制牌
最初的发牌涉及向玩家和庄家发两张牌。然而,庄家的第二张牌仍然未知。
# Initial dealing for player and dealer while len (player_cards) < 2 : # Randomly dealing a card player_card = random.choice(deck) player_cards.append(player_card) deck.remove(player_card) # Updating the player score player_score + = player_card.card_value # In case both the cards are Ace, make the first ace value as 1 if len (player_cards) = = 2 : if player_cards[ 0 ].card_value = = 11 and player_cards[ 1 ].card_value = = 11 : player_cards[ 0 ].card_value = 1 player_score - = 10 # Print player cards and score print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) input () # Randomly dealing a card dealer_card = random.choice(deck) dealer_cards.append(dealer_card) deck.remove(dealer_card) # Updating the dealer score dealer_score + = dealer_card.card_value # Print dealer cards and score, keeping in mind to hide the second card and score print ( "DEALER CARDS: " ) if len (dealer_cards) = = 1 : print_cards(dealer_cards, False ) print ( "DEALER SCORE = " , dealer_score) else : print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) # In case both the cards are Ace, make the second ace value as 1 if len (dealer_cards) = = 2 : if dealer_cards[ 0 ].card_value = = 11 and dealer_cards[ 1 ].card_value = = 11 : dealer_cards[ 1 ].card_value = 1 dealer_score - = 10 input () # Player gets a blackjack if player_score = = 21 : print ( "PLAYER HAS A BLACKJACK!!!!" ) print ( "PLAYER WINS!!!!" ) quit() |
看似简单的交易可能需要吸收很多东西。我们先来理解一下上面代码所涉及的流程:
- 主循环一直运行,直到玩家和庄家各拿到两张牌为止。
- 从牌组中随机选择一张牌,并在下一步中将该牌从牌组中移除。
- 该卡的价值将添加到玩家的分数中。
- 同样,为庄家随机选择一张牌,并将其值添加到庄家的分数中。
- 玩家的牌正常显示在屏幕上。
- 庄家的牌会小心地展示,以免第二张牌及其面值被泄露。
- 如果任何一个参与者获得双 A,他们的分数将被调整,这样他们都不会被淘汰。
- 当上述一切顺利进行后,我们就进入第二阶段的交易。
注:闲家和庄家的分数调整存在细微差别。在前一种情况下,调整第一张牌的值,而在后一种情况下,调整第二张牌的值。
调整第二张牌数值的原因是,如果我们调整第一张牌,我们就会暴露隐藏牌的身份:A。
这里需要做的最后一件事是检查玩家是否已经拥有二十一点。如果他这样做了,玩家获胜并且游戏结束。
注意:该
input()
功能暂停程序,直到玩家按“ENTER”键。这可以防止所有游戏事件快速失败。该
clear()
函数负责清理终端,为游戏提供干净的美感。
发牌第二阶段:玩家选择
发牌的第二阶段取决于玩家的决定,是想要另一张牌来提高分数,还是保留当前的牌组。
# Print dealer and player cards print ( "DEALER CARDS: " ) print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) print () print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) # Managing the player moves while player_score < 21 : choice = input ( "Enter H to Hit or S to Stand : " ) # Sanity checks for player's choice if len (choice) ! = 1 or (choice.upper() ! = 'H' and choice.upper() ! = 'S' ): clear() print ( "Wrong choice!! Try Again" ) # If player decides to HIT if choice.upper() = = 'H' : # Dealing a new card player_card = random.choice(deck) player_cards.append(player_card) deck.remove(player_card) # Updating player score player_score + = player_card.card_value # Updating player score in case player's card have ace in them c = 0 while player_score > 21 and c < len (player_cards): if player_cards[c].card_value = = 11 : player_cards[c].card_value = 1 player_score - = 10 c + = 1 else : c + = 1 clear() # Print player and dealer cards print ( "DEALER CARDS: " ) print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) print () print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) # If player decides to Stand if choice.upper() = = 'S' : break # Check if player has a Blackjack if player_score = = 21 : print ( "PLAYER HAS A BLACKJACK" ) quit() # Check if player busts if player_score > 21 : print ( "PLAYER BUSTED!!! GAME OVER!!!" ) quit() |
玩家决定是击牌还是停牌,直到分数超过21或者玩家决定停牌。发给玩家的牌张数没有限制,仅受分数限制。
每次玩家决定击牌时,都会从牌堆中发出一张新牌,并更新分数。如前所述,Ace 可以计为 1 或 11。如果分数超过 21,则一段特殊的代码会将 Ace 的值从 11 转换为 1。
当玩家对当前分数感到满意时,他就站立。当他这样做时,我们在进行一些强制性检查(例如二十一点或爆牌场景)后进入发牌的最后阶段。
发牌的最后阶段:庄家的牌
在发牌的最后阶段,庄家隐藏的牌被揭开,庄家的分数也随之揭晓。根据标准的二十一点规则,庄家必须给自己发更多的牌,直到其分数大于或等于 17 点。
# Managing the dealer moves while dealer_score < 17 : clear() print ( "DEALER DECIDES TO HIT....." ) # Dealing card for dealer dealer_card = random.choice(deck) dealer_cards.append(dealer_card) deck.remove(dealer_card) # Updating the dealer's score dealer_score + = dealer_card.card_value # Updating player score in case player's card have ace in them c = 0 while dealer_score > 21 and c < len (dealer_cards): if dealer_cards[c].card_value = = 11 : dealer_cards[c].card_value = 1 dealer_score - = 10 c + = 1 else : c + = 1 # print player and dealer cards print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) print () print ( "DEALER CARDS: " ) print_cards(dealer_cards, False ) print ( "DEALER SCORE = " , dealer_score) input () |
庄家继续击牌,直到分数超过 17 分。如果需要的话,我们有一个类似的实现,将 A 的牌值从 11 转换为 1。
游戏终局
当庄家的分数为 17 或更高时,我们进入最终游戏,其中包括比较数值并提名游戏的获胜者。可能有以下几种情况:
- 庄家爆牌 – 庄家的分数超过 21。
- 庄家有二十一点 – 庄家的准确分数为 21 点。
- 平局游戏 – 玩家和庄家的分数相同。
- 玩家获胜 – 玩家的分数高于庄家的分数。
- 庄家获胜 – 庄家的分数比玩家的分数高。
我们检查上述每种可能性并宣布获胜者。
# Dealer busts if dealer_score > 21 : print ( "DEALER BUSTED!!! YOU WIN!!!" ) quit() # Dealer gets a blackjack if dealer_score = = 21 : print ( "DEALER HAS A BLACKJACK!!! PLAYER LOSES" ) quit() # TIE Game if dealer_score = = player_score: print ( "TIE GAME!!!!" ) # Player Wins elif player_score > dealer_score: print ( "PLAYER WINS!!!" ) # Dealer Wins else : print ( "DEALER WINS!!!" ) |
这结束了玩家和庄家之间的二十一点游戏的单次迭代。
二十一点游戏的完整 Python 代码
import random import os import time # The Card class definition class Card: def __init__( self , suit, value, card_value): # Suit of the Card like Spades and Clubs self .suit = suit # Representing Value of the Card like A for Ace, K for King self .value = value # Score Value for the Card like 10 for King self .card_value = card_value # Clear the terminal def clear(): os.system( "clear" ) # Function to print the cards def print_cards(cards, hidden): s = "" for card in cards: s = s + "\t ________________" if hidden: s + = "\t ________________" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: if card.value = = '10' : s = s + "\t| {} |" . format (card.value) else : s = s + "\t| {} |" . format (card.value) if hidden: s + = "\t| |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * * |" print (s) s = "" for card in cards: s = s + "\t| {} |" . format (card.suit) if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: s = s + "\t| |" if hidden: s + = "\t| |" print (s) s = "" for card in cards: if card.value = = '10' : s = s + "\t| {} |" . format (card.value) else : s = s + "\t| {} |" . format (card.value) if hidden: s + = "\t| * |" print (s) s = "" for card in cards: s = s + "\t|________________|" if hidden: s + = "\t|________________|" print (s) print () # Function for a single game of blackjack def blackjack_game(deck): # Cards for both dealer and player player_cards = [] dealer_cards = [] # Scores for both dealer and player player_score = 0 dealer_score = 0 clear() # Initial dealing for player and dealer while len (player_cards) < 2 : # Randomly dealing a card player_card = random.choice(deck) player_cards.append(player_card) deck.remove(player_card) # Updating the player score player_score + = player_card.card_value # In case both the cards are Ace, make the first ace value as 1 if len (player_cards) = = 2 : if player_cards[ 0 ].card_value = = 11 and player_cards[ 1 ].card_value = = 11 : player_cards[ 0 ].card_value = 1 player_score - = 10 # Print player cards and score print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) input () # Randomly dealing a card dealer_card = random.choice(deck) dealer_cards.append(dealer_card) deck.remove(dealer_card) # Updating the dealer score dealer_score + = dealer_card.card_value # Print dealer cards and score, keeping in mind to hide the second card and score print ( "DEALER CARDS: " ) if len (dealer_cards) = = 1 : print_cards(dealer_cards, False ) print ( "DEALER SCORE = " , dealer_score) else : print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) # In case both the cards are Ace, make the second ace value as 1 if len (dealer_cards) = = 2 : if dealer_cards[ 0 ].card_value = = 11 and dealer_cards[ 1 ].card_value = = 11 : dealer_cards[ 1 ].card_value = 1 dealer_score - = 10 input () # Player gets a blackjack if player_score = = 21 : print ( "PLAYER HAS A BLACKJACK!!!!" ) print ( "PLAYER WINS!!!!" ) quit() clear() # Print dealer and player cards print ( "DEALER CARDS: " ) print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) print () print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) # Managing the player moves while player_score < 21 : choice = input ( "Enter H to Hit or S to Stand : " ) # Sanity checks for player's choice if len (choice) ! = 1 or (choice.upper() ! = 'H' and choice.upper() ! = 'S' ): clear() print ( "Wrong choice!! Try Again" ) # If player decides to HIT if choice.upper() = = 'H' : # Dealing a new card player_card = random.choice(deck) player_cards.append(player_card) deck.remove(player_card) # Updating player score player_score + = player_card.card_value # Updating player score in case player's card have ace in them c = 0 while player_score > 21 and c < len (player_cards): if player_cards[c].card_value = = 11 : player_cards[c].card_value = 1 player_score - = 10 c + = 1 else : c + = 1 clear() # Print player and dealer cards print ( "DEALER CARDS: " ) print_cards(dealer_cards[: - 1 ], True ) print ( "DEALER SCORE = " , dealer_score - dealer_cards[ - 1 ].card_value) print () print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) # If player decides to Stand if choice.upper() = = 'S' : break clear() # Print player and dealer cards print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) print () print ( "DEALER IS REVEALING THE CARDS...." ) print ( "DEALER CARDS: " ) print_cards(dealer_cards, False ) print ( "DEALER SCORE = " , dealer_score) # Check if player has a Blackjack if player_score = = 21 : print ( "PLAYER HAS A BLACKJACK" ) quit() # Check if player busts if player_score > 21 : print ( "PLAYER BUSTED!!! GAME OVER!!!" ) quit() input () # Managing the dealer moves while dealer_score < 17 : clear() print ( "DEALER DECIDES TO HIT....." ) # Dealing card for dealer dealer_card = random.choice(deck) dealer_cards.append(dealer_card) deck.remove(dealer_card) # Updating the dealer's score dealer_score + = dealer_card.card_value # Updating player score in case player's card have ace in them c = 0 while dealer_score > 21 and c < len (dealer_cards): if dealer_cards[c].card_value = = 11 : dealer_cards[c].card_value = 1 dealer_score - = 10 c + = 1 else : c + = 1 # print player and dealer cards print ( "PLAYER CARDS: " ) print_cards(player_cards, False ) print ( "PLAYER SCORE = " , player_score) print () print ( "DEALER CARDS: " ) print_cards(dealer_cards, False ) print ( "DEALER SCORE = " , dealer_score) input () # Dealer busts if dealer_score > 21 : print ( "DEALER BUSTED!!! YOU WIN!!!" ) quit() # Dealer gets a blackjack if dealer_score = = 21 : print ( "DEALER HAS A BLACKJACK!!! PLAYER LOSES" ) quit() # TIE Game if dealer_score = = player_score: print ( "TIE GAME!!!!" ) # Player Wins elif player_score > dealer_score: print ( "PLAYER WINS!!!" ) # Dealer Wins else : print ( "DEALER WINS!!!" ) if __name__ = = '__main__' : # The type of suit suits = [ "Spades" , "Hearts" , "Clubs" , "Diamonds" ] # The suit value suits_values = { "Spades" : "\u2664" , "Hearts" : "\u2661" , "Clubs" : "\u2667" , "Diamonds" : "\u2662" } # The type of card cards = [ "A" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "J" , "Q" , "K" ] # The card value cards_values = { "A" : 11 , "2" : 2 , "3" : 3 , "4" : 4 , "5" : 5 , "6" : 6 , "7" : 7 , "8" : 8 , "9" : 9 , "10" : 10 , "J" : 10 , "Q" : 10 , "K" : 10 } # The deck of cards deck = [] # Loop for every type of suit for suit in suits: # Loop for every type of card in a suit for card in cards: # Adding card to the deck deck.append(Card(suits_values[suit], card, cards_values[card])) blackjack_game(deck) |
读者没有义务遵循整个编码顺序。通过添加多个玩家对抗庄家的设施,可以对上述代码进行各种修改。
结论
二十一点游戏一开始可能看起来简单且随机,但只有当玩家遵循特定策略(例如算牌)时,游戏才会变得复杂。
世界各地有许多版本的二十一点,例如瑞典酒吧二十一点和家庭游戏二十一点。好奇的读者可以了解这些变体,并尝试使用本文中获得的知识来实现它们。
感谢您的阅读。请随意查看如何使用Python 开发 Mastermind 游戏。