프로젝트: 숫자 야구

타키탸키·2021년 1월 29일
0

Python 입문하기

목록 보기
14/14

Python 응용 프로젝트 두번째 시간입니다! 이번 시간에는 '숫자 야구' 게임을 함께 만들어 봅시다.

⚾ 프로젝트 개요

먼저, 게임의 규칙부터 설정해 볼까요?

숫자 야구 게임 규칙

  • 컴퓨터가 랜덤으로 0과 9 사이의 서로 다른 숫자 3개 추출
  • 사용자는 컴퓨터가 뽑은 숫자의 값과 위치를 맞춤
  • 아래의 규칙에 따라 컴퓨터는 사용자가 입력한 3개의 숫자에 대해 스트라이크(S)와 볼(B)의 개수를 알려줌
    => 숫자의 값과 위치가 모두 일치: S
    => 숫자의 값은 일치하지만 위치가 틀림: B
    => 예시: 컴퓨터(2,3,4) & 사용자(1,2,4) > 1B(값만 일치) / 1S(값/위치)
  • 기회는 무제한. 단, 시도한 횟수는 카운트되어 기록
  • 3S(숫자 3개의 값과 위치가 모두 일치함)가 나오면 게임 종료

다음으로 원활한 코드 작성을 위해 진행 방식을 세워봅시다.

  1. "0과 9 사이의 서로 다른 숫자 3개를 랜덤한 순서로 뽑았습니다." 출력
  2. "숫자 3개를 하나씩 차례대로 입력하세요." 출력
  3. "1번째 숫자를 입력하세요: " 출력 => 사용자로부터 입력 받기
  4. "2번째 숫자를 입력하세요: " / "3번째 숫자를 입력하세요: " 입출력 반복
  5. 중복되는 숫자 or 범위에서 벗어나는 숫자를 입력 => 다시 입력 받기
  6. 올바르게 숫자 3개 입력 => 규칙에 따라 "별표S 별표B" 출력
  7. 3S 아닌 경우, 2번부터 다시 진행
  8. 3S 달성 => "축하합니다. *번 만에 숫자 3개의 값과 위치를 모두 맞추셨습니다." 출력 후, 게임 종료

⚾ 숫자 3개 뽑기

진행 방식에 따라 랜덤 숫자 3개를 뽑는 함수 generate_numbers를 작성해봅시다. 이 함수는 0과 9 사이의 수 세 개를 랜덤으로 뽑고 그 수들이 담긴 리스트를 반환합니다.

우선 숫자들을 담을 리스트를 선언해야겠죠?

nums = []

그 다음 3개의 숫자를 추가하기 위해 while문을 사용해봅시다. 이때, while문의 조건 부분에는 리스트의 길이가 3을 초과하면 종료해야 된다는 조건이 들어가야 합니다.

while len(nums) < 3:

그리고 while문의 수행 부분에는 계속해서 리스트에 새로운 숫자들이 추가되어야 겠죠? 추가되는 수는 랜덤이지만 중복값은 허용되지 않습니다. 이를 구현하기 위해서는 randint, append, if문이 필요합니다. randint를 사용하기 위해 함수 정의 전에 import random을 꼭 작성해주세요.

while len(nums) < 3:
    random_num = random.randint(0, 9)
    if random_num not in nums:
        nums.append(random_num)

진행 방식에 따라 nums를 리턴하기 전 랜덤으로 숫자를 뽑았다는 문구부터 출력합니다. 그 다음에 nums를 리턴하면 됩니다.

print("0과 9 사이의 서로 다른 숫자 3개를 랜덤한 순서로 뽑았습니다.\n")
return nums

완성된 코드를 함께 볼까요?

import random

def generate_numbers():
    nums = []
    
    while len(nums) < 3:
        random_num = random.randint(0, 9)
        if random_num not in nums:
            nums.append(random_num)
            
    print("0과 9 사이의 서로 다른 숫자 3개를 랜덤한 순서로 뽑았습니다.\n")
    return nums         

⚾ 숫자 예측하기

이번에는 사용자로부터 숫자 3개를 입력받는 함수 take_guess를 작성해봅시다. 이 함수는 숫자 3개를 반복적으로 입력받고 그 숫자들을 리스트에 정리해서 반환합니다.

