Last time, I created a deck function of playing cards as shown in here.
Using the previous deck function, this time I implemented the main game function of blackjack. How would you actually write a program and extend what you said from existing requirements? I think I learned a lot by thinking about it!
For the basic rules and requirements, refer to the one in Graduation exam from programming beginners should develop "Blackjack". Thank you!
--The initial card is 52. Make sure there are no duplicate cards when drawing --A two-player match between the player and the dealer. Players run, dealers run automatically --At the start of execution, the player and the dealer each draw two cards. The drawn card is displayed on the screen. However, ** Don't know the dealer's second card ** --After that, the player draws the card first. Burst if the number of players exceeds 21, the game ends at that point --Players can choose to draw the next card each time they draw a card --Once the player has finished drawing, the dealer will continue to draw until his or her hand is 17 or higher. --A game when the player and the dealer finish drawing. The one closer to 21 wins --J, Q and K are treated as 10 -** A is treated only as "1" for the time being. ** Do not set to "11" --No double down, no split, no surrender, no other special rules
This time, in addition to these requirements, I added the following functions.
The following classes are prepared and each file is separated. The Card class and Deck class do not include blackjack-specific specifications so that they can be used in other card games.
I used the one created in this article as it is.
from bj import BlackJack
class Player:
"""
Child (player that can be operated manually)
"""
def __init__(self):
self.win_count = 0
self.hands = []
self.card_current_score = 0
self.card_current_score_sub = 0
self.has_A_card = False
def keep_drawing_card(self, deck):
"""
Let the player decide hit or stand
(The player's turn ends at stand)
Parameters
----------
deck : deck
A set of cards
"""
want_to_draw = True
while want_to_draw:
hit_or_stand_msg = "\nHit(1) or Stand(2) : "
hit_or_stand_res = input(hit_or_stand_msg)
if hit_or_stand_res == "1":
#1 draw for hit
self.draw_card(deck)
print(f"player draw card is : {self.hands[-1]}")
BlackJack.calc_current_score(self)
sub_score = ""
if self.has_A_card is True:
sub_score = \
f", {self.card_current_score_sub}"
print(
f"players's total_score : \
{self.card_current_score}{sub_score}")
#Forced termination of player turn with burst
if BlackJack.is_score_bust(int(self.card_current_score)) and \
BlackJack.is_score_bust(
int(self.card_current_score_sub)):
print("player bust!!!")
want_to_draw = False
if self.card_current_score == 21 or \
self.card_current_score_sub == 21:
#Forced termination when it reaches 21
want_to_draw = False
elif hit_or_stand_res == "2":
#In the case of stand, the turn ends
want_to_draw = False
else:
# 1,Re-enter commands other than 2
print("Is useless")
def draw_card(self, deck, num=1):
"""
Draw a card from the deck and add it to your hand
* Even if different numbers are drawn, it is ok
Parameters
----------
num : int, default 1
Number of times to draw a card
Examples
--------
>>> player.draw_card(2) #2 draws[♠︎-J, ♠︎-10]
>>> player.draw_card(3) # [♦︎-9, ♣️-10, ♠︎-2]
>>> print(player.hands)
[♠︎-J, ♠︎-10, ♦︎-9, ♣️-10, ♠︎-2]
"""
self.hands_store = deck.pick_card(num)
self.hands.extend(self.hands_store)
class Dealer(Player):
"""
Parent (automatic operation)
"""
def keep_drawing_card(self, deck):
"""
dealer keeps drawing cards automatically until it exceeds 17
End when 17 is exceeded
Parameters
----------
deck : object
Current hand
"""
self.has_A_card = False
while self.card_current_score < 17 or \
self.card_current_score_sub < 17:
self.draw_card(deck)
print(f"dealer draw card is : {self.hands[-1]}")
BlackJack.calc_current_score(self)
sub_score = ""
if self.has_A_card:
sub_score = \
f", {self.card_current_score_sub}"
print(
f"dealer's total_score : {self.card_current_score}{sub_score}")
if BlackJack.is_score_bust(self.card_current_score) and \
BlackJack.is_score_bust(
int(self.card_current_score_sub)):
print("dealer bust!!!")
from deck import stock
import role
from bj import BlackJack
class Game:
"""
Main game (create player and dealer instance when creating instance)
Examples
--------
>>> game = Game()
>>> game.main() #Game start (displays the initial phase below)
dealer's hands : [❤︎-7, *-*]
player's hands : [♠︎-9, ♦︎-J]
players's total_score : 19
Hit(1) or Stand(2) :
"""
def __init__(self):
#Create player and dealer
self.player = role.Player()
self.dealer = role.Dealer()
def get_nearest_score(self, score_list):
"""
Returns the number closest to 21 below 21 from the main and sub scores
Returns 0 if both exceed 21
Parameters
----------
score_list : list
List of main and sub scores
Returns
--------
main_score : int
A number close to 21 of the two scores (0 if both are greater than 21)
"""
main_score = 0
for score in score_list:
if score > 21:
#Numbers greater than 21 burst
continue
elif main_score < score:
main_score = score
return main_score
def judge_winner(self, player, dealer):
"""
Win / loss judgment
Parameters
----------
dealer : object
parent
player : object
Child
"""
# player,Get and compare the closer to 21 of 21 or less in each dealer's score
player_score_list = [
player.card_current_score,
player.card_current_score_sub]
player_score = self.get_nearest_score(player_score_list)
dealer_score_list = [
dealer.card_current_score,
dealer.card_current_score_sub]
dealer_score = self.get_nearest_score(dealer_score_list)
judge_win = ""
#Both bursts are draw
if player_score == 0 and dealer_score == 0:
judge_win = "---draw---"
if dealer_score < \
player_score <= 21:
# dealer < player <=At 21, player wins
judge_win = "player win!"
player.win_count += 1
elif player_score <= 21 \
< dealer_score:
#Player wins when player is 21 or less, dealer bursts
judge_win = "player win!"
player.win_count += 1
elif player_score == dealer_score \
and player_score <= 21:
#Neither bursts, and if the numbers are the same, a draw
judge_win = "---draw---"
else:
#Otherwise all players lose
judge_win = "dealer win!"
dealer.win_count += 1
#Console display
print(f"\n/***********/\n/{judge_win}/\n/***********/")
def display_final_result(
self,
player_win_count,
dealer_win_count,
total_count):
"""
Win / loss judgment
Parameters
----------
player_win_count : int
Number of player wins
dealer_win_count : int
Dealer wins
total_count : int
Total number of games
"""
#Calculate the number of draws by subtracting the number of player and dealer wins from the total number of games
draw_count = total_count - player_win_count - dealer_win_count
return f"""\
*-*-*-*-*-*-*-*
total:{total_count}
win:{player_win_count}
lose:{dealer_win_count}
draw:{draw_count}
*-*-*-*-*-*-*-*\
"""
def main(self):
"""
Blackjack main game function
"""
#Deck set (determine the number of sets)
deck = stock.Deck()
total_count = 0
can_play_game = True
#When there are 5 or more cards left
while can_play_game and len(deck.cards) > 5:
self.player.hands = []
self.dealer.hands = []
#Number of games+1
total_count += 1
#Draw two at first
self.player.draw_card(deck, 2)
self.dealer.draw_card(deck, 2)
#player initial score calculation
BlackJack.calc_current_score(self.player)
#If A is subtracted, the sub score is also displayed.
player_sub_score = BlackJack.check_draw_A(self.player)
#Score display at the time of initial draw (one on the dealer side is turned down)
print("\n--Game Start--\n")
first_msg = f"""\
dealer's hands : [{self.dealer.hands[0]}, *-*]
player's hands : {self.player.hands}
players's total_score : {self.player.card_current_score}{player_sub_score}\
"""
print(f"{first_msg}")
#Let the player decide hit or stand (stand ends the player's turn)
self.player.keep_drawing_card(deck)
print("\n--Result--\n")
#dealer score calculation
BlackJack.calc_current_score(self.dealer)
#If A is subtracted, the sub score is also displayed.
dealer_sub_score = BlackJack.check_draw_A(self.dealer)
dealer_msg = f"""\
dealer's hands : {self.dealer.hands}
dealer's total_score : {self.dealer.card_current_score}{dealer_sub_score}\
"""
print(f"{dealer_msg}")
#Draw until the dealer's hand totals 17
self.dealer.keep_drawing_card(deck)
#Win / loss judgment
self.judge_winner(self.player, self.dealer)
print("\n--Game End--\n")
#Game restart
restart_msg = "End the game with Q, start the game otherwise:"
start_res = input(restart_msg)
if start_res == 'Q':
can_play_game = False
#Calculate and display the number of games and the number of wins
final_score_str = self.display_final_result(
self.player.win_count, self.dealer.win_count, total_count)
print(final_score_str)
if __name__ == '__main__':
game = Game()
game.main()
class BlackJack:
"""
Blackjack rules
"""
RANKS = (*"A23456789", "10", *"JQK")
values = list(range(1, 11)) # 1〜10
values.extend([10, 10, 10]) # JQK
VALUES = (values)
#Associate the display mark with the score
# {'A': 1, '2': 2, '3': 3, '4': 4, '5': 5,
# '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
# 'J': 10, 'Q': 10, 'K': 10}
RANK_TO_VALUES = dict(zip(RANKS, VALUES))
@classmethod
def calc_current_score(cls, person):
"""
Calculate current score
Parameters
----------
person : object
Current hand
Returns
--------
card_current_score : int
Current score
"""
person.card_current_score = 0
person.card_current_score_sub = 0
person.has_A_card = False
for card in person.hands:
card_rank = str(card).split("-")[1]
card_value = cls.RANK_TO_VALUES[card_rank]
#Consider the time of A
person.card_current_score += card_value
person.card_current_score_sub += card_value
if card_value == 1:
if person.has_A_card:
#When A is continuous, the subscore is doubled and the subscore is added.+10(+11-1)
person.card_current_score_sub += 10
print(person.card_current_score_sub)
continue
person.has_A_card = True
person.card_current_score_sub += 11
@classmethod
def is_score_bust(cls, total_score):
"""
Calculate current score
Parameters
----------
current_hands : list
Current hand
Returns
--------
True or False
True in burst
"""
return total_score > 21
@classmethod
def check_draw_A(cls, person):
"""
If there is an A in your hand, the subscore is also displayed
Parameters
----------
person : object
player or dealer
Returns
--------
person_sub_score : str
Character string for subscore (empty string if there is no A in your hand)
"""
person_sub_score = ""
if person.has_A_card is True:
person_sub_score = f", {person.card_current_score_sub}"
return person_sub_score
I was worried about this, but I prepared a subscore from the beginning, and when I subtracted A, the console display, When calculating the score, I implemented it as +1 for the main and +11 for the sub. I think there are other better ways. I was able to implement it fairly smoothly up to the point of calculating the score with A as 1, By making it a way to prepare subscores I think it was a bit of a failure that the processing of score calculation increased.
This time we have 2 scores each for player and dealer In each other's list, the score closer to 21 without exceeding 21 was used as the judgment score.
If both scores are burst, the score will be 0, and if one is burst, the other will be the judgment score. → There is no player more than 17 (because there is a draw end at 16) → dealer automatically draws until both scores exceed 17
When executed, it looks like this. Finally, the number of games and the number of player wins are displayed.
$ python main.py
--Game Start--
dealer's hands : [❤︎-J, *-*]
player's hands : [♦︎-3, ♠︎-3]
players's total_score : 6
Hit(1) or Stand(2) : 1
player draw card is : ♠︎-Q
players's total_score : 16
Hit(1) or Stand(2) : 1
player draw card is : ♠︎-5
players's total_score : 21
--Result--
dealer's hands : [❤︎-J, ♦︎-5]
dealer's total_score : 15
dealer draw card is : ❤︎-Q
dealer's total_score : 25
dealer burst!!!
/***********/
/player win!/
/***********/
--Game End--
End the game with Q, start the game otherwise:
--Game Start--
dealer's hands : [♠︎-10, *-*]
player's hands : [♠︎-8, ♦︎-8]
players's total_score : 16
Hit(1) or Stand(2) : 2
--Result--
dealer's hands : [♠︎-10, ♣️-A]
dealer's total_score : 11, 22
dealer draw card is : ♣️-5
dealer's total_score : 16, 27
dealer draw card is : ♣️-Q
dealer's total_score : 26, 37
dealer burst!!!
/***********/
/player win!/
/***********/
--Game End--
End the game with Q, start the game otherwise:
--Game Start--
dealer's hands : [❤︎-K, *-*]
player's hands : [♦︎-A, ♠︎-7]
players's total_score : 8, 19
Hit(1) or Stand(2) : 2
--Result--
dealer's hands : [❤︎-K, ♠︎-J]
dealer's total_score : 20
/***********/
/dealer win!/
/***********/
--Game End--
End the game with Q, start the game otherwise: Q
*-*-*-*-*-*-*-*
total:3
win:2
lose:1
draw:0
*-*-*-*-*-*-*-*
Double down and split are future issues.
Recommended Posts