Chapter 9 - Sonar
Source Code
- # Sonar
- import random
- import sys
- def drawBoard(board):
- hline = ' ' # initial space for the numbers down the left side of the board
- for i in range(1, 6):
- hline += (' ' * 9) + str(i)
- print hline
- print ' ' + ('0123456789' * 6)
- print
- for i in range(15):
- if i < 10:
- extraSpace = ' '
- else:
- extraSpace = ''
- print '%s%s %s %s' % (extraSpace, i, getRow(board, i), i)
- print
- print ' ' + ('0123456789' * 6)
- print hline
- def getRow(board, row):
- boardRow = ''
- for i in range(60):
- boardRow += board[i][row]
- return boardRow
- def getNewBoard():
- board = []
- for x in range(60):
- board.append([])
- for y in range(15):
- # use different characters for the ocean to make it more readable.
- if random.randint(0, 1) == 0:
- ocean = '~'
- else:
- ocean = '`'
- board[x].append(ocean)
- return board
- def getRandomSubs(numSubs):
- subs = []
- for i in range(numSubs):
- subs.append([random.randint(0, 59), random.randint(0, 14)])
- return subs
- def isValidMove(x, y):
- return x >= 0 and x <= 59 and y >= 0 and y <= 14
- def makeMove(board, subs, x, y):
- if not isValidMove(x, y):
- return False
- smallestDistance = 100
- for s in subs:
- sx = s[0]
- sy = s[1]
- if abs(sx - x) < abs(sy - y):
- distance = abs(sy - y)
- else:
- distance = abs(sx - x)
- if distance < smallestDistance:
- smallestDistance = distance
- if smallestDistance == 0:
- # xy is directly on a sub!
- subs.remove([x, y])
- return 'You have found and destroyed a sub!'
- else:
- if smallestDistance < 10:
- board[x][y] = str(smallestDistance)
- return 'Sub detected at a distance of %s from the sonar device.' % (smallestDistance)
- else:
- board[x][y] = 'O'
- return 'Sonar did not detect anything. All subs out of range.'
-
- def enterPlayerMove():
- print 'Where do you want to drop the next sonar device? (0-59 0-14) (or type quit)'
- while True:
- move = raw_input()
- if move.lower() == 'quit':
- print 'Thanks for playing!'
- sys.exit()
- move = move.split()
- if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isValidMove(int(move[0]), int(move[1])):
- return [int(move[0]), int(move[1])]
- 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 raw_input().lower().startswith('y')
- def showInstructions():
- print '''Instructions:
- You are the captain of a sub-hunting warship, USS Simon. Your current mission
- is to find the three subs that are lurking in the part of the ocean you are in
- and destroy 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 sub 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...'''
- raw_input()
- print '''For example, here is a sub (the s) located a distance of 2 away from the
- sonar device (the d):
- 22222
- s 2
- 2 d 2
- 2 2
- 22222
- The point where the device was dropped will be marked with a 2.
- The subs don't move around. They have shut off their engines and are "running
- dark" to hide from you. Sonar devices can detect subs up to a distance of 9.
- In that case, the point will be marked with O
- If a device is directly dropped on a sub, you have discovered the location of
- the sub, and it will be destroyed with depth charges. The sonar device will
- remain there.
- When you destroy a sub, all sonar devices will update to locate the next
- closest sub.
- Press enter to continue...'''
- raw_input()
- print
- print 'S O N A R !'
- print
- print 'Would you like to view the instructions? (yes/no)'
- if raw_input().lower().startswith('y'):
- showInstructions()
- while True:
- sonarDevices = 16
- theBoard = getNewBoard()
- theSubs = getRandomSubs(3)
- drawBoard(theBoard)
- previousMoves = []
- while sonarDevices > 0:
- if sonarDevices > 1: extraSsonar = 's'
- else: extraSsonar = ''
- if len(theSubs) > 1: extraSsub = 's'
- else: extraSsub = ''
- print 'You have %s sonar device%s left. %s sub%s remaining.' % (sonarDevices, extraSsonar, len(theSubs), extraSsub)
- x, y = enterPlayerMove()
- previousMoves.append([x, y])
- moveResult = makeMove(theBoard, theSubs, x, y)
- if moveResult == False:
- continue
- else:
- if moveResult == 'You have found and destroyed a sub!':
- # update all the sonar devices currently on the map.
- for x, y in previousMoves:
- makeMove(theBoard, theSubs, x, y)
- drawBoard(theBoard)
- print moveResult
- if len(theSubs) == 0:
- print 'You have destroyed all the subs! 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 the subs still out there! Game over.'
- print ' The remaining subs were here:'
- for s in theSubs:
- print ' %s, %s' % (s[0], s[1])
- if not playAgain():
- break
Code Explanation
- # Sonar
- import random
- import sys
- def drawBoard(board):
- hline = ' ' # initial space for the numbers down the left side of the board
- for i in range(1, 6):
- hline += (' ' * 9) + str(i)
- print hline
- print ' ' + ('0123456789' * 6)
- print
- for i in range(15):
- if i < 10:
- extraSpace = ' '
- else:
- extraSpace = ''
- print '%s%s %s %s' % (extraSpace, i, getRow(board, i), i)
- print
- print ' ' + ('0123456789' * 6)
- print hline
- def getRow(board, row):
- boardRow = ''
- for i in range(60):
- boardRow += board[i][row]
- return boardRow
- def getNewBoard():
- board = []
- for x in range(60):
- board.append([])
- for y in range(15):
- # use different characters for the ocean to make it more readable.
- if random.randint(0, 1) == 0:
- ocean = '~'
- else:
- ocean = '`'
- board[x].append(ocean)
- return board
- def getRandomSubs(numSubs):
- subs = []
- for i in range(numSubs):
- subs.append([random.randint(0, 59), random.randint(0, 14)])
- return subs
- def isValidMove(x, y):
- return x >= 0 and x <= 59 and y >= 0 and y <= 14
- def makeMove(board, subs, x, y):
- if not isValidMove(x, y):
- return False
- smallestDistance = 100
- for s in subs:
- sx = s[0]
- sy = s[1]
- if abs(sx - x) < abs(sy - y):
- distance = abs(sy - y)
- else:
- distance = abs(sx - x)
- if distance < smallestDistance:
- smallestDistance = distance
- if smallestDistance == 0:
- # xy is directly on a sub!
- subs.remove([x, y])
- return 'You have found and destroyed a sub!'
- else:
- if smallestDistance < 10:
- board[x][y] = str(smallestDistance)
- return 'Sub detected at a distance of %s from the sonar device.' % (smallestDistance)
- else:
- board[x][y] = 'O'
- return 'Sonar did not detect anything. All subs out of range.'
-
- def enterPlayerMove():
- print 'Where do you want to drop the next sonar device? (0-59 0-14) (or type quit)'
- while True:
- move = raw_input()
- if move.lower() == 'quit':
- print 'Thanks for playing!'
- sys.exit()
- move = move.split()
- if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isValidMove(int(move[0]), int(move[1])):
- return [int(move[0]), int(move[1])]
- 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 raw_input().lower().startswith('y')
- def showInstructions():
- print '''Instructions:
- You are the captain of a sub-hunting warship, USS Simon. Your current mission
- is to find the three subs that are lurking in the part of the ocean you are in
- and destroy 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 sub 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...'''
- raw_input()
- print '''For example, here is a sub (the s) located a distance of 2 away from the
- sonar device (the d):
- 22222
- s 2
- 2 d 2
- 2 2
- 22222
- The point where the device was dropped will be marked with a 2.
- The subs don't move around. They have shut off their engines and are "running
- dark" to hide from you. Sonar devices can detect subs up to a distance of 9.
- In that case, the point will be marked with O
- If a device is directly dropped on a sub, you have discovered the location of
- the sub, and it will be destroyed with depth charges. The sonar device will
- remain there.
- When you destroy a sub, all sonar devices will update to locate the next
- closest sub.
- Press enter to continue...'''
- raw_input()
- print
- print 'S O N A R !'
- print
- print 'Would you like to view the instructions? (yes/no)'
- if raw_input().lower().startswith('y'):
- showInstructions()
- while True:
- sonarDevices = 16
- theBoard = getNewBoard()
- theSubs = getRandomSubs(3)
- drawBoard(theBoard)
- previousMoves = []
- while sonarDevices > 0:
- if sonarDevices > 1: extraSsonar = 's'
- else: extraSsonar = ''
- if len(theSubs) > 1: extraSsub = 's'
- else: extraSsub = ''
- print 'You have %s sonar device%s left. %s sub%s remaining.' % (sonarDevices, extraSsonar, len(theSubs), extraSsub)
- x, y = enterPlayerMove()
- previousMoves.append([x, y])
- moveResult = makeMove(theBoard, theSubs, x, y)
- if moveResult == False:
- continue
- else:
- if moveResult == 'You have found and destroyed a sub!':
- # update all the sonar devices currently on the map.
- for x, y in previousMoves:
- makeMove(theBoard, theSubs, x, y)
- drawBoard(theBoard)
- print moveResult
- if len(theSubs) == 0:
- print 'You have destroyed all the subs! 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 the subs still out there! Game over.'
- print ' The remaining subs were here:'
- for s in theSubs:
- print ' %s, %s' % (s[0], s[1])
- if not playAgain():
- break
Things Covered In This Chapter: