it공부 (개념)

파이썬으로 블랙잭게임 만들기 후기

cantor 2022. 12. 7. 15:23

Dr Angela Yu 의 100day of codes
day 11 첫번째캡스톤프로젝트: 블랙젝 게임만들기에 도달했다.

블랙잭이란?

트럼프카드 혹은 플레잉카드로 즐기는 수읽기 게임으로
21을 넘지 않는선에서, 숫자의 총합이 더 높은 카드들을 획득한 플레이어가 이긴다.

게임은 여기서 해볼 수있다.
https://games.washingtonpost.com/games/blackjack

2,3,4,5,6,7,8,9,10 의 카드들은 각각 카드의 숫자와 일치하는 점수를 가지고있으며,
에이스A(1) 는 11점, J,Q,K는 10점의 점수를 가지고있다

게임의 진행은이렇다

  1. 이번 라운드에 배팅할 돈을 정한다.

  2. 딜러와 플레이어는 각각 카드를 두장씩 받는다. 딜러는 플레이어에게 카드를 한장 공개한다.

  3. 플레이어는 Stand, Hit 혹은 double 중 한가지를 선택한다

  4. player가 stand를 누른 후 딜러가 카드를 뽑는다.이후 두 사람의 점수를 비교하여 라운드의 승자를 정한다.

처음 두장의 카드를 손에받았을때 21점을 이미 가지고있다면그것을 black jack이다. 게임을 더 진행할것없이 자동으로 승리하고, 배팅한 돈의 두배를 딴다

딜러가 black jack이면 딜러가 승리한다.

배팅한 돈을 잃는다

둘다 black jack이면 비긴다.
배팅한 돈을 돌려받는다

black jack으로 승부가 안난다면,
stand: 내 카드에만족하고 라운드 결과를 확인한다
Hit: 카드를 한장 더 뽑는다
double: 배팅을 두배로 늘린다

Hit을 선택할경우

나는 카드를 한장 더 받는다.이 때, 내 카드의 숫자합이 21을초과하면 bust! 패배한다.
만약 내카드가 3장이라면 hit와 stand 중 하나를 고르는 행위를 다시 해야한다.

stand를 선택할 경우

딜러에게 차례가 넘어간다. 딜러는 자신의 점수가 17점 미만인경우, 17점이 넘어갈 때까지 카드를 계속해서 뽑는다,
이때, 17점이상, 21점이하인 점수가되면 딜러의차례가 끝나고 서로카드를 비교해 점수가 높은사람이 승자가된다.

만일 딜러의점수가 21점을 넘어간다면 딜러가 bust!! 내가 이기게 된다.

게임은 여기서 할 수있다.

아래는 선생님의 설명을 듣기전 내가 짠코드이다.

import random  
import art
cards = \[11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10\]  
bank = 1000  
betting\_money = 0  
replay = True  
print(art.logo)
def bet(money):  
global bank  
global betting\_money  
if bank - money < 0:  
print(  
f"you have ${bank} in your bank/n please type lower or equal money"  
)  
return "again"  
else:  
bank = (bank - money)  
betting\_money = (money)  

돈을 배팅하는 함수이다.
여기서부터 bank, betting_money, cards등을 전역 변수로 사용했다.
함수내부에서 전역변수를 불러오는것이 안좋은것은 알고있다.
단지 처음이라 일단 구현해 보기 위해 강행한 선택이다.