우선, 사용자가 입력하는 숫자들을 담을 리스트를 만들어야 합니다.

guess_list = []

다음으로 사용자가 3개의 숫자를 반복적으로 넣기 위해 while문을 작성합니다. generate_numbers 함수를 작성했을 때와 마찬가지로 조건 부분에는 리스트의 길이가 3을 초과하지 않는다는 조건을 적어야 합니다.

while len(guess_list) < 3:

while문의 수행 부분에 들어가야 하는 항목은 다음과 같습니다.

  1. 사용자로부터 숫자 입력 받기
  2. 숫자가 범위에서 벗어나면 벗어났다는 문구 출력하기
  3. 숫자가 중복되었다면 중복되었다는 문구 출력하기
  4. 2번과 3번 모두 해당되지 않으면 숫자를 리스트에 추가하기

먼저, 사용자로부터 숫자를 입력 받는 코드를 작성합니다.

guess_list = int(input(f"{len(guess_list) + 1}번째 숫자를 입력하세요: "))

나머지 세 단계는 if문으로 표현할 수 있습니다.

if guess < 0 or  guess > 9:
    print("범위를 벗어나는 숫자입니다. 다시 입력하세요.")
elif guess in new_guess:
    print("중복된 숫자입니다. 다시 입력하세요.")
else:
    guess_list.append(guess)

이제 리스트를 반환하기만 하면 됩니다.

그럼 완성된 코드를 볼까요?

def take_guess():
    print("숫자 3개를 하나씩 차례대로 입력하세요.")
    
    guess_list = []
    while len(guess_list) < 3:
        guess = int(input(f"{len(guess_list) + 1}번째 숫자를 입력하세요: "))
        
        if guess < 0 or  guess > 9:
            print("범위를 벗어나는 숫자입니다. 다시 입력하세요.")
        elif guess in guess_list:
            print("중복된 숫자입니다. 다시 입력하세요.")
        else:
            guess_list.append(guess)
            
    return guess_list   

⚾ 점수 계산

이제 스트라이크 수와 볼 수를 알려주는 get_score 함수를 작성할 차례입니다.

이 함수는 두 개의 리스트 파라미터를 받는데요. 리스트 하나는 사용자로부터 받은 숫자가 담긴 guess이고 또 다른 리스트는 컴퓨터가 뽑은 숫자들이 담긴 answer입니다.

함수 get_score는 이 두 리스트를 비교해서 스트라이크 수와 볼 수를 계산한 후 두 결괏값을 리턴합니다.

def get_score(guess, answer):
    strike_count = 0
    ball_count = 0

우선, get_score 함수를 정의하는 코드를 작성합니다. 앞으로 계산할 스트라이크 수와 볼 수를 저장할 변수도 각각 선언해줍시다.

다음으로, 스트라이크 수를 판단하는 코드부터 작성해보도록 하죠. 위치와 값이 모두 일치할 때 스트라이크 수가 증가합니다. 이 과정을 코드를 통해 구현해봅시다.

for i in range(3):
    if guess_list[i] == answer_list[i]:
        strike_count += 1

여기서 for문을 사용하는 이유는 리스트의 인덱스를 차례로 돌면서 스트라이크 기준에 맞는 수가 있는지 판단하기 위해서입니다.

스트라이크의 기준은 값과 위치가 모두 일치하는 경우라고 했죠? 따라서 인덱스를 지정하고 그 값이 다른 리스트 속 동일한 인덱스의 값과 일치하는 경우카운트가 증가하도록 설정하면 됩니다.

이번에는 볼 수를 판단하는 코드를 작성해봅시다.

for i in range(3):
    if guess[i] in answer and guess[i] != answer[i]:
        ball_count += 1

볼의 판단 기준은 값의 일치 여부였습니다. 따라서 인덱스를 일치시킬 필요 없이 특정 값이 상대 리스트에 있는지 확인하면 됩니다.

잊지 말아야 할 것은 위 조건과 다르게 위치가 아닌 값만 일치해야 하므로 동일한 인덱스의 값과 일치하지 않아야 한다는 조건을 추가해줘야 한다는 점입니다.

이제 두 조건문을 하나로 합쳐 봅시다.

