Thursday, February 25, 2010

Caeser Cipher

Now I have finished up the encryption chapter of this book. The entire idea behind the encryption is to shift each character of a string over by a certain amount. Whenever a character of a string exited the parameters of a-z or A-Z, you just add or subtract 26, thus "wrapping" your encryption around and back, so that letters are only encrypted into letters. This took me about 30 minutes total to create. Here is my source code:

import sys

def getMode():
    print('Do you want to encrypt decrypt, or brute force a message?')
    mode = raw_input().lower()
    if mode in 'encrypt decrypt e d brute b'.split():
        return mode
    else:
        print('You need to enter in one of the following: e, d, b')

def getMessage():
    print('Enter your message.')
    return raw_input()

def getKey():
    key = 0

    while True:
        print('Enter in a number for your key, 1-25.')
        key = int(raw_input())
        if (key >= 1 and key <= 25):
            return key

def getTranslatedMessage(key, mode, message):
    if mode[0] == 'd':
        key = -key

    translated = ''

    for symbol in message:
        if symbol.isalpha():
            num = ord(symbol)
            num += key

            if symbol.isupper():
                if num > ord('Z'):
                    num -= 26
                elif num < ord('A'):
                    num += 26
            elif symbol.islower():
                if num > ord('z'):
                    num -= 26
                elif num < ord('a'):
                    num += 26

            translated += chr(num)
        else:
            translated += symbol

    return translated

def playAgain():
    print('Do you wish to continue? (yes or no)')
    return raw_input().lower().startswith('y')

Again = True

while True:
    mode = getMode()
    message = getMessage()
    if mode != 'b':
        Key = getKey()
    print('Your translated text is:')
    if mode != 'b':
        print(getTranslatedMessage(Key, mode, message))
    else:
        for key in range(1, 26 + 1):
            print(key, getTranslatedMessage(key, 'decrypt', message))
    if not playAgain():
        sys.exit



The next chapter of this book is here. This chapter goes over the Reversi game. I won't be constructing a program from this chapter as it doesn't really introduce any new concepts. The Ai for the reversi game just runs through each possible move and chooses the one that results in the most points. I will be skipping over chapter 14, and chapter 15, and heading straight into chapter 16. Chapter 16 is going over graphics and animation; I'll be starting to use the Pygame engine.

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.

Tuesday, February 23, 2010

Bagels

The name of the game I have created for this post, is the game Bagels. Bagels is a game where the user guesses a three digit number, and the computer responds with "Fermi" for every digit that is in the right place that you guessed, and "Pico" for every digit that you guessed which is in the wrong place, but is still a digit in the secret number.

The concepts that this game goes over are hardcoding and nested loops, the chapter is this one: http://inventwithpython.com/chapter10.html.

A nested loop is simply a loop within a loop. This is useful for when you want to iterate something x times, for every time y appears, or something similar.

Hardcoding is a coding practice where the coder codes the program so that changing of simple variables requires changing lots of code. This program was programmed without hardcoding, where a couple constants (variables that do not change while the program is running, which are represented with caps, although, are actually just normal variables in Python) can be changed to change how the game is played.

import random

def getSecretNumbers(numDigits):

    numbers = list(range(10))
    random.shuffle(numbers)

    secretNum = ''
    for i in range(numDigits):
        secretNum += str(numbers[i])

    return secretNum

def getClues(guess, secretNum):

    if guess == secretNum:
        return 'You have guessed the correct number!'

    clue = []

    for i in range(len(guess)):
        if guess[i] == secretNum[i]:
            clue.append('Fermi')
        elif guess[i] in secretNum:
            clue.append('Pico')

    if len(clue) == 0:
        return 'Bagels'

    clue.sort()

    return ' '.join(clue)

def isOnlyDigits(num):

    if num == '':
        return False

    for i in num:
        if i not in '1 2 3 4 5 6 7 8 9'.split():
            return False

    return True

def playAgain():

    print('Do you want to play again? Yes or no.')
    return raw_input().lower().startswith('y')

NUMDIGITS = 3
MAXGUESS = 10

print('I am thinking of a %s-digit number. Try to guess what it is.' % (NUMDIGITS))
print('Here are some clues:')
print('When I say:    That means:')
print('  Pico         One digit is correct but in the wrong position.')
print('  Fermi        One digit is correct and in the right position.')
print('  Bagels       No digit is correct.')

while True:
    secretNum = getSecretNumbers(NUMDIGITS)
    print('I have thought up a number. You have %s guesses to get it.' % (MAXGUESS))

    numGuesses = 1
    while numGuesses <= MAXGUESS:
        guess = ''
        while len(guess) != NUMDIGITS or not isOnlyDigits(guess):
            print('Guess #%s: ' % (numGuesses))
            guess = raw_input()

        clue = getClues(guess, secretNum)
        print(clue)
        numGuesses += 1

        if guess == secretNum:
            break
        if numGuesses > MAXGUESS:
            print('You ran out of guesses. The answer was %s.' % (secretNum))

    if not playAgain():
        break


