Wednesday, February 24, 2010

Sonar

I have finished up creating a game that functions almost the same as the game in this chapter. The game I created is slightly different in how the code works in a few specific areas, but altogether the example code in this chapter, and mine, should be fairly similar. Here is my source code:

#Sonar

import random
import sys

def drawBoard(board):
    hline = '    '
    for i in range(1, 6):
        hline += (' ' * 9) + str(i)
  
    print(hline)
    print('   ' + ('0123456789' * 6))
    print('')
  
    for i in range(15):
        if i < 10:
            es = ' '
        else:
            es = ''
        print('%s%s %s %s' % (es, i, getRow(board, i), i))
          
    print('')
    print('   ' + ('0123456789' * 6))
    print(hline)

def getRow(board, row):
    boardc = ''
  
    for i in range(60):
        boardc += board[i][row]
    return boardc

def getNewBoard():
    board = []

    for x in range(60):
        board.append([])
        for y in range(15):
            if random.randint(0, 1) == 1:
                board[x].append('~')
            else:
                board[x].append('`')

    return board

def placeChests(chestAmount):
    chests = []
  
    for i in range(chestAmount):
        chests.append([random.randint(0, 59), random.randint(0, 14)])
    return chests

def isValidMove(x, y):
    if (x >= 0 and x <= 59 and y >= 0 and y <= 14):
        return True
    else:
        return False

def makeMove(board, chests, x, y):
    if not isValidMove(x, y):
        return False
  
    smalld = 100
    for cx, cy in chests:
        if (abs(cx - x) > abs(cy - y)):
            distance = abs(cx - x)
        else:
            distance = abs(cy - y)
          
        if distance < smalld:
            smalld = distance

    if smalld == 0:
        chests.remove([x, y])
        return 'You have found a treasure chest!'
    else:
        if smalld < 10:
            board[x][y] = str(smalld)
            return 'Treasure has been detected at a distance of %s' % (smalld)
        else:
            board[x][y] = '0'
            return 'Treasure is nowhere to be found within range.'

def enterPlayerMove():
    print('Enter in two integers (0-59, 0-14), otherwise type quit to exit the game.')

    while True:
        move = raw_input()
        if move.lower() == 'quit':
            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 in two integers (0-59, 1-15), otherwise type quit to exit the game.')

def playAgain():
    print('Do you want to play again? (yes or no)')
    return input().lower().startswith('y')

print('S O N A R !')

while True:
    sonarDevices = 16
    theBoard = getNewBoard()
    previousMoves = []
    playerMovec = []
    drawBoard(theBoard)
    print('Where do you want to place your sonar device?')
    secretChests = placeChests(3)

    while sonarDevices > 0:
      
        if sonarDevices > 1: extraSsonar = 's'
        else: extraSsonar = ''
        if len(secretChests) > 1: extraSchest = 's'
        else: extraSchest = ''
        print('You have %s sonar device%s left. %s treasure chest%s remaining.' % (sonarDevices, extraSsonar, len(secretChests), extraSchest))

        x, y = enterPlayerMove()
        playerMovec.append([x, y])
        result = makeMove(theBoard, secretChests, x, y)

        if sonarDevices < 16:
            if playerMovec[len(previousMoves)-1] == previousMoves[len(previousMoves)-1]:
                sonarDevices -= 1
            else:
                result = False
                drawBoard(theBoard)
                print('You have already placed a sonar device here!')
 
        previousMoves.append([x, y])

        if sonarDevices == 16:
            sonarDevices -= 1
        if result == False:
            continue
        else:
            if result == 'You have found a treasure chest!':
                for x, y in previousMoves:
                    makeMove(theBoard, secretChests, x, y)
            drawBoard(theBoard)
            print(result)
        if len(secretChests) == 0:
                print('You have found all the sunken treasure chests! Congratulations and good game!')
                break

    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:')
        for x, y in theChests:
            print('    %s, %s' % (x, y))

    if not playAgain():
        sys.exit()



A large difference between my code, and the example code, is the fact that I have support for allowing the player to suffer no negative penalty (a loss of one of the sonar beacons) for trying to place a sonar over an area that was placed during the previous turn. This honestly, took me forever to figure out how to do. I finally decided on creating two copies of all previous turns, and then use these two copies to see if the last values in the two lists equal one another, before the value in the second list had been appended. This way, I compared the value of entered coordinates to the value of previous coordinates, and didn't subtract from the overall sonar amount when this happened.


The math is simple, and the whole Cartesian Plane didn't really teach me anything new. Although, if you don't understand how the math in my makeMove() function doesn't work, you might need to read over this chapter again.


I plan to go other the thirteenth chapter, here, for my next post. This seems rather interesting, as it is about cryptology.


Let me know if you see something I could improve upon in this code. Hopefully my lack of commenting the code isn't detrimental, if it is let me know and I'll add in comments.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.