206 lines
10 KiB
Python
206 lines
10 KiB
Python
# Охотник за сокровищами
|
||
|
||
import random
|
||
import sys
|
||
import math
|
||
|
||
def getNewBoard():
|
||
# Создать структуру данных нового игрового поля размером 60х15.
|
||
board = []
|
||
for x in range(60): # Главный список из 60 списков.
|
||
board.append([])
|
||
for y in range(15): # Каждый список в главном списке содержит 15 односимвольных строк.
|
||
# Для создания океана используем разные символы, чтобы сделать его реалистичнее.
|
||
if random.randint(0, 1) == 0:
|
||
board[x].append('~')
|
||
else:
|
||
board[x].append('`')
|
||
|
||
return board
|
||
|
||
def drawBoard(board):
|
||
# Изобразить структуру данных игрового поля.
|
||
tensDigitsLine = ' ' # Создать место для чисел вниз по левой стороне поля.
|
||
for i in range(1, 6):
|
||
tensDigitsLine += (' ' * 9) + str(i)
|
||
# Вывести числа в верхней части поля.
|
||
print(tensDigitsLine)
|
||
print('' + ('0123456789' * 6))
|
||
print()
|
||
# Вывести каждый из 15 рядов.
|
||
for row in range(15):
|
||
# К однозначным числам нужно добавить дополнительный пробел.
|
||
if row < 10:
|
||
extraSpace = ' '
|
||
else:
|
||
extraSpace = ''
|
||
|
||
|
||
# Создать строку для этого ряда на игровом поле.
|
||
boardRow = ''
|
||
for column in range(60):
|
||
boardRow += board[column][row]
|
||
print('%s%s %s %s' % (extraSpace, row, boardRow, row))
|
||
# Вывести числа в нижней части поля.
|
||
print()
|
||
print('' + ('0123456789' * 6))
|
||
print(tensDigitsLine)
|
||
|
||
|
||
def getRandomChests(numChests):
|
||
# Создать список структур данных сундука (двухэлементные списки целочисленных координат x и y)).
|
||
chests = []
|
||
while len(chests) < numChests:
|
||
newChest = [random.randint(0, 59), random.randint(0, 14)]
|
||
if newChest not in chests: # Убедиться, что сундука здесь еще нет.
|
||
chests.append(newChest)
|
||
return chests
|
||
|
||
|
||
def isOnBoard(x, y):
|
||
# Возвращать True, если координаты есть на поле; в противном случае возвращать False.
|
||
return x >= 0 and x <= 59 and y >= 0 and y <= 14
|
||
|
||
def makeMove(board, chests, x, y):
|
||
# Изменить структуру данных поля, используя символ гидролокатора. Удалить сундуки
|
||
# с сокровищами из списка с сундуками, как только их нашли. Вернуть False, если это
|
||
# недопустимый ход. В противном случае, вернуть строку с результатом этого хода.
|
||
smallestDistance = 100 # Все сундуки будут расположены ближе, чем на расстоянии в 100 единиц.
|
||
for cx, cy in chests:
|
||
distance = math.sqrt((cx - x) * (cx - x) + (cy - y) * (cy - y))
|
||
|
||
if distance < smallestDistance: # Нам нужен ближайший сундук с сокровищами.
|
||
smallestDistance = distance
|
||
|
||
smallestDistance = round(smallestDistance)
|
||
|
||
if smallestDistance == 0:
|
||
# Координаты xy попали прямо в сундук с сокровищами!
|
||
chests.remove([x, y])
|
||
return 'Вы нашли сундук с сокровищами на затонувшем судне!'
|
||
else:
|
||
if smallestDistance < 10:
|
||
board[x][y] = str(smallestDistance)
|
||
return 'Сундук с сокровищами обнаружен на расстоянии %s от гидролокатора.' % (smallestDistance)
|
||
else:
|
||
board[x][y] = 'Х'
|
||
return 'Гидролокатор ничего не обнаружил. Все сундуки с сокровищами вне пределов досягаемости.'
|
||
|
||
def enterPlayerMove(previousMoves):
|
||
# Позволить игроку сделать ход. Вернуть двухэлементный список с целыми координатами x и y.
|
||
print('Где следует опустить гидролокатор? (координаты: 0-59 0-14) (или введите "выход")')
|
||
while True:
|
||
move = input()
|
||
if move.lower() == 'выход':
|
||
print('Спасибо за игру!')
|
||
sys.exit()
|
||
|
||
move = move.split()
|
||
if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isOnBoard(int(move[0]), int(move[1])):
|
||
if [int(move[0]), int(move[1])] in previousMoves:
|
||
print('Здесь вы уже опускали гидролокатор.')
|
||
continue
|
||
return [int(move[0]), int(move[1])]
|
||
|
||
print('Введите число от 0 до 59, потом пробел, а затем число от 0 до 14.')
|
||
|
||
def showInstructions():
|
||
print('''Инструктаж:
|
||
Вы - капитан корабля, плывущего за сокровищами. Ваша задача - с помощью
|
||
гидролокаторов найти три сундука с сокровищами в затонувших судах на дне океана.
|
||
Но гидролокаторы очень просты и определяют только расстояние, но не направление.
|
||
Введите координаты, чтобы опустить гидролокатор в воду. На карте будет показано
|
||
число, обозначающее, на каком расстоянии находится ближайший сундук. Или будет
|
||
показана буква Х, обозначающая, что сундук в области действия гидролокатора неИгра «Охотник за сокровищами» 225
|
||
обнаружен. На карте ниже метки C - это сундуки.
|
||
Цифра 3 обозначает, что ближайший сундук находится на отдалении в 3 единицы.
|
||
|
||
1 2 3
|
||
012345678901234567890123456789012
|
||
|
||
0 ~~~~`~```~`~``~~~``~`~~``~~~``~`~ 0
|
||
1 ~`~`~``~~`~```~~~```~~`~`~~~`~~~~ 1
|
||
2 `~`C``3`~~~~`C`~~~~`````~~``~~~`` 2
|
||
3 ````````~~~`````~~~`~`````~`~``~` 3
|
||
4 ~`~~~~`~~`~~`C`~``~~`~~~`~```~``~ 4
|
||
|
||
012345678901234567890123456789012
|
||
1 2 3
|
||
(Во время игры сундуки на карте не обозначаются!)
|
||
|
||
Нажмите клавишу Enter, чтобы продолжить...''')
|
||
input()
|
||
|
||
print('''Если гидролокатор опущен прямо на сундук, вы сможете поднять
|
||
сундук. Другие гидролокаторы обновят данные о расположении ближайшего сундука.
|
||
Сундуки ниже находятся вне диапазона локатора, поэтому отображается буква X.
|
||
|
||
1 2 3
|
||
012345678901234567890123456789012
|
||
|
||
0 ~~~~`~```~`~``~~~``~`~~``~~~``~`~ 0
|
||
1 ~`~`~``~~`~```~~~```~~`~`~~~`~~~~ 1
|
||
2 `~`X``7`~~~~`C`~~~~`````~~``~~~`` 2
|
||
3 ````````~~~`````~~~`~`````~`~``~` 3
|
||
4 ~`~~~~`~~`~~`C`~``~~`~~~`~```~``~ 4
|
||
|
||
012345678901234567890123456789012
|
||
1 2 3
|
||
|
||
Сундуки с сокровищами не перемещаются. Гидролокаторы определяют сундуки
|
||
на расстоянии до 9 единиц. Попробуйте поднять все 3 сундука до того, как все
|
||
гидролокаторы будут опущены на дно. Удачи!
|
||
|
||
Нажмите клавишу Enter, чтобы продолжить...''')
|
||
input()
|
||
|
||
|
||
print('О х о т н и к з а с о к р о в и щ а м и !')
|
||
print()
|
||
print('Показать инструктаж? (да/нет) ')
|
||
if input().lower().startswith('д'):
|
||
showInstructions()
|
||
|
||
while True:
|
||
# Настройка игры
|
||
sonarDevices = 20
|
||
theBoard = getNewBoard()
|
||
theChests = getRandomChests(3)
|
||
drawBoard(theBoard)
|
||
previousMoves = []
|
||
|
||
|
||
while sonarDevices > 0:
|
||
# Показать гидролокаторные устройства и сундуки с сокровищами.
|
||
print("Осталось гидролокаторов: %s Осталось сундуков с сокровищами: %s" % (sonarDevices, len(theChests)))
|
||
|
||
x, y = enterPlayerMove(previousMoves)
|
||
previousMoves.append([x, y]) # Мы должны отслеживать все ходы, чтобы гидролокаторы могли обновляться.
|
||
|
||
moveResult = makeMove(theBoard, theChests, x, y)
|
||
if moveResult == False:
|
||
continue
|
||
else:
|
||
if moveResult == 'Вы нашли сундук с сокровищами на затонувшем судне!':
|
||
# Обновить все гидролокаторные устройства, в настоящее время находящиеся на карте.
|
||
for x, y in previousMoves:
|
||
makeMove(theBoard, theChests, x, y)
|
||
drawBoard(theBoard)
|
||
print(moveResult)
|
||
|
||
if len(theChests) == 0:
|
||
print('Вы нашли все сундуки с сокровищами на затонувших судах! Поздравляем и приятной игры!')
|
||
break
|
||
|
||
sonarDevices -= 1
|
||
|
||
if sonarDevices == 0:
|
||
print('Все гидролокаторы опущены на дно! Придется разворачивать корабль и')
|
||
print('отправляться домой, в порт! Игра окончена.')
|
||
print('Вы не нашли сундуки в следующих местах:')
|
||
for x, y in theChests:
|
||
print(' %s, %s' % (x, y))
|
||
|
||
print('Хотите сыграть еще раз? (да или нет)')
|
||
if not input().lower().startswith('д'):
|
||
sys.exit() |