My code should be pretty much identicle to the code in the example program, as there aren't really any easier ways to code this program; this is a really rather cut and draw program to create.

This part of the program confused me for a moment:

def getSecretNumbers(numDigits):

    numbers = list(range(10))
    random.shuffle(numbers)


These lines create a list of numbers and then shuffle them. When I first saw these lines, the first one confused me: numbers = list(range(10)). I wasn't sure why the auther was changing the range() to list() inside of the range. Although, in the book it explained that if I wanted to store a list of integers, they needed to be converted from an iterator (value of range) into a list. This made sense, although the author didn't go into detail about exactly what the value of a range was. I assume it's just an amount of iterations to perform, which isn't what I would want if I wanted a list to store variables in.

I plan to run through chapter eleven of this book for my next post. This should be a relatively easy chapter, as it just goes through the basics of a Cartesian coordinate system.

Monday, February 22, 2010

Finishing Tic Tac Toe

Aha! So I coded up my own version of Tic Tac Toe. I did take a look at my old program that I posted up before (here) in a couple spots where I couldn't pinpoint my own bugs, but other than that I wrote this thing without a reference. This, pretty much just solidified my understanding and familiarity of Python syntax even further. Not much else to explain. Here is my source code:


import random

def drawBoard():
    print(board[1] + '|' + board[2] + '|' + board[3])
    print('-----')
    print(board[4] + '|' + board[5] + '|' + board[6])
    print('-----')
    print(board[7] + '|' + board[8] + '|' + board[9])

def pickYourLetter():

    letter = ''

    while (letter != 'X' and letter != 'O'):
        print('Would you like to X or O?')
        letter = raw_input().upper()

        if (letter != 'X' and letter != 'O'):
              print('Uhm, I said X or O.')

    if letter == 'X':
        return ['X', 'O']
    else:
        return ['O', 'X']

def whoGoesFirst():

    if random.randint(0, 1) == 1:
        return 'player'
    else:
        return 'computer'

def getPlayerMove(theBoard):

    move = ' '

    while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(theBoard, int(move)):
        print('It is your turn to move.')
        move = raw_input()

    return int(move)

def isSpaceFree(theBoard, move):

    return board[move] == ' '

def makeMove(board, letter, move):

    board[move] = letter

def isWinner(b, l):
    return ((b[1] == l and b[2] == l and b[3] == l) or
    (b[4] == l and b[5] == l and b[6] == l) or
    (b[7] == l and b[8] == l and b[9] == l) or
    (b[1] == l and b[4] == l and b[7] == l) or
    (b[2] == l and b[5] == l and b[8] == l) or
    (b[3] == l and b[6] == l and b[9] == l) or
    (b[1] == l and b[5] == l and b[9] == l) or
    (b[3] == l and b[5] == l and b[7] == l))

def isTie(board):

    for i in range(1, 10):
        if isSpaceFree(board, i):
            return False
  
    return True


def getBoardCopy(theBoard):

    dupeBoard = []

    for i in board:
        dupeBoard.append(i)

    return dupeBoard

def getComputerMove(theBoard, letter):

    if computerLetter == 'X':
        playerLetter = 'O'
    else:
        playerLetter = 'X'

    for i in range(1, 10):
        copy = getBoardCopy(theBoard)
        if isSpaceFree(copy, i):
            makeMove(copy, computerLetter, i)
            if isWinner(copy, computerLetter):
                return i

    for i in range(1, 10):
        copy = getBoardCopy(theBoard)
        if isSpaceFree(copy, i):
            makeMove(copy, playerLetter, i)
            if isWinner(copy, playerLetter):
                return i

    move = chooseRandomMove(theBoard, [1, 3, 7, 9])
    if move != None:
        return move

    if isSpaceFree(board, 5):
        return 5

    return chooseRandomMove(board, [2, 4, 6, 8])

def chooseRandomMove(theBoard, moveList):
  
    moves = []
    for i in moveList:
        if isSpaceFree(theBoard, i):
            moves.append(i)

    if len(moves) != 0:
        return random.choice(moves)
    else:
        return None

def playAgain():

    print('Do you want to play again? (yes or no)')
    return raw_input().lower().startswith('y')

      


