Monday, February 22, 2010

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

No comments:

Post a Comment

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