본문 바로가기
DEV/파이썬 이론

파이썬 코딩 :: 파이썬 숫자 야구 게임 만들기

by 올커 2022. 9. 7.

파이썬 숫자 야구 게임(베이스 볼) 만들기


 

※ 숫자 야구란?

- 감춰진 숫자를 맞추는 게임으로 Strike, Ball과 같은 야구의 룰을 일부 가져와서 '숫자 야구'라는 이름이 붙어졌다.
- 같은 자리수에 숨겨진 숫자를 맞추면 Strike, 다른 자리수에 숨겨진 숫자를 맞추면 Ball로 점수가 매겨진다.

ex) 숨겨진 숫자 : 159
1회차 - 135 : 1S 1B (첫째자리 1 → 1S, 셋째자리 5 → 1B)
2회차 - 236 : Out(0S 0B)
3회차 - 139 : 2S (첫째자리 1, 둘째자리 3 → 2S)

 

1. 조건

- 프로그램 시작시 참여자에게 자릿수를 입력받는다. (최대 10자리)
- 입력받은 자리수로 랜덤한 수 생성 (숫자 중복 X)
- 사용자가 숫자를 입력했을 때 게임의 규칙에 맞게 Strike / Ball count 출력
- 사용자가 정답을 맞춘 경우 입력한 횟수/소요 시간/정답을 맞춘 날짜 및 시간을 출력
- 게임을 진행하던 도중 'exit'을 입력할 경우 프로그램 종료


2. 파이썬 코드 해석

(1) 모듈 import

# 숫자 야구 게임 만들기
from random import randint       # 랜덤 모듈 임포트
import time         		# 시간 모듈 임포트
from datetime import datetime        # 날짜 모듈 임포트


- 숫자 야구게임에서는 랜덤한 숫자 생성이 필요하므로 파이썬에서 제공하는 random 모듈 임포트
- 사용자가 정답을 맞춘 경우 소요시간, 정답을 맞춘 날짜를 출력하기 위한 time, datetime 모듈 임포트

(2) 함수① - 감춰진 임의의 숫자 생성

# 랜덤 수 생성 함수 (중복 X)
def gen_num(n):
    num_list = []
    while len(num_list)<n:
        num = randint(1, 9)
        if num not in num_list:
            num_list.append(num)       # join을 위해 num을 string화 해줌
        elif num in num_list:
            continue
        number = ''.join(map(str,num_list))
    return number


- 임의의 숫자를 생성하기 위해 파이썬의 random 모듈을 불러왔었다.
- 숫자 생성은 기능 단위로 구분하기 위해 함수로 지정했다.
- 숫자를 담아올 num_list[ ]를 정의하고, while문을 통해 랜덤 숫자 뽑기를 반복한다.
- while문 반복 조건len(num_list) < n이다.
num_list의 요소들의 숫자가 n(자릿수)이 될 때까지 반복하며 변수 n은 이후 코드에서 자릿수로 입력받을 예정이다.
- randint는 함수를 직접 임포트 했기 때문에 num = randint(1, 9)와 같이 그대로 사용했다.
- if문에서는 생성한 숫자 num이 num_list에 없으면 append를 사용해 리스트에 넣어주고,
이미 있다면 다시 while문을 진행한다.
- num_list의 숫자는 map 함수를 이용해 리스트 안의 각각의 수를 문자자료형으로 만든 후 join을 통해 문자열로 만든다.
이 문자열은 number라는 변수에 넣고 number를 결과값으로 반환한다.

(3) 함수② - 입력된 숫자 검사

# 입력된 숫자 검사
def test_num(check_num, ran_num):
    s = 0       # strike
    b = 0       # ball
    for i in range(n):
        for j in range(n):
            if (i == j)&(check_num[i] == ran_num[j]):
                s += 1
            elif check_num[i] == ran_num[j]:
                b += 1
    print(f"{s}S {b}B")
    return s, b


