2023. 12. 23. 17:20ㆍpython/basic
이 프로젝트에서는 주사위 굴리기 이벤트를 시뮬레이션하는 애플리케이션을 코딩하게 됩니다. 이를 위해 Python의 random 모듈을 사용합니다.
이 튜토리얼에서는 다음 방법을 배웁니다.
- 주사위 굴리기 이벤트 시뮬레이션 하기 위하여 random.randint() 사용
- 내장된 input()함수를 사용하여 사용자 입력 요청
- 파싱 및 검증 사용자 입력
- .center() 및 .join()와 같은 방법을 사용하여 문자열을 조작합니다.
프로젝트 개요
사용자에게 굴릴 6면체 주사위 수를 선택하라는 메시지를 표시한 다음 사용자의 입력을 읽습니다. | Python 내장 input() 함수 | 적절한 인수를 사용하여 input() 호출 |
사용자 입력을 구문 분석하고 검증합니다. | 문자열 메서드, 비교 연산자 및 조건문 | parse_input() 라는 사용자 정의 함수 |
주사위 굴리기 시뮬레이션 실행 | Python의 random 모듈, 특히 randint() 함수 | roll_dice() 라는 사용자 정의 함수 |
결과 주사위 면으로 ASCII 다이어그램을 생성합니다. | 루프, list.append() 및 str.join() | generate_dice_faces_diagram() 라는 사용자 정의 함수 |
주사위 면의 다이어그램을 화면에 표시 | Python 내장 print() 함수 | 적절한 인수를 사용하여 print() 호출 |
전제조건
- Python에서 스크립트 실행 방법
- Python의 import 메커니즘
- 기본Python 데이터 유형, 주로 문자열 및 정수
- 기본 데이터 구조, 특히 목록
- Python 변수 및 상수
- Python 비교 연산자
- 부울 값 및 논리식
- 조건부문
- Python for 루프
- 파이썬에서 기본입력, 출력 및 문자열 형식 지정
1단계: Python 주사위 굴리기 앱의 TUI 코딩
명령줄에서 사용자 입력 받기
# dice.py
# ~~~ App's main code block ~~~
# 1. Get and validate user's input
num_dice_input = input("How many dice do you want to roll? [1-6] ")
num_dice = parse_input(num_dice_input)
사용자 입력 구문 분석 및 유효성 검사
# dice.py
def parse_input(input_string):
"""Return `input_string` as an integer between 1 and 6.
Check if `input_string` is an integer number between 1 and 6.
If so, return an integer with the same value. Otherwise, tell
the user to enter a valid number and quit the program.
"""
if input_string.strip() in {"1", "2", "3", "4", "5", "6"}:
return int(input_string)
else:
print("Please enter a number from 1 to 6.")
raise SystemExit(1)
# ~~~ App's main code block ~~~
# ...
- 3번째 행은 입력 문자열을 인수로 사용하는 parse_input()를 정의합니다.
- 4~9행은 함수의 독스트링을 제공합니다. 유익하고 올바른 형식의 독스트링을 함수에 포함시키는 것은 Python 프로그래밍의 모범 사례입니다. 독스트링을 사용하면 코드를 문서화할 수 있기 때문입니다.
- 10행은 사용자 입력이 굴릴 주사위 수에 대한 유효한 값인지 확인합니다. .strip() 호출은 입력 문자열 주위에 불필요한 공백을 제거합니다. in 연산자는 입력이 허용된 주사위 수 집합 내에 있는지 확인합니다. 이 경우 Python에서 멤버십 테스트를 수행하므로 세트를 사용합니다. 데이터 구조는 매우 효율적입니다.
- 11행은 입력을 정수로 변환하여 호출자에게 반환합니다.
- 13행은 해당되는 경우 사용자에게 잘못된 입력을 알리는 메시지를 화면에 인쇄합니다.
- 14행은 SystemExit 예외 및 상태 코드1 문제가 발생했음을 알리는 신호입니다.
2단계: Python에서 육면체 주사위 굴리기 시뮬레이션
# dice.py
import random
# ...
def roll_dice(num_dice):
"""Return a list of integers with length `num_dice`.
Each integer in the returned list is a random number between
1 and 6, inclusive.
"""
roll_results = []
for _ in range(num_dice):
roll = random.randint(1, 6)
roll_results.append(roll)
return roll_results
# ~~~ App's main code block ~~~
# ...
- 2행은 random을 현재 네임스페이스로 가져옵니다.
- 6행은 roll_dice()를 정의하며, 이는 주어진 호출에서 굴릴 주사위 수를 나타내는 인수를 취합니다.
- 7~11행은 함수의 docstring을 제공합니다.
- 12행은 빈 목록, roll_results을 생성합니다. 주사위 굴리기 시뮬레이션 결과를 저장합니다.
- 13행은 사용자가 굴리려는 각 주사위에 대해 한 번씩 반복하는 for 루프를 정의합니다.
- 14행은 randint()를 호출하여 1부터 6까지의 의사 난수 정수를 생성합니다. 이 호출은 각 반복마다 단일 숫자를 생성합니다. 이 숫자는 6각형 주사위를 굴린 결과를 나타냅니다.
- 15행은 roll_results에 현재 주사위 굴리기 결과를 추가합니다.
- 16행은 주사위 굴리기 시뮬레이션 결과 목록을 반환합니다.
새로 생성된 함수를 시험해 보려면 dice.py 파일 끝에 다음 코드 줄을 추가하세요.
# dice.py
# ...
# ~~~ App's main code block ~~~
# 1. Get and validate user's input
num_dice_input = input("How many dice do you want to roll? [1-6] ")
num_dice = parse_input(num_dice_input)
# 2. Roll the dice
roll_results = roll_dice(num_dice)
print(roll_results) # Remove this line after testing the app
3단계: 주사위 면의 ASCII 다이어그램 생성 및 표시
# dice.py
import random
DICE_ART = {
1: (
"┌─────────┐",
"│ │",
"│ ● │",
"│ │",
"└─────────┘",
),
2: (
"┌─────────┐",
"│ ● │",
"│ │",
"│ ● │",
"└─────────┘",
),
3: (
"┌─────────┐",
"│ ● │",
"│ ● │",
"│ ● │",
"└─────────┘",
),
4: (
"┌─────────┐",
"│ ● ● │",
"│ │",
"│ ● ● │",
"└─────────┘",
),
5: (
"┌─────────┐",
"│ ● ● │",
"│ ● │",
"│ ● ● │",
"└─────────┘",
),
6: (
"┌─────────┐",
"│ ● ● │",
"│ ● ● │",
"│ ● ● │",
"└─────────┘",
),
}
DIE_HEIGHT = len(DICE_ART[1])
DIE_WIDTH = len(DICE_ART[1][0])
DIE_FACE_SEPARATOR = " "
# ...
4~47행에서는 ASCII 문자를 사용하여 6개의 주사위 면을 그립니다. 각 얼굴을 해당 정수 값에 매핑하는 사전인 DICE_ART에 얼굴을 저장합니다.
라인 48은 주어진 면이 차지할 행 수를 보유하는 DIE_HEIGHT을 정의합니다. 이 예에서 각 면은 5개의 행을 차지합니다. 마찬가지로 49행에서는 주사위 면을 그리는 데 필요한 열 수를 유지하도록 DIE_WIDTH를 정의합니다. 이 예에서 너비는 11자입니다.
마지막으로 50행에서는 공백 문자를 포함하는 DIE_FACE_SEPARATOR을 정의합니다. 이 모든 상수를 사용하여 애플리케이션에 맞는 주사위 면의 ASCII 다이어그램을 생성하고 표시하게 됩니다.
주사위 면의 다이어그램 생성
# dice.py
# ...
def generate_dice_faces_diagram(dice_values):
"""Return an ASCII diagram of dice faces from `dice_values`.
The string returned contains an ASCII representation of each die.
For example, if `dice_values = [4, 1, 3, 2]` then the string
returned looks like this:
~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ ● ● │ │ │ │ ● │ │ ● │
│ │ │ ● │ │ ● │ │ │
│ ● ● │ │ │ │ ● │ │ ● │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
"""
# Generate a list of dice faces from DICE_ART
dice_faces = []
for value in dice_values:
dice_faces.append(DICE_ART[value])
# Generate a list containing the dice faces rows
dice_faces_rows = []
for row_idx in range(DIE_HEIGHT):
row_components = []
for die in dice_faces:
row_components.append(die[row_idx])
row_string = DIE_FACE_SEPARATOR.join(row_components)
dice_faces_rows.append(row_string)
# Generate header with the word "RESULTS" centered
width = len(dice_faces_rows[0])
diagram_header = " RESULTS ".center(width, "~")
dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
return dice_faces_diagram
# ~~~ App's main code block ~~~
# ...
- 5행은 dice_values이라는 단일 인수로 generate_dice_faces_diagram()를 정의합니다. 이 인수는 roll_dice()를 호출하여 얻은 주사위 굴림 정수 값 목록을 보유합니다.
- 6~18행 함수의 독스트링을 제공합니다.
- 20행은 dice_faces라는 빈 목록을 생성하여 입력된 주사위 값 목록에 해당하는 주사위 면을 저장합니다. 이 주사위 면은 최종 ASCII 다이어그램에 표시됩니다.
- 21행은 주사위 값을 반복하는 for 루프를 정의합니다.
- 22행은 DICE_ART에서 현재 주사위 값에 해당하는 주사위 면을 검색하여 dice_faces에 추가합니다.
- 25행는 최종 주사위 면 다이어그램의 행을 보관할 빈 목록을 만듭니다.
- 26행은 0에서 DIE_HEIGHT - 1까지의 인덱스를 반복하는 루프를 정의합니다. 각 색인은 주사위 면 다이어그램에서 특정 행의 색인을 나타냅니다.
- 27행은 row_components를 주어진 행을 채울 주사위 면의 일부를 담는 빈 목록으로 정의합니다.
- 28행은 중첩된 for 루프를 시작하여 주사위 면을 반복합니다.
- 29행은 각 행 구성요소를 저장합니다.
- 30행은 행 구성요소를 최종 행 문자열로 결합하고 개별 구성요소를 공백으로 구분합니다.
- 31행은 최종 다이어그램을 구성할 행이 포함된 목록에 각 행 문자열을 추가합니다.
- 34행은 현재 주사위 면 다이어그램의 width를 보유할 임시 변수를 생성합니다.
- 35행은 RESULTS라는 단어를 표시하는 헤더를 생성합니다. 이를 위해 다이어그램의 width및 물결표 기호() ~ 와 함께 str.center()를 인수로 사용합니다.
- 37행은 최종 주사위 면 다이어그램을 포함하는 문자열을 생성합니다. 줄 바꿈 문자(\n)는 행 구분 기호로 사용됩니다. .join()에 대한 인수는 다이어그램 헤더와 주사위 면을 형성하는 문자열(행)을 연결하는 문자열 목록입니다.
- 38행은 인쇄 가능한 주사위 면 다이어그램을 호출자에게 반환합니다.
앱의 메인 코드를 완성하고 주사위를 굴려보세요
# dice.py
# ...
# ~~~ App's main code block ~~~
# 1. Get and validate user's input
num_dice_input = input("How many dice do you want to roll? [1-6] ")
num_dice = parse_input(num_dice_input)
# 2. Roll the dice
roll_results = roll_dice(num_dice)
# 3. Generate the ASCII diagram of dice faces
dice_face_diagram = generate_dice_faces_diagram(roll_results)
# 4. Display the diagram
print(f"\n{dice_face_diagram}")
generate_dice_faces_diagram() 구현으로 돌아가면 코드의 해당 부분이 수행하는 작업을 지적하는 몇 가지 주석이 포함되어 있음을 알 수 있습니다.
라인 12는 generate_dice_faces_diagram() roll_results를 인수로 사용하여 호출합니다. 이 호출은 현재 주사위 굴리기 결과에 해당하는 주사위 면의 다이어그램을 작성하고 반환합니다. 14행에서는 print() 호출하여 화면에 다이어그램을 표시합니다.
def generate_dice_faces_diagram(dice_values):
# ...
# Generate a list of dice faces from DICE_ART
dice_faces = []
for value in dice_values:
dice_faces.append(DICE_ART[value])
# Generate a list containing the dice faces rows
dice_faces_rows = []
for row_idx in range(DIE_HEIGHT):
row_components = []
for die in dice_faces:
row_components.append(die[row_idx])
row_string = DIE_FACE_SEPARATOR.join(row_components)
dice_faces_rows.append(row_string)
# Generate header with the word "RESULTS" centered
width = len(dice_faces_rows[0])
diagram_header = " RESULTS ".center(width, "~")
dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
return dice_faces_diagram
4단계: 주사위면 다이어그램을 생성하는 코드 리팩터링
추출 메소드추출 메소드라는 리팩터링 기술이 있습니다. 독립적으로 작동할 수 있는 기능을 추출하여 코드를 개선하는 데 도움을 줍니다. 예를 들어, generate_dice_faces_diagram()의 이전 구현에서 20~22행의 코드를 추출하여 _get_dice_faces()인 비공개 도우미 함수에 배치할 수 있습니다.
def _get_dice_faces(dice_values):
dice_faces = []
for value in dice_values:
dice_faces.append(DICE_ART[value])
return dice_faces
# dice.py
# ...
def generate_dice_faces_diagram(dice_values):
"""Return an ASCII diagram of dice faces from `dice_values`.
The string returned contains an ASCII representation of each die.
For example, if `dice_values = [4, 1, 3, 2]` then the string
returned looks like this:
~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ ● ● │ │ │ │ ● │ │ ● │
│ │ │ ● │ │ ● │ │ │
│ ● ● │ │ │ │ ● │ │ ● │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
"""
dice_faces = _get_dice_faces(dice_values)
dice_faces_rows = _generate_dice_faces_rows(dice_faces)
# Generate header with the word "RESULTS" centered
width = len(dice_faces_rows[0])
diagram_header = " RESULTS ".center(width, "~")
dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
return dice_faces_diagram
def _get_dice_faces(dice_values):
dice_faces = []
for value in dice_values:
dice_faces.append(DICE_ART[value])
return dice_faces
def _generate_dice_faces_rows(dice_faces):
dice_faces_rows = []
for row_idx in range(DIE_HEIGHT):
row_components = []
for die in dice_faces:
row_components.append(die[row_idx])
row_string = DIE_FACE_SEPARATOR.join(row_components)
dice_faces_rows.append(row_string)
return dice_faces_rows
# ~~~ App's main code block ~~~
# ...
소스 코드 가져오기: https://realpython.com/bonus/python-dice-roll-project-code/를 클릭하여 Python 주사위 굴리기 앱을 빌드하는 데 사용할 소스 코드를 가져오세요.
'python > basic' 카테고리의 다른 글
Django와 Python으로 개인 일기 만들기 (0) | 2023.12.25 |
---|---|
Python의 pip를 사용하여 프로젝트 관리 종속성 관리하기 (0) | 2023.12.24 |
밖에 비가 내리고있다? Python으로 Weather CLI 앱 구축 (1) | 2023.12.22 |
Python의 all()-Iterable의 진실성을 확인하세요. (1) | 2023.12.21 |
Tkinter를 사용한 Python GUI 프로그래밍2 (1) | 2023.12.20 |