본문 바로가기

Code-note

[프로젝트] BlackJack 구현 - python

 

BLACK JACK
https://www.7luck.com/JSPVIEW/default?URL_JSP=--guid--GUID_04_01_01&sel_lang_typ=KR

 

[룰 설명]

[BlackJack 기본 규칙]

목적: 블랙잭의 목표는 딜러(dealer)를 상대로 21을 넘지 않으면서, 21에 가까운 숫자를 만드는 것입니다.

카드의 값:
- 숫자 카드(2-10): 각 카드에 적힌 숫자대로 점수를 가집니다.
- 그림 카드(J, Q, K): 각 카드의 값은 10점입니다.
- 에이스(A): 11점으로 계산합니다.

게임 진행:
- 각 플레이어는 두 장의 카드를 받고, 딜러도 두 장의 카드를 받습니다. 딜러의 한 장은 보통 뒤집어서 숨깁니다.
- 플레이어는 자신의 카드 합계가 21에 가까워지도록 추가 카드를 요청(hit)하거나 현재 점수로 만족하여 더 이상 카드를 받지 않겠다고 선언할 수 있습니다(stay 또는 stand).
- 딜러는 자신의 카드 합계가 17 이상이 될 때까지 반드시 카드를 추가로 받아야 합니다.
- 플레이어의 카드 합계가 21을 초과하면 패배(bust)합니다.
- 플레이어가 멈춘 후 딜러의 차례가 되며, 딜러의 카드 합계가 21을 초과하면 딜러가 패배합니다.
- 딜러의 카드 합계가 21을 넘지 않으면, 딜러와 플레이어의 카드 합계를 비교하여 높은 쪽이 승리합니다.

플레이어 승리
딜러 승리
유효성 검사

[파이썬 코드]

import random  # 랜덤 모듈을 가져옵니다. 덱을 섞을 때 사용합니다.

# 문제 1: 카드 덱 생성하기
# 빈칸을 채워 카드 덱을 생성하는 create_deck 함수를 완성하세요.
def create_deck():
    """
    이 함수는 52장의 카드로 구성된 덱을 생성하고 이를 무작위로 섞어서 반환합니다.
    카드 덱은 네 가지 무늬(하트, 다이아몬드, 클로버, 스페이드)와
    각각의 무늬마다 13개의 랭크(2-10, 잭, 퀸, 킹, 에이스)로 이루어져 있습니다.
    
    Returns:
        list: 무작위로 섞인 카드 덱
    """
    deck = []  # 빈 리스트로 덱을 초기화합니다.
    suits = ['하트', '다이아몬드', '클로버', '스페이드']  # 카드의 네 가지 무늬를 리스트로 정의합니다.
    ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '잭', '퀸', '킹', '에이스']  # 카드의 13가지 랭크를 리스트로 정의합니다.
    
    # 모든 무늬와 랭크를 조합하여 덱을 만듭니다.
    for suit in suits:  # suits 리스트를 순회합니다.
        for rank in ranks:  # ranks 리스트를 순회합니다.
            deck.append((rank, suit))  # 각 카드(rank와 suit의 조합)를 덱에 추가합니다.
    
    random.shuffle(deck)  # 덱을 무작위로 섞습니다.
    return deck  # 섞인 덱을 반환합니다.

# 힌트:
# - suits 리스트의 각 항목을 suit 변수에 담아 순회합니다.
# - ranks 리스트의 각 항목을 rank 변수에 담아 순회합니다.
# - deck 리스트를 shuffle 함수로 섞습니다.
# - 최종적으로 생성된 deck 리스트를 반환합니다.