"""

def start():  
global cards  
dealer\_cards = \[\]  
user\_cards = \[\]  
dealer\_cards.append(random.choice(cards))  
dealer\_cards.append(random.choice(cards))  
user\_cards.append(random.choice(cards))  
user\_cards.append(random.choice(cards))  
print(f" dealer's first card {dealer\_cards\[0\]}")  
print(f"your cards{user\_cards}")  
choice\_round(user\_cards, dealer\_cards)  

'''
게임을 시작하고 처음에 카드를 나눠받은후 딜러의 카드를 한장 보여주는 함수이다.
여기서 리스트는 += 연산으로 추가하지말고 append함수를 사용해야함을 배웠다
+=로 추가할경우 저장이 안된다. 지금보니까 dealer_cards와 user_cards가

검색해보니까 알게된사실
list에 element를 추가하는 함수는 append이고

list에 +=연산을 하려면 그 대상도 list여야 한다

즉 list += list2
ilst == list와 list2를 합친 새로운 리스트
+= 연산은 extend로 할 수있다.

def choice\_round(user\_cards, dealer\_cards):  
global cards  
global bank  
global betting\_money  
user\_choice = ""  
while user\_choice != "double" and user\_choice != "hit" and user\_choice != "stand":  
user\_choice = input(f"Hit, Stand, Double? \\n bank : {bank}, betting: {betting\_money}").lower()
if user_choice == "double":
    if bank - betting_money < 0:
        print(" you don't have enoung money.")
        user_choice = input("Hit or Stand?").lower()
    else:
        bank = bank - betting_money
        betting_money = betting_money * 2
        user_choice = input("Hit or Stand").lower()

if user_choice == "hit":
    is_choice_time = True
    while is_choice_time:
        user_cards.append(random.choice(cards))
        if sum(user_cards) > 21:
            print(f" your point is {sum(user_cards)}!!!  bust!")
            if bank == 0:
              bank = -1
            return
        else:
            print(f"you card set is {user_cards}")
            user_choice = input("More hit or stand").lower()
            if user_choice == "stand":
                is_choice_time = False

if user_choice == "stand":
    while sum(dealer_cards) < 17:
        dealer_cards.append(random.choice(cards))
        print("dealer drow one more")
    if sum(dealer_cards) > 21:
        print(f"dealer's point is {sum(dealer_cards)}. bust !!")
        bank = bank + betting_money * 2
        betting_money = 0
    else:
        if sum(user_cards) > sum(dealer_cards):
            print(
                f"your point: {user_cards} dealer's point: {dealer_cards}")
            print("you win this round")
            bank += betting_money * 2
            betting_money = 0
        elif sum(user_cards) == sum(dealer_cards):
            print(
                f"your point: {user_cards} dealer's point: {dealer_cards}")
            print("you draw this round")
            bank += betting_money
            betting_money = 0
        else:
            print(
                f"your point: {user_cards} dealer's point: {dealer_cards}")
            print("dealer win this round")
            betting_money = 0
            if bank == 0:
              bank = -1

"""
유저의 선택과 라운드의 끝을 구현한코드이다.
bank에서 배팅한만큼 돈을 빼고,
라운드에서 비기면 돌려주고, 이기면 두배로 돌려주고, 지면 안돌려주는 식으로 구현하니까

라운드가 끝났을때는 bank가 0이면 게임이 끝나야하고,
라운드가 막 시작했을때는 뱅크가 0이어도 게임은진행되어야해서
bank가 0 미만인경우에 게임이 끝나게 설정했고, 라운드가 끝났을 때 bank가 0이면 값을 -1로 바꿔
강제로 게임오버시키는식의억지구현을 했다.

def gamefunction():  
global bank  
global betting\_money  
while bank >= 0 and bank < 10000:  
is\_betting\_error = True  
print(f"your bank : ${bank}")  
while is\_betting\_error == True:  
betting\_money = int(input("how much money do you want to bet?"))  
check\_bet = bet(betting\_money)  
if check\_bet != "again":  
is\_betting\_error = False  
start()  
if bank > 10000:  
print(f" congratulations!! you win! your score is {bank}")  
if bank < 0:  
print("you lose")

while replay:  
gamefunction()  
check\_replay = input("One more game? type 'y' for restart or anythnig to quit")  
if check\_replay !="y" :  
is\_replay = False  
bank = 1000  
print(art.logo)