for i in range(3):
    if guess[i] == answer[i]:
        strike_count += 1
    elif guess[i] in answer and guess[i] != answer[i]:
        ball_count += 1

이제 두 값을 반환할 차례입니다. 여기서 잠깐! 우리는 이제까지 하나의 값만을 반환했었는데요. 여러가지 값을 동시에 반환하려면 어떻게 해야할까요? 다음 사례를 봅시다.

def add_and_subtract(x):
    add = x + 1
    subtract = x - 1
    return add, subtract

이처럼 변수 두 개가 선언되면 두 개의 결괏값을 반환할 수 있습니다.

또 한 가지 알아야 할 개념은 여러 개의 리턴 값을 하나의 변수에 저장하는 방법입니다. 아래와 같이 코드를 작성하면 add_and_subtract(3)의 첫번째 반환값이 변수 a에 저장되고 두번째 반환값이 변수 s에 저장됩니다.

a, s = add_and_subtract(3)
print(a)
print(s)
4
2

이런 식으로 get_score 함수도 스트라이크 수와 볼 수, 두 값 모두를 리턴하도록 해야합니다. 따라서 리턴값을 두 개로 설정하고 get_score 함수를 호출하는 방식도 위 코드와 유사하게 작성해야 하죠.

return strike_count, ball_count
# 테스트
s_1, b_1 = get_score([3, 9, 6], [3, 6, 9])
print(s_1, b_1)
1 2

자, 이제 완성된 함수를 봅시다.

def get_score(guess, answer):
    strike_count = 0
    ball_count = 0

    # 코드를 작성하세요.
    for i in range(3):
        if guess[i] == answer[i]:
            strike_count += 1

    for i in range(3):
        if guess[i] in answer and guess[i] != answer[i]:
            ball_count += 1

    return strike_count, ball_count

⚾ 숫자 야구 최종

드디어 마지막 단계입니다. 마지막 단계에서는 이제까지 작성했던 코드를 하나로 모으고 필요한 코드 몇 줄만 추가하면 됩니다.

필요한 코드를 작성하기 전 을 먼저 구상해봅시다.

  1. 필요한 변수상수 정의
  2. 반복적으로 사용자로부터 숫자 입력 받기
    2-1. 3개의 스트라이크가 나오면 게임 종료
  3. 시도 횟수와 함께 축하 문구 출력

❗ 변수, 상수 정의

먼저, 필요한 변수와 상수를 생각해봅시다. 상수는 변하지 않는 수를 뜻하죠? 게임 내에서 변하지 않는 수는 어떤 것일까요? 네, 맞습니다. 게임이 진행되는 동안 정답은 변하지 않아야 겠죠?

그런데 이 정답에는 어떤 값이 들어가야 할까요? 우리는 앞서 generate_numbers 함수를 호출하여 임의의 수를 뽑아냈습니다. 바로 그 수들이 정답입니다.

그렇다면 변수에는 어떤 것이 있을까요? 이제까지 등장하지 않았던 개념인 시도 횟수가 바로 변수입니다.

이제 이 둘을 각각 변수와 상수로 표현해보도록 하죠.

SOLUTION = generate_numbers()
tries = 0

❗ 유저 입력 받기

다음으로 생각해봐야 할 것은 게임을 진행하며 반복적으로 해야할 일들입니다.

  1. 사용자로부터 숫자 3개 입력 받기
  2. 스트라이크 수와 볼 수 세고 출력하기
  3. 시도 횟수를 1씩 늘리기
  4. 3개의 스트라이크가 나오면 반복문 종료

하나씩 코드로 구현해봅시다.

사용자로부터 3개의 숫자를 입력 받기 위해서는 앞서 만들어둔 take_guess 함수를 사용하면 됩니다.

user_guess = take_guess()

다음으로 get_score 함수를 통해 스트라이크 수와 볼 수를 셀 수 있습니다. get_score에는 take_guess로부터 반환 받은 리스트가 필요합니다. 따라서, take_guess의 결과를 user_guess라는 새 변수에 저장하고 get_score 파라미터로 넣어주면 됩니다.

그런 다음, get_socre의 결과를 스트라이크 수를 의미하는 변수 s와 볼 수를 의미하는 변수 b에 각각 저장한 후에 출력해줍시다. 그 후, 시도 횟수가 늘면 1씩 증가한다는 코드를 작성해야 합니다.

