# Sonar Game
# drawBoard(board) : 좌표를 받아서 게임보드를 화면에 출력한다.
# getNewBoard() : 보드 데이터 구조를 만든다.
# getRow(board,row) : 행의 가로 상태 알아내기
# getRandomChests(numChests) : 게임 보드에 임의로 흩어져 있는 보물상자 데이터 구조를 만든다.
# isValidMove(x,y) : x,y좌표를 받아 이 좌표가 게임 보드에 있는지 검사한다.
# enterPlayerMove() : 어디에 놓을 건지 X,Y좌표를 받고, 유효한 좌표를 입력할때 까지 계속 묻는다.
# makeMove(board,chests,x,y) : 게임보드에 음파 탐지기를 놓고, 상황을 문자열로 출력한다.
# playAgain() : 게임을 또 할 것인지 묻는다.
# showInstruction() : 게임 방법을 보여준다.
# sys모듈은 exit()함수를 가지고 있다.
# sys.exit()함수 : 프로그램을 바로 종료한다.
def drawBoard(board):
# Draw the board data structure.
# hline -> 공백을 만든다.
hline = ' ' # initial space for the numbers down the left side of the board
for i in range(1, 6):
hline += (' ' * 9) + str(i)
# print the numbers across the top
print(' ' + ('0123456789' * 6))
# print each of the 15 rows
for i in range(15):
# single-digit numbers need to be padded with an extra space
if i < 10:
extraSpace = ' '
else:
extraSpace = ''
print('%s%s %s %s' % (extraSpace, i, getRow(board, i), i))
# print the numbers across the bottom
print(' ' + ('0123456789' * 6))
def getRow(board, row):
# Return a string from the board data structure at a certain row.
boardRow = ''
for i in range(60):
boardRow += board[i][row]
def getNewBoard():
# Create a new 60x15 board data structure.
# 여기서는 60행*15열
board = []
for x in range(60): # the main list is a list of 60 lists
board.append([])
for y in range(15): # each list in the main list has 15 single-character strings # use different characters for the ocean to make it more readable.
# 바다 모양 만들기
if random.randint(0, 1) == 0: # 랜덤함수를 통해 만든다.
board[x].append('~')
else:
board[x].append('`')
def getRandomChests(numChests):
# Create a list of chest data structures (two-item lists of x, y int coordinates)
chests = []
for i in range(numChests): # 보물의 갯수만큼
chests.append([random.randint(0, 59), random.randint(0, 14)])
# x축은 0~59까지, y축은 0~14까지 임의의 랜덤 수를 chests리스트에 붙인다.
# Return True if the coordinates are on the board, otherwise False.
# 전체 사이즈 안에 있어야 유효한 움직임이다.
return x >= 0 and x <= 59 and y >= 0 and y <= 14
def makeMove(board, chests, x, y): # Change the board data structure with a sonar device character. Remove treasure chests
# from the chests list as they are found. Return False if this is an invalid move.
# Otherwise, return the string of the result of this move.
if not isValidMove(x, y):
smallestDistance = 100 # any chest will be closer than 100.
for cx, cy in chests: # 보물의 x,y를 비교한다.
if abs(cx - x) > abs(cy - y): # 절대값 중 큰 값이 거리가 된다. else:
if distance < smallestDistance: # we want the closest treasure chest.
smallestDistance = distance
if smallestDistance == 0: # 거리가 0이 되면 정답이다.
# xy is directly on a treasure chest!
# 리스트 remove(@)메소드 : 리스트의 원소 값 중 파라미터 @값을 찾아 제거한다.
# 단, 지울 값이 없으면 에러가 발생한다.
chests.remove([x, y]) # 정답을 맞췄으므로 보물 리스트에서 지운다. return 'You have found a sunken treasure chest!' else:
if smallestDistance < 10: # 음파 탐지기의 최대 제한 탐지 값이다.
board[x][y] = str(smallestDistance) # 탐지 값 안에 있으면 거리 값을 출력한다. return 'Treasure detected at a distance of %s from the sonar device.' % (smallestDistance) else:
board[x][y] = 'O' # 탐지기에 잡히지 않으면 O를 출력한다. return 'Sonar did not detect anything. All treasure chests out of range.'
def enterPlayerMove():
# Let the player type in her move. Return a two-item list of int xy coordinates.
print('Where do you want to drop the next sonar device? (0-59 0-14) (or type quit)') while True:
move = input()
if move.lower() == 'quit': # 입력 값이 quit일 경우 프로그램을 종료한다.
print('Thanks for playing!') sys.exit() #sys모듈의 exit()함수 : 프로그램을 종료
move = move.split() # 공백을 분할하여 리스트로 저장한다.
# 문자열 메소드 isdigit() : 문자열이 모두 숫자로 되어 있으면 True를 반환한다.
if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isValidMove(int(move[0]), int(move[1])): # 리스트의 길이는 2(x,y 값 2개이므로), 각 문자열은 숫자로만 이뤄져야 한다. 각 숫자들은 움직임에 유효해야 한다.
# 현재 문자열이므로 정수형으로 캐스팅하여 반환한다.
print('Enter a number from 0 to 59, a space, then a number from 0 to 14.')
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)') return input().lower().startswith('y')
def showInstructions(): # 플레이어 에게 게임 방법을 보여준다.
You are the captain of the Simon, a treasure-hunting ship. Your current mission
is to find the three sunken treasure chests that are lurking in the part of the
ocean you are in and collect them.
To play, enter the coordinates of the point in the ocean you wish to drop a
sonar device. The sonar can find out how far away the closest chest is to it.
For example, the d below marks where the device was dropped, and the 2's represent distances of 2 away from the device. The 4's represent
distances of 4 away from the device.
444444444
4 4
4 22222 4
4 2 2 4
4 2 d 2 4
4 2 2 4
4 22222 4
4 4
444444444
Press enter to continue...''')
input()
print('''For example, here is a treasure chest (the c) located a distance of 2 away from the sonar device (the d):
22222
c 2
2 d 2
2 2
22222
The point where the device was dropped will be marked with a 2.
The treasure chests don't move around. Sonar devices can detect treasure
chests up to a distance of 9. If all chests are out of range, the point
will be marked with O
If a device is directly dropped on a treasure chest, you have discovered
the location of the chest, and it will be collected. The sonar device will
remain there.
When you collect a chest, all sonar devices will update to locate the next
closest sunken treasure chest.
Press enter to continue...''')
input()
print()
print('S O N A R !')
print()
print('Would you like to view the instructions? (yes/no)') if input().lower().startswith('y'): showInstructions()
while True:
# game setup
sonarDevices = 30 # 음파 탐지기의 개수
theBoard = getNewBoard()
theChests = getRandomChests(3) # 보물의 개수
drawBoard(theBoard)
previousMoves = []
while sonarDevices > 0:
# Start of a turn:
# sonar device/chest status
if sonarDevices > 1: extraSsonar = 's' # 개수의 단/복수를 표현하기 위해 s를 붙이는 지의 유무 else: extraSsonar = ''
if len(theChests) > 1: extraSchest = 's' else: extraSchest = ''
print('You have %s sonar device%s left. %s treasure chest%s remaining.' % (sonarDevices, extraSsonar, len(theChests), extraSchest))
x, y = enterPlayerMove()
previousMoves.append([x, y]) # 모든 움직임을 기록한다.
# we must track all moves so that sonar devices can be updated.
moveResult = makeMove(theBoard, theChests, x, y)
if moveResult == False:
continue
else:
if moveResult == 'You have found a sunken treasure chest!':
# update all the sonar devices currently on the map.
for x, y in previousMoves:
makeMove(theBoard, theChests, x, y)
drawBoard(theBoard)
print(moveResult)
if len(theChests) == 0:
print('You have found all the sunken treasure chests! Congratulations and good game!')
break
sonarDevices -= 1
if sonarDevices == 0:
print('We\'ve run out of sonar devices! Now we have to turn the ship around and head')
print('for home with treasure chests still out there! Game over.') print(' The remaining chests were here:')
if not playAgain():