while True:

    board = [' '] * 10
    print('This is Tic Tac Toe.')

    playerLetter, computerLetter = pickYourLetter()

    gameIsPlaying = True
    currentTurn = whoGoesFirst()

    if currentTurn == 'player':
        print('You will move first, as decided at random.')
    else:
        print('The computer will move first, as decided at random.')

    while gameIsPlaying == True:

        if currentTurn == 'player':
            drawBoard()

            move = getPlayerMove(board)
            makeMove(board, playerLetter, move)

            if isWinner(board, playerLetter):
                drawBoard()
                print('You have won the game!')
                gameIsPlaying = False
            else:
                if isTie(board):
                    drawBoard()
                    print('Game is a tie!!')
                    gameIsPlaying = False
                else:
                    currentTurn = 'computer'

        else:
            move = getComputerMove(board, computerLetter)
            makeMove(board, computerLetter, move)

            if isWinner(board, computerLetter):
                drawBoard()
                print('You have lost the game!')
                gameIsPlaying = False
            else:
                if isTie(board):
                    drawBoard()
                    print('Game is a tie!')
                    gameIsPlaying = False
                else:
                    currentTurn = 'player'    
              
    if not playAgain():
        break

And that is my code. Here is the exe file in case you are interested: http://www.mediafire.com/?oodckz5oxmy


Anyways, I plan to go over this chapter tomorrow and follow through with constructing the program from scratch without referring to the example code http://inventwithpython.com/chapter10.html.


I had a few troubles throughout the program, and the most annoying one was in the definitions of winning. I had constantly placed a 1 in place of a lower case L, and this resulted in bad things. I also had a couple typos here and there, things like typing = instead of ==, and vise versa.


One thing in particular that I found interesting while creating this program, was the "None" value. Here is a quote from the book "Calls to functions that do not return anything (that is, they exit by reaching the end of the function and not from a return statement) will evaluate to None." This was useful in that whenever I wanted the Ai in my simulation to choose a random location to place his letter, say, one of the four corners; if all four of these corners were taken, I could return the value of None instead of one of the values for one of the four corners.


I also learned from this chapter some interesting aspects of list referencing. Take a look at this function:

def makeMove(board, letter, move):
    board[move] = letter

  
It would seem like this function wouldn't do anything due to the change of the board list being of the private scope by default, since it is happening within the function itself. This is because the word "board" isn't actually the list board, it is just a reference to that list passed onto the function as an argument. This means that when we have the line board[move] = letter we aren't modifying the data stored in a variable, but we are modifying the data stored in the list, which is referenced by the word "board". Here is a quote from the book that explains this: "When you assign a list to a variable with the = sign, you are actually assigning a reference to the list. A reference is a value that points to some bit of data, and a list reference is a value that points to a list."

Starting up Python!

Well, sadly, I have no more time for C++, and I probably won't for a couple months. Things are getting really busy. Although, I have good news; I started a programming club at my highschool that meets once a week, where I teach them all how to code in Python. For the time being, my next posts will be about my learnings of Python.

I chose Python after doing a little bit of research; Python is a language that was created to allow coders to create code quickly and efficiently. Readability of Python was also a concern while developing the Python environment. As such, Python is great for readability and for quickly coding programs. Although Python is great at what it was intended to be used for, Python isn't made to create highly optimized code for intense programming (things like 3D rendering). Although, you can create visual programs that render in 3D, Python code can only be optimized so much.

I spent this weekend reading some of the chapters from this excellent book on programming games in Python, with the Pygame engine. Here is the book I am currently reading: http://inventwithpython.com/chapters/. I am currently on nine.

I am working with Python 2.6, as this has the most up-to-date third party support from things like Pygame and Py2Exe.


I recommend that anyone reading this check out the Pygame.org website, and sift around through the tutorials there, as well as check out the source code for some of the more simple programs that are on display there.

Over the course of chapter nine, I created a game of TicTacToe. The player can choose to play as X's or O's, and I have a functioning Ai.


At this point in time, I do have a working program, although, I created it while using the example code in the book as reference. As an exercise, my next post will be about me trying to create the entire program without reference code whatsoever.


Here is my source code for my program:

import random

def drawBoard(board):
    #This function draws the board whenever it is called. The board is represented as an array.
  
    print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
    print('   |   |')

def getPlayerLetter():
    #This function allows the human to choose whether they play as an X or O.

    letter = ''

    while not (letter == 'X' or letter == 'O'):
        print('What would you like to play as? X or O?')
        letter = raw_input().upper()

        if letter != 'X' and letter != 'O':
            print('You can only pick X or O to play as.')

    if letter == 'X':
        return ['X', 'O']
    else:
        return ['O', 'X']

def whoGoesFirst():
    #This function randomly picks which player goes first.

    if random.randint(0, 1) == 1:
        return 'player'
    else:
        return 'computer'

def getPlayerMove(board):
    #Captures the player's input on their desired move for their turn.

    move = ' '

    while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
        print('What is your next move?')
        move = raw_input()
    return int(move)