s, b = get_score(user_guess, SOLUTION)
print(s, b)
tries += 1

마지막으로 '3개의 스트라이크가 나올 시 종료'라는 조건을 만들어주어야 합니다. 이 조건이 충족되면 반복문이 종료됩니다.

if s == "3S"
    break

이제 이 코드들을 하나로 모아 while문을 완성해봅시다. while문의 조건 부분에는 True만을 써줍니다. 이렇게 하는 이유는 특정 조건이 아니면 계속해서 과정을 반복하도록 하기 위함입니다. 따라서, 종료 조건을 따로 지정해 주어야 합니다.

이때, 이렇게 생각하시는 분들도 있을 것 같습니다.

"조건 부분을 그냥 's != 3'으로 하면 되지 않나?"

하지만 조건 부분을 's != 3'으로 두게 되면 s를 미리 정의해야 합니다. 코드는 짧고 간결할수록 좋다고 했었죠? 그렇기 때문에 일단 True로만 두고 따로 조건문을 작성해준 것입니다.

❗ 축하 문구 출력

마지막 단계는 축하 문구를 출력하는 것입니다. 시도 횟수를 알려주기 위해 tries 변수를 활용하는 걸 잊지 마세요!

print(f"축하합니다. {tries}번 만에 세 숫자의 값과 위치를 모두 맞추셨습니다.")

⚾ 숫자 야구 완성본

이렇게 해서 완성된 코드를 보여 드리겠습니다.

import random

def generate_numbers():
    # 지난 과제의 코드를 붙여 넣으세요.
    nums = []

    while len(nums) < 3:
        random_num = random.randint(0, 9)
        if random_num not in nums:
            nums.append(random_num)

    print("0과 9 사이의 서로 다른 숫자 3개를 랜덤한 순서로 뽑았습니다.\n")
    return nums

def take_guess():
    # 지난 과제의 코드를 붙여 넣으세요.
    print("숫자 3개를 하나씩 차례대로 입력하세요.")

    guess_list = []
    while len(guess_list) < 3:
        guess = int(input(f"{len(guess_list) + 1}번째 숫자를 입력하세요: "))

        if guess < 0 or guess > 9:
            print("범위를 벗어나는 숫자입니다. 다시 입력하세요.")
        elif guess in guess_list:
            print("중복된 숫자입니다. 다시 입력하세요.")
        else:
            guess_list.append(guess)

    return guess_list

def get_score(guess, answer):
    strike_count = 0
    ball_count = 0

    # 지난 과제의 코드를 붙여 넣으세요.
    for i in range(3):
        if guess[i] == answer[i]:
            strike_count += 1

    for i in range(3):
        if guess[i] in answer and guess[i] != answer[i]:
            ball_count += 1

    return f"{strike_count}S", f"{ball_count}B"

ANSWER = generate_numbers()
tries = 0

s = 0
b = 0

while True:
    user_guess = take_guess()
    s, b = get_score(user_guess, ANSWER)

    print(s, b)
    tries += 1

    if s == "3S":
        break

print(f"축하합니다. {tries}번 만에 숫자 3개의 값과 위치를 모두 맞추셨습니다.")

모든 함수가 오류 없이 동작한다면 숫자 야구 게임은 성공적으로 완성된 것입니다.


이번 시간에는 저번 시간에 이어 Python을 활용한 프로젝트를 진행해봤습니다. 처음 프로젝트를 접할 때는 어떤 것부터 해야할 지 막막했을 것입니다. 하지만 어떤 단계가 필요한지, 어떤 함수가 필요한지를 먼저 생각하고 각각의 과정을 하나씩 수행해 나가다 보면 어느새 원하는 결과를 만들어내고 있는 자신을 발견할 수 있을 것입니다.

이로써 여러분들은 Python의 기본을 완벽히 익혔습니다. 이제 여러분들만의 방법으로 Python을 응용해보시길 바랍니다. 수고 많으셨습니다! 🥰🥰🥰

* 이 자료는 CODEIT의 '프로그래밍 기초 in Python'을 기반으로 작성되었습니다.
profile
There's Only One Thing To Do: Learn All We Can

0개의 댓글