# 문제 2: 카드 점수 계산하기
# 빈칸을 채워 손에 있는 카드의 점수를 계산하는 calculate_score 함수를 완성하세요.
def calculate_score(hand):
    """
    이 함수는 주어진 카드 리스트(hand)의 총 점수를 계산합니다.
    점수 계산 규칙:
      - 숫자 카드는 해당 숫자만큼 점수를 더합니다.
      - '잭', '퀸', '킹'은 10점으로 계산합니다.
      - '에이스'는 11점으로 계산하되, 점수가 21을 초과할 경우 1점으로 계산합니다.
    
    Args:
        hand (list): 카드의 리스트, 각 카드는 (랭크, 무늬) 튜플로 표현됩니다.
    
    Returns:
        int: 손에 있는 카드의 총 점수
    """
    score = 0  # 점수를 0으로 초기화합니다.
    ace_count = 0  # 에이스 카드의 개수를 세기 위한 변수를 0으로 초기화합니다.
    
    # 각 카드의 점수를 계산합니다.
    for card, suit in hand:  # hand 리스트를 순회합니다.
        if card in ['잭', '퀸', '킹']:  # '잭', '퀸', '킹'은 10점으로 계산합니다.
            score += 10  # score에 10을 더합니다.
        elif card == '에이스':  # '에이스'는 11점으로 계산합니다.
            ace_count += 1  # 에이스 개수를 하나 증가시킵니다.
            score += 11  # score에 11을 더합니다.
        else:  # 숫자 카드는 해당 숫자만큼 점수를 더합니다.
            score += int(card)  # card를 정수로 변환하여 score에 더합니다.
    
    # 점수가 21점을 초과하고 에이스가 있을 경우, 에이스를 1점으로 계산합니다.
    while score > 21 and ace_count:  # score가 21점을 초과하고 ace_count가 0보다 클 때
        score -= 10  # score에서 10을 뺍니다.
        ace_count -= 1  # ace_count를 하나 감소시킵니다.
    
    return score  # 최종 점수를 반환합니다.

# 힌트:
# - hand 리스트의 각 항목을 card와 suit 변수에 담아 순회합니다.
# - '에이스'는 초기 11점으로 계산하고, 필요시 1점으로 조정합니다.
# - 최종적으로 계산된 score를 반환합니다.

# 문제 3: 카드 출력하기
# 빈칸을 채워 손에 있는 카드를 출력하는 show_cards 함수를 완성하세요.
def show_cards(player, hand):
    """
    이 함수는 주어진 플레이어의 이름과 해당 플레이어의 손에 있는 카드를 출력합니다.
    
    Args:
        player (str): 플레이어의 이름
        hand (list): 플레이어의 손에 있는 카드 리스트, 각 카드는 (랭크, 무늬) 튜플로 표현됩니다.
    """
    print(f"{player}의 카드: ", end="")  # 플레이어의 이름을 출력합니다.
    for card, suit in hand:  # hand 리스트를 순회합니다.
        print(f"{card} {suit}", end=", ")  # 각 카드의 랭크와 무늬를 출력합니다.
    print()  # 줄 바꿈을 위해 빈 print문을 추가합니다.

# 힌트:
# - player를 출력합니다.
# - hand 리스트를 순회하며 각 카드의 랭크와 무늬를 출력합니다.

# 유효한 입력만 받도록 하는 함수
def get_valid_input(prompt, valid_options):
    """
    이 함수는 사용자가 유효한 옵션을 입력할 때까지 반복하여 입력을 받습니다.
    
    Args:
        prompt (str): 사용자에게 표시할 입력 메시지
        valid_options (list): 유효한 입력 옵션 리스트
    
    Returns:
        str: 유효한 입력 값
    """
    while True:
        choice = input(prompt).lower()
        if choice in valid_options:
            return choice
        print(f"유효하지 않은 입력값입니다. {valid_options}중에서 선택해주세요.")