def isSpaceFree(board, move):
    #Return true if the move is available on the board.
  
    return board[move] == ' '

def makeMove(board, letter, move):
    board[move] = letter

def isWinner(bo, le):
    # Given a board and a player's letter, this function returns True if that player has won.
    # We use bo instead of board and le instead of letter so we don't have to type as much.
  
    return ((b[7] == l and b[8] == l and b[9] == l) or # across the top
    (b[4] == l and b[5] == l and b[6] == l) or # across the middle
    (b[1] == l and b[2] == l and b[3] == l) or # across the bottom
    (b[7] == l and b[4] == l and b[1] == l) or # down the left side
    (b[8] == l and b[5] == l and b[2] == l) or # down the middle
    (b[9] == l and b[6] == l and b[3] == l) or # down the right side
    (b[7] == l and b[5] == l and b[3] == l) or # diagonal
    (b[9] == l and b[5] == l and b[1] == l)) # diagonal

def isBoardFull(board):
    #Checks to see if the board is full or not.

    for i in range(1, 10):
        if isSpaceFree(board, i):
            return False

    return True

def getComputerMove(board, computerLetter):
    #Determines how to react depending on which letter (X or O) the computer player has.

    if computerLetter == 'X':
        playerLetter = 'O'
    else:
        playerLetter = 'X'

    # Check if the computer can win in the next move.
    for i in range(1, 10):
        copy = getBoardCopy(board)
        if isSpaceFree(copy, i):
            makeMove(copy, computerLetter, i)
            if isWinner(copy, computerLetter):
                return i

    # Check if the player could win on his next move, and block them.
    for i in range(1, 10):
        copy = getBoardCopy(board)
        if isSpaceFree(copy, i):
            makeMove(copy, playerLetter, i)
            if isWinner(copy, playerLetter):
                return i
          
    # Try to take one of the corners, if they are free.
    move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
    if move != None:
        return move

    # Try to take the center, if it is free.
    if isSpaceFree(board, 5):
        return 5

    # Move on one of the sides.
    return chooseRandomMoveFromList(board, [2, 4, 6, 8])

def chooseRandomMoveFromList(board, movesList):
    # Returns a valid move from the passed list on the passed board.
    # Returns None if there is no valid move.
  
    possibleMoves = []
    for i in movesList:
        if isSpaceFree(board, i):
            possibleMoves.append(i)

    if len(possibleMoves) != 0:
        return random.choice(possibleMoves)
    else:
        return None

def getBoardCopy(board):
    #This returns a copy of the actual board, used to simulate or test things.

    dupeBoard = []

    for i in board:
        dupeBoard.append(i)

    return dupeBoard

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')
      

while True:
    #Resets the board.
    theBoard = [' '] * 10
    playerLetter, computerLetter = getPlayerLetter()
    currentTurn = whoGoesFirst()
    print('The ' + currentTurn + ' player will go first.')

    gameIsPlaying = True

    while gameIsPlaying:
        if currentTurn == 'player':
            #Player's turn.

            drawBoard(theBoard)
            move = getPlayerMove(theBoard)
            makeMove(theBoard, playerLetter, move)

            if isWinner(theBoard, playerLetter):
                drawBoard(theBoard)
                print('You have won the game!')
                gameIsPlaying = False
            else:
                if isBoardFull(theBoard):
                    drawBoard(theBoard)
                    print('The game is a tie!')
                    break
                else:
                    currentTurn = 'computer'

        else:
            #Computer player's turn.
            move = getComputerMove(theBoard, computerLetter)
            makeMove(theBoard, computerLetter, move)

            if isWinner(theBoard, computerLetter):
                drawBoard(theBoard)
                print('The computer has beaten you! You lose.')
                gameIsPlaying = False
            else:
                if isBoardFull(theBoard):
                    drawBoard(theBoard)
                    print('The game is a tie!')
                    break
                else:
                    currentTurn = 'player'

    if not playAgain():
        break


As you might notice, this code is pretty darn similar to my reference code. As I mentioned, I will as my next project re-write this entire program without any reference.

I would say that the most interesting part of creating this program, was the Ai. The Ai really only cycles through a copy of the currently existing board, and searches for any winning moves from either player. If it finds one, it takes it. If not, it moves to one of the currently open corners, randomly. If all the corners are taken, the Ai moves into the middle space. If that is taken, it moves onto one of the four last spaces, at random. This algorithm is pretty darn simple, but it is effective at playing Tic Tac Toe.

Overall, I would say I gained a better understanding of Python syntax more than anything while writing this program.

I tried to include a source file, and my exe, although I'm currently having troubles uploading. I'll try to remember to modify this post with some links, in case anyone wanted to download the exe or the source. Edit: No, I will not be supplying the exe//source code this time ;P