-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter14_1.py
109 lines (86 loc) · 4.01 KB
/
chapter14_1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# ch14
# 하노이 탑과 사목 게임
"""하노이 탑, 작성자 : ****
원판 더미를 움직이는 퍼즐 게임"""
import copy
import sys
#
TOTAL_DISKS = 5 # 원판이 많을 수록 퍼즐은 더 어려워진다.
SOLVED_TOWER = list(range(TOTAL_DISKS, 0, -1))
def main():
"""하노이 탑을 실행한다."""
print(
"""하노이 탑, 작성자: Wi Seonggyu **@****.com
탑에 쌓인 원판을 한 번에 하나씩 다른 탑으로 이동한다.
큰 원판은 작은 원판 위에 놓일 수 없다.
추가 정보는 https://en.wikipedia.org/wiki/Tower_of_hanoi를 참고한다.""")
towers = {"A":copy.copy(SOLVED_TOWER),"B":[],"C":[]}
while True:
# 탑과 원판을 표시한다.
displayTowers(towers)
# 사용자에게 이동 명령을 요청한다.
fromTower, toTower = getPlayerMove(towers)
# 맨 위 원판을 fromTower에서 toTower로 이동한다.
disk = towers[fromTower].pop()
towers[toTower].append(disk)
# 사용자가 퍼즐을 풀었는지 확인한다.
if SOLVED_TOWER in (towers["B"], towers["C"]):
displayTowers(towers) # 마지막으로 한번 더 표시한다.
print("퍼즐을 풀었습니다! 참 잘했습니다")
sys.exit()
def getPlayerMove(towers):
"""플레이어에게 이동 명령을 요청한다. (fromTower, toTower)를 반환한다"""
while True: # 플레이어가 유효한 이동 명령을 입력할 때까지 계속 요청한다.
print('탑의 "시작"과 "끝"의 글자 또는 QUIT를 입력하시오')
print('(예: 탑 A에서 탑 B로 원판을 이동하려면 AB를 입력합니다.)')
print()
response = input("> ").upper().strip()
if response == "QUIT":
print("즐겁게 퍼즐을 풀어주셔서 감사합니다")
sys.exit()
# 사용자가 유효한 탑 문자를 입력했는지 확인한다.
if response not in ("AB","AC","BA","BC","CA","CB"):
print("AB, AC, BA, CA, CB 중 하나를 입력하십시오.")
continue
# 더 설명적인 변수 이름을 사용한다.
fromTower, toTower = response[0],response[1]
if len(towers[fromTower])==0:
# from 탑은 비어 있을 수 없다.
print("원판이 없는 탑을 선택했습니다.")
continue # 플레이어에게 이동 명령을 다시 요청한다.
elif len(towers[toTower]) == 0:
# 어떤 원판이라도 빈 "to" 탑으로 이동이 가능하다.
return fromTower, toTower
elif towers[toTower][-1] < towers[fromTower][-1]:
print('더 작은 원판에 더 큰 원판을 올릴 수 없습니다.')
continue
else:
# 유효한 움직임임으로 선택된 탑을 반환한다.
return fromTower, toTower
def displayTowers(towers):
"""세 탑에 배치된 원판을 표시한다."""
# 세 탑을 표시한다.
for level in range(TOTAL_DISKS,-1, -1):
for tower in (towers["A"], towers["B"], towers["C"]):
if level >= len(tower):
displayDisk(0) # 원판이 없는 빈 기둥을 표시한다.
else:
displayDisk(tower[level]) # 원판을 표시한다.
print()
# 탑 이름 A, B, C를 표시한다.
emptySpace = " " * TOTAL_DISKS
print("{0} A{0}{0} B{0}{0} C\n".format(emptySpace))
def displayDisk(width):
"""주어진 Width로 원판을 표시한다. width가 0이면 원판이 없음을 의미한다."""
emptySpace = " " * (TOTAL_DISKS - width)
if width == 0:
# 원판이 없는 기둥을 표시한다.
print(f"{emptySpace}||{emptySpace}", end="")
else:
# 원판을 표시한다
disk = "@" * width
numLabel = str(width).rjust(2, "_")
print(f"{emptySpace}{disk}{numLabel}{disk}{emptySpace}", end="")
# 이 프로그램이 임포트 되지 않고 단독으로 실행되면 게임을 시작한다.
if __name__ == "__main__":
main()