# 문제 4: 블랙잭 게임 진행하기
# 빈칸을 채워 블랙잭 게임을 진행하는 play_blackjack 함수를 완성하세요.
def play_blackjack():
    """
    이 함수는 블랙잭 게임의 전체 진행을 관리합니다.
    게임 시작 메시지를 출력하고, 덱을 생성하며, 초기 카드를 분배합니다.
    플레이어와 딜러의 행동을 처리하고, 최종 결과를 출력합니다.
    """
    print("블랙잭 게임에 오신 것을 환영합니다!")  # 게임 시작 메시지를 출력합니다.
    deck = create_deck()  # 덱을 생성합니다.

    # 초기 카드 분배
    player_hand = [deck.pop(), deck.pop()]  # 플레이어에게 두 장의 카드를 분배합니다.
    dealer_hand = [deck.pop(), deck.pop()]  # 딜러에게 두 장의 카드를 분배합니다.

    show_cards("플레이어",player_hand )  # 플레이어의 카드를 출력합니다.
    show_cards("딜러", [dealer_hand[0], ("?", "?")])  # 딜러의 첫 번째 카드만 공개하고 두 번째 카드는 숨깁니다.

    # 플레이어의 선택
    while True:
        player_score = calculate_score(player_hand)  # 플레이어의 점수를 계산합니다.
        print(f"플레이어의 점수: {player_score}")  # 플레이어의 점수를 출력합니다.
        
        if player_score > 21:  # 플레이어가 21점을 초과하면 버스트입니다.
            print("플레이어가 버스트 했습니다! 딜러 승리!")
            return

        choice = get_valid_input("카드를 더 받으시겠습니까? (y/n): ", "[y,n]")  # 플레이어에게 카드를 더 받을지 물어봅니다.
        if choice.lower() == 'y':  # 'y'를 선택하면 카드를 한 장 더 받습니다.
            player_hand.append(deck.pop())
            show_cards("플레이어", player_hand)  # 플레이어의 새로운 카드를 출력합니다.
        else:  # 'n'을 선택하면 반복문을 종료합니다.
            break

    # 딜러의 카드 공개 및 추가 카드 받기
    show_cards("딜러", dealer_hand)  # 딜러의 모든 카드를 공개합니다.
    while calculate_score(dealer_hand) < 17:  # 딜러의 점수가 17점 미만이면 카드를 더 받습니다.
        dealer_hand.append(deck.pop())
        show_cards("딜러", dealer_hand)  # 딜러의 새로운 카드를 출력합니다.

    dealer_score = calculate_score(dealer_hand)  # 딜러의 최종 점수를 계산합니다.
    print(f"딜러의 점수: {dealer_score}")  # 딜러의 점수를 출력합니다.

    # 결과 판단
    if dealer_score > 21:
        print("딜러가 버스트 했습니다! 플레이어 승리!")  # 딜러가 버스트 했으면 플레이어가 승리합니다.
    elif dealer_score > player_score:
        print("딜러 승리!")  # 딜러의 점수가 더 높으면 딜러가 승리합니다.
    elif dealer_score < player_score:
        print("플레이어 승리!")  # 플레이어의 점수가 더 높으면 플레이어가 승리합니다.
    else:
        print("무승부!")  # 점수가 같으면 무승부입니다.

# 힌트:
# - create_deck 함수를 호출하여 덱을 생성합니다.
# - 플레이어와 딜러에게 각각 두 장의 카드를 분배합니다.
# - 플레이어의 점수를 계산하고, 21점을 초과하면 버스트 처리합니다.
# - 딜러의 점수를 계산하고, 필요한 경우 추가 카드를 받습니다.
# - 최종 점수를 비교하여 승자를 결정합니다.

# 메인 함수: 게임을 시작하고, 사용자가 원하면 반복합니다.
if __name__ == "__main__":
    while True:
        play_blackjack()  # 블랙잭 게임을 시작합니다.
        replay = get_valid_input("다시 게임을 하시겠습니까? (y/n): ","[y,n]")  # 사용자가 게임을 다시 할지 물어봅니다.
        if replay.lower() != 'y':  # 'y'가 아니면 게임을 종료합니다.
            break

 

# 해당 코드는 오즈코딩스쿨의 프로젝트 과제의 일부 입니다.