- 입력받은 숫자가 랜덤의 숫자와 동일한지 확인하는 기능도 기능 단위로 구분하기 위해 함수로 지정했다.
- Strike와 Ball을 카운트하기 위해 s = 0, b = 0으로 변수 지정한다.
- 이중 for문을 사용하여,
(1) strike의 경우 인덱스가 동일(i == j) 하면서 값이 동일(check_num[i] == ran_num[j])한지 검사하고
(2) ball의 경우 strike가 아니면서(elif), 값이 동일(check_num[i] == ran_num[j])한지 검사한다,
각각의 검사에 해당되는 경우에는 변수를 하나씩 카운트한다.(s += 1, b += 1)
- for문을 모두 돌면서 검사가 완료된 경우 f-string을 활용해 검사결과를 출력한다. → print(f"{s}S {b}B")
- 검사 결과 s와 b를 반환한다.

 

(4) 자리수 입력

# 자릿수 입력
while True:
    n = int(input(">>> 자릿수를 입력해주세요 : "))
    start_time = time.time()        # 시작 시간 저장
    if n < 10:
        break
    else:
        continue


- 초기에 유저로부터 자리수를 입력받는다. int는 str이기 때문에 int로 변환해준다.
- 소요시간을 계산하기 위해 start_time에 time모듈을 활용하여 시작시간을 저장한다.
- 초기 자리수는 10을 넘어가지 않아야 하기 때문에 while문 안에 if문을 통해 break, continue를 판별한다.

(5) 함수 호출, 예측 횟수 카운트

cnt = 0     # 예측 횟수
ran_num = gen_num(n)        # 함수 호출


- 예측 횟수를 카운트하기 위해 변수(cnt) 지정, 초기값은 0
- 임의의 수를 생성하는 함수(gen_num)를 호출하고, 반환받는 결과는 ran_num에 할당

(6) 예측 게임 시행

# 예측 시행
while True:
    check_num = input(">>> 예측값을 입력해주세요 : ")        # 예측값 받기
    if check_num == "exit":
        break
    elif len(check_num) != len(ran_num):
        print("자리수를 다시 입력바랍니다.")
        continue
    else:
        cnt += 1
        result = test_num(check_num, ran_num)
        if result != (n, 0):
            continue
        else:
            end_time = time.time()      # 완료 시간 저장
            print("---- 축하합니다! 정답입니다 ----")
            print(f"- 예측 횟수 : {cnt}회")
            print(f"- 소요 시간 : {end_time-start_time:.2f}초")
            now = datetime.now()
            string_datetime = datetime.strftime(now, "%y/%m/%d %H:%M:%S")
            print(f"- 정답 일시 : {string_datetime}")
            break


- 게임은 완료될 때 까지(일정한 횟수가 정해지지 않은) 시행되어야 하기 때문에 while문 사용
- check_num에 input으로 예측값을 입력받는다.(예측값은 input으로 받기 때문에 문자열 string)
- 입력값이 "exit"일 경우 while문을 빠져나가도록 if문 시작
- 예측값의 자릿수가 임의의 수의 자릿수와 다를 경우(elif) 다시 입력을 받음
- 정상적으로 입력되었을 경우, 예측횟수를 카운트(cnt += 1)하고,
test_num함수에 check_num, ran_num변수를 넣어 시행한 후 결과값을 result에 할당
- result는 결과값을 s(strike), b(ball)로 받으므로, s = n(자릿수 만큼), b = 0가 아닐경우, 루프를 반복하고,
맞을 경우(else) 완료시간 저장, 예측횟수, 소요시간, 정답일시를 각각 출력한다.


 

3. 파이썬 숫자 야구 게임 코드 및 출력 결과

# 숫자 야구 게임 만들기
from random import randint       # 랜덤 모듈 임포트
import time         # 시간 모듈 임포트
from datetime import datetime        # 날짜 모듈 임포트


# 랜덤 수 생성 함수 (중복 X)
def gen_num(n):
    num_list = []
    while len(num_list)<n:
        num = randint(1, 9)
        if num not in num_list:
            num_list.append(num)       # join을 위해 num을 string화 해줌
        elif num in num_list:
            continue
        number = ''.join(map(str,num_list))
    return number


# 입력된 숫자 검사
def test_num(check_num, ran_num):
    s = 0       # strike
    b = 0       # ball
    for i in range(n):
        for j in range(n):
            if (i == j)&(check_num[i] == ran_num[j]):
                s += 1
            elif check_num[i] == ran_num[j]:
                b += 1
    print(f"{s}S {b}B")
    return s, b


