야구 게임의 규칙.
- 각 플레이어가 서로의 숫자를 맞추는 게임.
- 상대방의 3자리 숫자를 추측해야 함.
- 숫자는 0에서 9 사이의 서로 다른 숫자로 구성됨.
- 숫자와 위치를 정확히 맞추면 "스트라이크" 획득.
- 숫자만 맞추고 위치가 다르면 "볼" 획득.
- 정답을 맞출 때까지 턴을 번갈아 진행.
- 최소한의 시도로 정답을 맞추는 것이 목표.
이를 컴퓨터와 게임을 하는 것으로 바꾸고, 컴퓨터의 숫자만을 맞추는 것으로 변경하여 최소한의 시도횟수가 가장 높은 스코어로 표시되도록 Python으로 구현하면 다음과 같음.
Python 구현
함수를 이용하여 structured programming을 이용해 구현함.
- Function으로 모듈화.
- 전역변수(global variable)를 최대한 피하여 구현.
import random
def generate_secret_number():
"""
서로 다른 3자리 숫자를 랜덤으로 생성.
Returns:
list[int]: 3자리 숫자로 구성된 리스트.
"""
digits = list(range(10)) # 0~9까지 숫자 리스트 생성
random.shuffle(digits) # 리스트를 섞음
return digits[:3] # 첫 3개의 숫자를 반환
def get_strike_and_ball(secret_number, guess):
"""
비밀 숫자와 추측 값을 비교하여 스트라이크와 볼 개수를 계산.
Args:
secret_number (list[int]): 컴퓨터가 생성한 3자리 숫자.
guess (list[int]): 플레이어가 입력한 3자리 숫자 리스트.
Returns:
tuple[int, int]: (스트라이크 개수, 볼 개수)
"""
strikes = sum(s == g for s, g in zip(secret_number, guess))
balls = len(set(secret_number) & set(guess)) - strikes
return strikes, balls
def is_valid_guess(guess):
"""
플레이어의 입력이 유효한지 확인.
Args:
guess (str): 플레이어가 입력한 숫자 문자열.
Returns:
bool: 유효한 입력일 경우 True, 그렇지 않으면 False.
"""
if len(guess) != 3 or not guess.isdigit():
return False
digits = list(map(int, guess))
return len(set(digits)) == 3
def update_best_score(current_attempts, best_score):
"""
현재 게임의 시도 횟수를 기준으로 최고 스코어를 갱신.
Args:
current_attempts (int): 현재 게임의 시도 횟수.
best_score (int): 이전 최고 스코어.
Returns:
int: 갱신된 최고 스코어.
"""
return min(current_attempts, best_score)
def play_game():
"""
숫자 야구 게임 실행. 게임 루프를 포함하며 플레이어가 계속하거나 종료를 선택할 수 있음.
"""
print("숫자 야구 게임에 오신 것을 환영합니다!")
best_score = float('inf') # 최고 스코어 초기화
while True: # 게임 전체 반복 루프
secret_number = generate_secret_number()
attempts = 0
print("새로운 숫자가 생성되었습니다. 시작합니다!")
while True: # 단일 게임 루프
guess = input("3자리 숫자를 입력하세요 (게임 종료: q): ")
if guess.lower() == 'q': # 게임 종료 조건
print("게임을 종료합니다. 즐거운 시간 되세요!")
return
if not is_valid_guess(guess): # 유효하지 않은 입력 처리
print("잘못된 입력입니다. 서로 다른 숫자로 이루어진 3자리 숫자를 입력하세요.")
continue
guess = list(map(int, guess)) # 입력을 정수 리스트로 변환
attempts += 1
strikes, balls = get_strike_and_ball(secret_number, guess) # 스트라이크와 볼 계산
print(f"{strikes} 스트라이크, {balls} 볼") # 결과 출력
if strikes == 3: # 정답 맞춤
print(f"축하합니다! {attempts}번 만에 정답을 맞추셨습니다!")
best_score = update_best_score(attempts, best_score) # 최고 스코어 갱신
break
# 최고 스코어 출력
print(f"현재 최고 스코어: {best_score} 시도")
again = input("게임을 계속하시겠습니까? (계속: Enter, 종료: q): ")
if again.lower() == 'q': # 게임 종료 선택
print("게임을 종료합니다. 즐거운 시간 되세요!")
break
if __name__ == "__main__":
play_game()
Python 구현: Type Annotation을 이용.
2023.08.30 - [Python] - [Python] Type Annotation: 파이썬에서 변수 및 함수에 type 지정.
[Python] Type Annotation: 파이썬에서 변수 및 함수에 type 지정.
Python은 Dynamic language이기 때문에 variable은 여러 type object를 가르킬 수 있다.이는 매우 높은 유연성을 제공해주고, 작은 규모의 소스코드에서는 잘 동작한다. (특히 type에 대해 자유롭다보니 언어
ds31x.tistory.com
Type Annotation을 추가한 구현은 다음과 같음.
import random
from typing import List, Tuple
def generate_secret_number() -> List[int]:
"""
서로 다른 3자리 숫자를 랜덤으로 생성.
Returns:
List[int]: 3자리 숫자로 구성된 리스트.
"""
digits = list(range(10)) # 0~9까지 숫자 리스트 생성
random.shuffle(digits) # 리스트를 섞음
return digits[:3] # 첫 3개의 숫자를 반환
def get_strike_and_ball(secret_number: List[int], guess: List[int]) -> Tuple[int, int]:
"""
비밀 숫자와 추측 값을 비교하여 스트라이크와 볼 개수를 계산.
Args:
secret_number (List[int]): 컴퓨터가 생성한 3자리 숫자.
guess (List[int]): 플레이어가 입력한 3자리 숫자 리스트.
Returns:
Tuple[int, int]: (스트라이크 개수, 볼 개수)
"""
strikes = sum(s == g for s, g in zip(secret_number, guess))
balls = len(set(secret_number) & set(guess)) - strikes
return strikes, balls
def is_valid_guess(guess: str) -> bool:
"""
플레이어의 입력이 유효한지 확인.
Args:
guess (str): 플레이어가 입력한 숫자 문자열.
Returns:
bool: 유효한 입력일 경우 True, 그렇지 않으면 False.
"""
if len(guess) != 3 or not guess.isdigit():
return False
digits = list(map(int, guess))
return len(set(digits)) == 3
def update_best_score(current_attempts: int, best_score: int) -> int:
"""
현재 게임의 시도 횟수를 기준으로 최고 스코어를 갱신.
Args:
current_attempts (int): 현재 게임의 시도 횟수.
best_score (int): 이전 최고 스코어.
Returns:
int: 갱신된 최고 스코어.
"""
return min(current_attempts, best_score)
def play_game() -> None:
"""
숫자 야구 게임 실행. 게임 루프를 포함하며 플레이어가 계속하거나 종료를 선택할 수 있음.
"""
print("숫자 야구 게임에 오신 것을 환영합니다!")
best_score: int = float('inf') # 최고 스코어 초기화
while True: # 게임 전체 반복 루프
secret_number: List[int] = generate_secret_number()
attempts: int = 0
print("새로운 숫자가 생성되었습니다. 시작합니다!")
while True: # 단일 게임 루프
guess: str = input("3자리 숫자를 입력하세요 (게임 종료: q): ")
if guess.lower() == 'q': # 게임 종료 조건
print("게임을 종료합니다. 즐거운 시간 되세요!")
return
if not is_valid_guess(guess): # 유효하지 않은 입력 처리
print("잘못된 입력입니다. 서로 다른 숫자로 이루어진 3자리 숫자를 입력하세요.")
continue
guess_list: List[int] = list(map(int, guess)) # 입력을 정수 리스트로 변환
attempts += 1
strikes, balls = get_strike_and_ball(secret_number, guess_list) # 스트라이크와 볼 계산
print(f"{strikes} 스트라이크, {balls} 볼") # 결과 출력
if strikes == 3: # 정답 맞춤
print(f"축하합니다! {attempts}번 만에 정답을 맞추셨습니다!")
best_score = update_best_score(attempts, best_score) # 최고 스코어 갱신
break
# 최고 스코어 출력
print(f"현재 최고 스코어: {best_score} 시도")
again: str = input("게임을 계속하시겠습니까? (계속: Enter, 종료: q): ")
if again.lower() == 'q': # 게임 종료 선택
print("게임을 종료합니다. 즐거운 시간 되세요!")
break
if __name__ == "__main__":
play_game()
OOP로 작성
Python 3.10이상에서 동작하는 것을 가정하고, OOP로 작성한 코드는 다음과 같음.
import random
class NumberBaseballGame:
"""
숫자 야구 게임 클래스.
- 3자리 비밀 숫자를 생성하고 플레이어가 추측하여 맞추는 게임을 관리합니다.
"""
def __init__(self):
"""
게임 초기화.
- secret_number: 생성된 비밀 숫자.
- attempts: 현재 게임에서 시도한 횟수.
- best_score: 플레이어가 달성한 최소 시도 횟수 기록.
"""
self.secret_number: list[int] = []
self.attempts: int = 0
self.best_score: int = float('inf')
def generate_secret_number(self) -> None:
"""
서로 다른 3자리 숫자를 생성하여 secret_number에 저장.
"""
digits = list(range(10))
random.shuffle(digits)
self.secret_number = digits[:3]
def get_strike_and_ball(self, guess: list[int]) -> tuple[int, int]:
"""
비밀 숫자와 추측 값을 비교하여 스트라이크와 볼 개수를 계산.
Args:
guess (list[int]): 플레이어가 입력한 숫자 리스트.
Returns:
tuple[int, int]: (스트라이크 개수, 볼 개수)
"""
strikes = sum(s == g for s, g in zip(self.secret_number, guess))
balls = len(set(self.secret_number) & set(guess)) - strikes
return strikes, balls
def is_valid_guess(self, guess: str) -> bool:
"""
플레이어의 입력이 유효한지 확인.
Args:
guess (str): 플레이어가 입력한 숫자 문자열.
Returns:
bool: 유효한 입력일 경우 True, 그렇지 않으면 False.
"""
if len(guess) != 3 or not guess.isdigit():
return False
digits = list(map(int, guess))
return len(set(digits)) == 3
def update_best_score(self) -> None:
"""
현재 게임의 시도 횟수를 기준으로 최고 스코어를 갱신.
"""
if self.attempts < self.best_score:
self.best_score = self.attempts
def play_single_game(self) -> None:
"""
한 번의 숫자 야구 게임을 실행.
- 정답을 맞출 때까지 반복.
"""
self.generate_secret_number()
self.attempts = 0
print("새로운 숫자가 생성되었습니다. 시작합니다!")
while True:
guess = input("3자리 숫자를 입력하세요 (게임 종료: q): ")
if guess.lower() == 'q': # 게임 종료
print("게임을 종료합니다. 즐거운 시간 되세요!")
return
if not self.is_valid_guess(guess):
print("잘못된 입력입니다. 서로 다른 숫자로 이루어진 3자리 숫자를 입력하세요.")
continue
guess_list = list(map(int, guess))
self.attempts += 1
strikes, balls = self.get_strike_and_ball(guess_list)
print(f"{strikes} 스트라이크, {balls} 볼")
if strikes == 3:
print(f"축하합니다! {self.attempts}번 만에 정답을 맞추셨습니다!")
self.update_best_score()
break
def play_game(self) -> None:
"""
숫자 야구 게임을 실행.
- 플레이어가 종료를 선택할 때까지 반복.
"""
print("숫자 야구 게임에 오신 것을 환영합니다!")
while True:
self.play_single_game()
print(f"현재 최고 스코어: {self.best_score} 시도")
again = input("게임을 계속하시겠습니까? (계속: Enter, 종료: q): ")
if again.lower() == 'q':
print("게임을 종료합니다. 즐거운 시간 되세요!")
break
if __name__ == "__main__":
game = NumberBaseballGame()
game.play_game()
'Python' 카테고리의 다른 글
[Py] Context Manager: with statement! (0) | 2024.11.27 |
---|---|
[Py] Higher-order Function (고차함수) (1) | 2024.11.20 |
[DIP] Block Truncation Coding (BTC) (0) | 2024.11.18 |
[Py] Queue 와 Stack 구현하기: 상속과 오버라이딩 이용. (0) | 2024.11.13 |
[Py] 사칙연산 구현 예제 (0) | 2024.11.13 |