"""

나는 돈이 0원이 되면 게임에서 지고, 10000원을 따면 끝나게 설정했다.
내코드를 보고 해보고싶은분은 https://replit.com/@boteplay3/blackjack-start#main.py 에서 fork 해가시라..

코딩하면서 느낀점

  1. 전역변수 쓰기 싫다.

  2. 이함수저함수 돌려막기식으로 진행되게 구현한것이 불편하다.

  3. 오류를 제어하는 코드를 만들기가 까다롭다. user가 잘못입력했을떄 while "제대로입력이 들어올때까지"등으로땜방했는데 다른방법은없는지 고민하는중이다.

    1. 지금보니까 첫 두장을 받았을때 승부가 결정되는 블랙잭 룰은 구현을 안했다. 하하..

    이제 강사님의 코드다
    강의는 유료지만 코드는 https://replit.com/@appbrewery/blackjack-final
    여기에서 그냥 퍼가요(fork) 할 수있길래 퍼왔다.
    문제가 될시 자삭하겠다.나는 플래시게임을 해보고 혼자 그대로 구현하고 double, bank 등을 구현했는데
    강사님은 배팅이나 게임 완려 그런거없이 간단하게 1라운드승부를 구현해 놓으셨다.

  4. 강사님의 강의는 유데미에서 볼 수있다.
    https://www.udemy.com/course/100-days-of-code/

나는 hint를 안보고했는데
각 hint를 보고 따라가면서 할 수있게 되어있다.

############### Blackjack Project #####################

#Difficulty Normal 😎: Use all Hints below to complete the project.  
#Difficulty Hard 🤔: Use only Hints 1, 2, 3 to complete the project.  
#Difficulty Extra Hard 😭: Only use Hints 1 & 2 to complete the project.  
#Difficulty Expert 🤯: Only use Hint 1 to complete the project.

############### Our Blackjack House Rules #####################

## The deck is unlimited in size.

## There are no jokers.

## The Jack/Queen/King all count as 10.

## The the Ace can count as 11 or 1.

## Use the following list as the deck of cards:

## cards = \[11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10\]

## The cards in the list have equal probability of being drawn.

## Cards are not removed from the deck as they are drawn.

##################### Hints #####################

#Hint 1: Go to this website and try out the Blackjack game:

# [https://games.washingtonpost.com/games/blackjack/](https://games.washingtonpost.com/games/blackjack/)

#Then try out the completed Blackjack project here:

# [http://blackjack-final.appbrewery.repl.run](http://blackjack-final.appbrewery.repl.run)

#Hint 2: Read this breakdown of program requirements:

# [http://listmoz.com/view/6h34DJpvJBFVRlZfJvxF](http://listmoz.com/view/6h34DJpvJBFVRlZfJvxF)

#Then try to create your own flowchart for the program.

#Hint 3: Download and read this flow chart I've created:

# [https://drive.google.com/uc?export=download&id=1rDkiHCrhaf9eX7u7yjM1qwSuyEk-rPnt](https://drive.google.com/uc?export=download&id=1rDkiHCrhaf9eX7u7yjM1qwSuyEk-rPnt)

#Hint 4: Create a deal\_card() function that uses the List below to _return_ a random card.  
#11 is the Ace.  
import random  
from replit import clear  
from art import logo

def deal\_card():  
"""Returns a random card from the deck."""  
cards = \[11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10\]  
card = random.choice(cards)  
return card

#Hint 6: Create a function called calculate\_score() that takes a List of cards as input  
#and returns the score.  
#Look up the sum() function to help you do this.  
def calculate\_score(cards):  
"""Take a list of cards and return the score calculated from the cards"""  

dealcard를 함수로 구현한게 인상깊었다.
나는 시작할때 두장씩 받는코드를 구현하고, 라운드진행 선택 함수에서 다시 받는코드를 구성했는데

dealcard 기능을 따로 빼서 함수로 놓으면 귀찮게 여러번 type 할 필요가 없겠구나 싶었다.

#Hint 7: Inside calculate\_score() check for a blackjack (a hand with only 2 cards: ace + 10) and return 0 instead of the actual score. 0 will represent a blackjack in our game.  
if sum(cards) == 21 and len(cards) == 2:  
return 0  
#Hint 8: Inside calculate\_score() check for an 11 (ace). If the score is already over 21, remove the 11 and replace it with a 1. You might need to look up append() and remove().  
if 11 in cards and sum(cards) > 21:  
cards.remove(11)  
cards.append(1)  
return sum(cards)  

black jack 룰과 11두장을 뽑는것을 방지하는 코드이다.
11 2장 룰은몰라서 구현을 안했었다 .

#Hint 13: Create a function called compare() and pass in the user\_score and computer\_score. If the computer and user both have the same score, then it's a draw. If the computer has a blackjack (0), then the user loses. If the user has a blackjack (0), then the user wins. If the user\_score is over 21, then the user loses. If the computer\_score is over 21, then the computer loses. If none of the above, then the player with the highest score wins.  
def compare(user\_score, computer\_score):  
#Bug fix. If you and the computer are both over, you lose.  
if user\_score > 21 and computer\_score > 21:  
return "You went over. You lose 😤"
if user\_score == computer\_score:  
return "Draw 🙃"  
elif computer\_score == 0:  
return "Lose, opponent has Blackjack 😱"  
elif user\_score == 0:  
return "Win with a Blackjack 😎"  
elif user\_score > 21:  
return "You went over. You lose 😭"  
elif computer\_score > 21:  
return "Opponent went over. You win 😁"  
elif user\_score > computer\_score:  
return "You win 😃"  
else:  
return "You lose 😤"  

승부를 정하는 구간이다
나는 각 구간별로 bust를 확인해서 바로 게임이종료되게끔 코드를 구성했는데
이분은 점수비교 마지막에 체크하도록 compare함수를 따로 구현해서 아래 메인함수의마지막에 넣어놨다.

def play\_game():

print(logo)

#Hint 5: Deal the user and computer 2 cards each using deal\_card()  
user\_cards = \[\]  
computer\_cards = \[\]  
is\_game\_over = False

for \_ in range(2):  
user\_cards.append(deal\_card())  
computer\_cards.append(deal\_card())

#Hint 11: The score will need to be rechecked with every new card drawn and the checks in Hint 9 need to be repeated until the game ends.

while not is\_game\_over:  
#Hint 9: Call calculate\_score(). If the computer or the user has a blackjack (0) or if the user's score is over 21, then the game ends.  
user\_score = calculate\_score(user\_cards)  
computer\_score = calculate\_score(computer\_cards)  
print(f" Your cards: {user\_cards}, current score: {user\_score}")  
print(f" Computer's first card: {computer\_cards\[0\]}")
if user_score == 0 or computer_score == 0 or user_score > 21:
  is_game_over = True
else:
  #Hint 10: If the game has not ended, ask the user if they want to draw another card. If yes, then use the deal_card() function to add another card to the user_cards List. If no, then the game has ended.
  user_should_deal = input("Type 'y' to get another card, type 'n' to pass: ")
  if user_should_deal == "y":
    user_cards.append(deal_card())
  else:
    is_game_over = True
#Hint 12: Once the user is done, it's time to let the computer play. The computer should keep drawing cards as long as it has a score less than 17.  
while computer\_score != 0 and computer\_score < 17:  
computer\_cards.append(deal\_card())  
computer\_score = calculate\_score(computer\_cards)

print(f" Your final hand: {user\_cards}, final score: {user\_score}")  
print(f" Computer's final hand: {computer\_cards}, final score: {computer\_score}")  
print(compare(user\_score, computer\_score))

#Hint 14: Ask the user if they want to restart the game. If they answer yes, clear the console and start a new game of blackjack and show the logo from art.py.  
while input("Do you want to play a game of Blackjack? Type 'y' or 'n': ") == "y":  
clear()  
play\_game()

전부 읽고나서 전역변수를 main함수안에 지역변수로 구현 한후
지역변수를 요하는 각각의 기능들을 함수화해서 구현하면 전역변수 사용과 함수돌려막기코드를 해결 할 수있겠다고 느꼈다.

그런데 유저오류는 이분도 나와 같은것을 사용하셨다..

이제 카드게임두개정도를 더 구현한 후 파이참을 설치하는 강의를 볼텐데

그 두개를 구현할때는 여기서 배운점을 생각하며 코딩을 해봐야겠다.