1. #1
    Will Watts's Avatar
    Join Date
    Mar 2012
    Location
    %tmp%
    Posts
    5,189
    • specs System Specs
      • Manufacturer:
        Alienware M15x
      • Model Number:
        M15x
      • CPU:
        i5 520 M @ 2.40GHz
      • Memory:
        8GB
      • Graphics:
        ATI Radeon HD 5800
      • Hard Drives:
        720GB 7200 rpm
      • Operating System:
        Windows 8 + Ubuntu

    [Python] - Naughts and Crosses/Tic-Tac-Toe

    A new program... a lot of it was already written - I had to edit functions to get it working as intended etc. I'm having some problems with the logic, I can't wrap my head around some things. I'm not sure how many of you here know python, but hopefully you can help me with the logic anyway which is screwing with my mind .

    The full code for the game is below. It plays as intended, with reasonable AI. I know only one combination of moves too beat it at the moment, but I didn't play it that much after I was satisfied it all worked. It's not in a perfect state, so if you just press enter rather than typing a move it will break and bring up errors. The bit I want some help with is the pseudo-AI

    Code:
    # Tic-Tac-Toe
    # Plays the game of tic-tac-toe against a human opponent
       
    # global constants
    X = "X"
    O = "O"
    EMPTY = " "
    TIE = "TIE"
    NUM_SQUARES = 9
    
    
    def display_instruct():
        """Display game instructions."""  
        print(
        """
        Welcome to the greatest intellectual challenge of all time: Tic-Tac-Toe.  
        This will be a showdown between your human brain and my silicon processor.  
    
        You will make your move known by entering a number, 0 - 8.  The number 
        will correspond to the board position as illustrated:
        
                        0 | 1 | 2
                        ---------
                        3 | 4 | 5
                        ---------
                        6 | 7 | 8
    
        Prepare yourself, human.  The ultimate battle is about to begin. \n
        """
        )
    
    
    def ask_yes_no(question):
        """Ask a yes or no question."""
        response = None
        while response not in ("y", "n"):
            response = input(question).lower()
        return response
    
    
    def ask_number(question, low, high):
        """Ask for a number within a range."""
        response = None
        while response not in range(low, high):
            response = int(input(question))
        return response
    
    
    def pieces():
        """Determine if player or computer goes first."""
        go_first = ask_yes_no("Do you require the first move? (y/n): ")
        if go_first == "y":
            print("\nThen take the first move.  You will need it.")
            human = X
            computer = O
        else:
            print("\nYour bravery will be your undoing... I will go first.")
            computer = X
            human = O
        return computer, human
    
    
    def new_board():
        """Create new game board."""
        board = []
        for square in range(NUM_SQUARES):
            board.append(EMPTY)
        return board
    
    
    def display_board(board):
        """Display game board on screen."""
        print("\n\t", board[0], "|", board[1], "|", board[2])
        print("\t", "---------")
        print("\t", board[3], "|", board[4], "|", board[5])
        print("\t", "---------")
        print("\t", board[6], "|", board[7], "|", board[8], "\n")
    
    
    def legal_moves(board):
        """Create list of legal moves."""
        moves = []
        for square in range(NUM_SQUARES):
            if board[square] == EMPTY:
                moves.append(square)
        return moves
    
    
    def winner(board):
        """Determine the game winner."""
        WAYS_TO_WIN = ((0, 1, 2),
                       (3, 4, 5),
                       (6, 7, 8),
                       (0, 3, 6),
                       (1, 4, 7),
                       (2, 5, 8),
                       (0, 4, 8),
                       (2, 4, 6))
        
        for row in WAYS_TO_WIN:
            if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
                winner = board[row[0]]
                return winner
    
        if EMPTY not in board:
            return TIE
    
        return None
    
    
    def human_move(board, human):
        """Get human move."""  
        legal = legal_moves(board)
        move = None
        while move not in legal:
            move = ask_number("Where will you move? (0 - 8):", 0, NUM_SQUARES)
            if move not in legal:
                print("\nThat square is already occupied, foolish human.  Choose another.\n")
        print("Fine...")
        return move
    
    
    def computer_move(board, computer, human):
        """Make computer move."""
        # make a copy to work with since function will be changing list
        board = board[:]
        # the best positions to have, in order
        BEST_MOVES = (4, 0, 2, 6, 8, 1, 3, 5, 7)
    
        print("I shall take square number", end=" ")
        
        # if computer can win, take that move
        for move in legal_moves(board):
            board[move] = computer
            if winner(board) == computer:
                print(move)
                return move
            # done checking this move, undo it
            board[move] = EMPTY
        
        # if human can win, block that move
        for move in legal_moves(board):
            board[move] = human
            if winner(board) == human:
                print(move)
                return move
            # done checkin this move, undo it
            board[move] = EMPTY
    
        # two turns check
        playable_moves = legal_moves(board)
        for move in playable_moves:
            board[move] = computer
            for move in playable_moves:
                board[move] = human
                if winner(board) == human:
                    playable_moves.remove(move)
            board[move] = EMPTY
    
                
            #end check
            board[move] = EMPTY
    
        # since no one can win on next move, pick best open square
        for move in BEST_MOVES:
            if move in legal_moves(board) and move in playable_moves:
                print(move)
                return move
            elif move in legal_moves(board):
                print(move)
                return move
                
                                    
    
    
    def next_turn(turn):
        """Switch turns."""
        if turn == X:
            return O
        else:
            return X
    
        
    def congrat_winner(the_winner, computer, human):
        """Congratulate the winner."""
        if the_winner != TIE:
            print(the_winner, "won!\n")
        else:
            print("It's a tie!\n")
    
        if the_winner == computer:
            print("As I predicted, human, I am triumphant once more.  \n" \
                  "Proof that computers are superior to humans in all regards.")
    
        elif the_winner == human:
            print("No, no!  It cannot be!  Somehow you tricked me, human. \n" \
                  "But never again!  I, the computer, so swear it!")
    
        elif the_winner == TIE:
            print("You were most lucky, human, and somehow managed to tie me.  \n" \
                  "Celebrate today... for this is the best you will ever achieve.")
    
    
    def main():
        display_instruct()
        computer, human = pieces()
        turn = X
        board = new_board()
        display_board(board)
    
        while not winner(board):
            if turn == human:
                move = human_move(board, human)
                board[move] = human
            else:
                move = computer_move(board, computer, human)
                board[move] = computer
            display_board(board)
            turn = next_turn(turn)
    
        the_winner = winner(board)
        congrat_winner(the_winner, computer, human)
    
    
    # start the program
    main()
    input("\n\nPress the enter key to quit.")
    I added in this section to improve the computer's moves:

    Code:
    # two turns check
        playable_moves = legal_moves(board)
        for move in playable_moves:
            board[move] = computer
            for move in playable_moves:
                board[move] = human
                if winner(board) == human:
                    playable_moves.remove(move)
            board[move] = EMPTY
    It seems to improve the game, but I can't wrap my head around how. When I wrote the code, I was intending it to check the next turn to see if anyone can win, and then check the second turn - ideally then checking the third and fourth to make the computer unbeatable. I realised after, that checking move 2 for human victory was already being done basically by the code before this section.

    Questions: Why does this code improve the AI? It's harder to beat with it, than without it, but I'm not really sure what's going on - I've made it better... somehow...but I don't think that's a good way to leave it.

    How can I improve the AI further? I want it to check the first possible move, then second, then third, then fourth.
    Has Sysnative Forums helped you? Please consider donating to help support the forum.



    • Ad Bot

      advertising
      Beep.

        
       

  2. #2
    niemiro's Avatar
    Join Date
    Mar 2012
    Location
    District 12
    Posts
    7,865

    Re: [Python] - Naughts and Crosses/Tic-Tac-Toe

    I haven't actually read the code yet, however, until then, I would guess that it is because playable_moves.remove(move) is removing moves which will make the computer lose in two or fewer turns.

    However, without this code, the computer was taking a lucky dip with moves, and that move might make the computer lose in any number of turns.

    A very nice game!

  3. #3
    Will Watts's Avatar
    Join Date
    Mar 2012
    Location
    %tmp%
    Posts
    5,189
    • specs System Specs
      • Manufacturer:
        Alienware M15x
      • Model Number:
        M15x
      • CPU:
        i5 520 M @ 2.40GHz
      • Memory:
        8GB
      • Graphics:
        ATI Radeon HD 5800
      • Hard Drives:
        720GB 7200 rpm
      • Operating System:
        Windows 8 + Ubuntu

    Re: [Python] - Naughts and Crosses/Tic-Tac-Toe

    Thanks, the logic is just screwing with me a bit.

    The computer already checks if it can win the next move first, then if the player - I'm confused as to how my code improved on the first check as on turn 2 the human doesn't have any more possibilities. I tried re-doing the code a bit, but it doesn't work like this:

    Code:
    playable_moves = legal_moves(board)
        for move in playable_moves:
            board[move] = computer
            playable_second = legal_moves(board)
            for move2 in playable_second:
                board[move2] = human
                if winner(board) == human:
                    playable_moves.remove(move)
            board[move] = EMPTY
    It gives me an error on this line: playable_moves.remove(move). I was trying to fix what seemed to me to be skewed code that I wrote, but I might just not be used to the logic.
    Has Sysnative Forums helped you? Please consider donating to help support the forum.


Similar Threads

  1. HiLo Game - Python
    By AceInfinity in forum Programming
    Replies: 2
    Last Post: 02-06-2013, 01:24 AM
  2. Python - Will's Amazing Menu Program
    By Will Watts in forum Programming
    Replies: 10
    Last Post: 07-04-2012, 02:22 AM
  3. CYPHER - Python
    By Will Watts in forum Programming
    Replies: 1
    Last Post: 06-13-2012, 02:14 PM
  4. Python - I'm stuck.
    By Will Watts in forum Programming
    Replies: 5
    Last Post: 05-23-2012, 03:39 AM

Log in

Log in