# 자릿수 입력
while True:
    n = int(input(">>> 자릿수를 입력해주세요 : "))
    start_time = time.time()        # 시작 시간 저장
    if n < 10:
        break
    else:
        continue


cnt = 0     # 예측 횟수
ran_num = gen_num(n)        # 함수 호출


# 예측 시행
while True:
    check_num = input(">>> 예측값을 입력해주세요 : ")        # 예측값 받기
    if check_num == "exit":
        break
    elif len(check_num) != len(ran_num):
        print("자리수를 다시 입력바랍니다.")
        continue
    else:
        cnt += 1
        result = test_num(check_num, ran_num)
        if result != (n, 0):
            continue
        else:
            end_time = time.time()      # 완료 시간 저장
            print("---- 축하합니다! 정답입니다 ----")
            print(f"- 예측 횟수 : {cnt}회")
            print(f"- 소요 시간 : {end_time-start_time:.2f}초")
            now = datetime.now()
            string_datetime = datetime.strftime(now, "%y/%m/%d %H:%M:%S")
            print(f"- 정답 일시 : {string_datetime}")
            break


### 출력 결과
'''
>>> 자릿수를 입력해주세요 : 3
>>> 예측값을 입력해주세요 : 123
0S 1B
>>> 예측값을 입력해주세요 : 456
2S 0B
>>> 예측값을 입력해주세요 : 789
0S 0B
>>> 예측값을 입력해주세요 : 125
0S 1B
>>> 예측값을 입력해주세요 : 126
1S 0B
>>> 예측값을 입력해주세요 : 256
2S 0B
>>> 예측값을 입력해주세요 : 356
3S 0B
---- 축하합니다! 정답입니다 ----
- 예측 횟수 : 7회
- 소요 시간 : 28.81초
- 정답 일시 : 22/09/07 17:50:42


>>> 자릿수를 입력해주세요 : 2
>>> 예측값을 입력해주세요 : 12
0S 0B
>>> 예측값을 입력해주세요 : 34
0S 0B
>>> 예측값을 입력해주세요 : 56
1S 0B
>>> 예측값을 입력해주세요 : 78
0S 0B
>>> 예측값을 입력해주세요 : 90
0S 1B
>>> 예측값을 입력해주세요 : 05
0S 1B
>>> 예측값을 입력해주세요 : 06
0S 0B
>>> 예측값을 입력해주세요 : 59
2S 0B
---- 축하합니다! 정답입니다 ----
- 예측 횟수 : 8회
- 소요 시간 : 18.91초
- 정답 일시 : 22/09/07 17:51:29
'''

 


※ 숫자야구 만들기 Tip

더보기

1. 사용자의 입력을 받아 n개의 중복되지 않는 랜덤한 숫자를 생성한다.
2. 프로그램이 시작 된 시간을 기록한다.
3. 사용자의 입력을 받고, 입력을 받을 때마다 try count를 1씩 더해준다.
4. 사용자 입력x와 랜덤하게 생성 된 y 두 숫자를 비교한다.
4-a. x의 첫 번째 숫자가 y에 포함되어 있는지 확인한다.
* 포함되어 있지 않다면 out count + 1
4-b. x의 첫 번째 숫자가 y에 포함되어 있다면 x의 첫 번째 숫자와 y의 첫 번쨰 숫자가 일치하는지 확인한다.
* 일치하는 경우 strike count + 1
* 일치하지 않는 경우 ball count + 1
4-c. 4-a ~ 4-b를 x의 모든 자릿수를 돌 때까지 반복한다.
5. 사용자가 exit을 입력하거나 정답을 맞출 때까지 3~4의 동작을 무한하게 반복한다.
6. 사용자의 입력이 1번에서 생성한 숫자와 일치 할 경우 필요한 정보를 출력하고 프로그램을 종료한다.
6-a. try count를 출력한다.
6-b. 프로그램이 종료 된 시간과 프로그램이 시작 된 시간의 차를 계산해 프로그램의 실행 시간을 출력한다.
6-c. 게임이 종료 된 시점의 날짜와 시각을 출력한다.

반응형

댓글