2
\$\begingroup\$

I am new to programming and wrote this code for a Tic-Tac-Toe game.

The game works as desired, however, I feel the code can be condensed a bit especially within the functions, Map_1st_Player_Input_to_Player_Board, Map_2nd_Player_Input_to_Player_Board, and Check_For_Win where I rely heavily on if, elif statements.

Can I get some feedback on optimizing this code?

#Function to print out the playing board
def Print_Player_Board():
    print '\n'.join([' '.join(row) for row in Player_Board])

#Function to print out player ones position
def Map_1st_Player_Input_to_Player_Board():
    while True:
        try:

            Entry = int(raw_input("Player One Enter Your Playing Position: ")) 

            if  Entry == 1 and Player_Board[2][1] not in ('X', 'O'):
                Player_Board[2][1] = 'X'
                break

            elif  Entry == 2 and Player_Board[2][3] not in ('X', 'O'):   
                Player_Board[2][3] = 'X'
                break

            elif  Entry == 3 and Player_Board[2][5] not in ('X', 'O'):
                Player_Board[2][5] = 'X'
                break

            elif  Entry == 4 and Player_Board[1][1] not in ('X', 'O'):
                Player_Board[1][1] = 'X'
                break

            elif  Entry == 5 and Player_Board[1][3] not in ('X', 'O'):
                Player_Board[1][3] = 'X'
                break

            elif  Entry == 6 and Player_Board[1][5] not in ('X', 'O'):
                Player_Board[1][5] = 'X'
                break

            elif  Entry == 7 and Player_Board[0][1] not in ('X', 'O'):
                Player_Board[0][1] = 'X'
                break

            elif  Entry == 8 and Player_Board[0][3] not in ('X', 'O'):
                Player_Board[0][3] = 'X'
                break

            elif  Entry == 9 and Player_Board[0][5] not in ('X', 'O'):
                Player_Board[0][5] = 'X'
                break

            elif Entry > 9:
                print 'An Incorrect Board Position Was Entered. Player Please Try Again'

            else:
                print "Current Position Is Filled. Please Try Again."

        except ValueError:
            print 'Sorry, Invalid Entry Made, Please Try Again.'

#Function to print out player twos position
def Map_2nd_Player_Input_to_Player_Board():
    while True:
        try:

            Entry = int(raw_input("Player Two Enter Your Playing Position: ")) 

            if  Entry == 1 and Player_Board[2][1] not in ('X', 'O'):
                Player_Board[2][1] = 'O'
                break

            elif  Entry == 2 and Player_Board[2][3] not in ('X', 'O'):   
                Player_Board[2][3] = 'O'
                break

            elif  Entry == 3 and Player_Board[2][5] not in ('X', 'O'):
                Player_Board[2][5] = 'O'
                break

            elif  Entry == 4 and Player_Board[1][1] not in ('X', 'O'):
                Player_Board[1][1] = 'O'
                break

            elif  Entry == 5 and Player_Board[1][3] not in ('X', 'O'):
                Player_Board[1][3] = 'O'
                break

            elif  Entry == 6 and Player_Board[1][5] not in ('X', 'O'):
                Player_Board[1][5] = 'O'
                break

            elif  Entry == 7 and Player_Board[0][1] not in ('X', 'O'):
                Player_Board[0][1] = 'O'
                break

            elif  Entry == 8 and Player_Board[0][3] not in ('X', 'O'):
                Player_Board[0][3] = 'O'
                break

            elif  Entry == 9 and Player_Board[0][5] not in ('X', 'O'):
                Player_Board[0][5] = 'O'
                break

            elif Entry > 9:
                print 'An Incorrect Board Position Was Entered. 2nd Player Please Try Again'

            else:
                print "Current Position Is Filled. Please Try Again."

        except ValueError:
            print 'Sorry, Invalid Entry Made, Try Again Please.'


#Function to check for possible win. 
def Check_For_Win():

    if  Player_Board[2][1] == 'X' and Player_Board[2][3] == 'X' and Player_Board[2][5] == 'X':
        return 1
    elif  Player_Board[2][1] == 'O' and Player_Board[2][3] == 'O' and Player_Board[2][5] == 'O':
        return 2
    elif  Player_Board[1][1] == 'X' and Player_Board[1][3] == 'X' and Player_Board[1][5] == 'X':
        return 1
    elif  Player_Board[1][1] == 'O' and Player_Board[1][3] == 'O' and Player_Board[1][5] == 'O':
        return 2
    elif  Player_Board[0][1] =='X' and Player_Board[0][3] == 'X' and Player_Board[0][5] == 'X':
        return 1
    elif  Player_Board[0][1] == 'O' and Player_Board[0][3] == 'O' and Player_Board[0][5] == 'O':
        return 2
    elif  Player_Board[2][1] == 'X' and Player_Board[1][1] == 'X' and Player_Board[0][1] == 'X':
        return 1
    elif  Player_Board[2][1] == 'O' and Player_Board[1][1] == 'O' and Player_Board[0][1] == 'O':
        return 2
    elif  Player_Board[2][3] == 'X' and Player_Board[1][3] == 'X' and Player_Board[0][3] == 'X':
        return 1
    elif  Player_Board[2][3] == 'O' and Player_Board[1][3] == 'O' and Player_Board[0][3] == 'O':
        return 2
    elif  Player_Board[2][5] == 'X' and Player_Board[1][5] == 'X' and Player_Board[0][5] == 'X':
        return 1
    elif  Player_Board[2][5] == 'O' and Player_Board[1][5] == 'O' and Player_Board[0][5] == 'O':
        return 2
    elif  Player_Board[2][1] == 'X' and Player_Board[1][3] == 'X' and Player_Board[0][5] == 'X':
        return 1
    elif  Player_Board[2][1] == 'O' and Player_Board[1][3] == 'O' and Player_Board[0][5] == 'O':
        return 2
    elif  Player_Board[0][1] == 'X' and Player_Board[1][3] == 'X' and Player_Board[2][5] == 'X':
        return 1
    elif  Player_Board[0][1] == 'O' and Player_Board[1][3] == 'O' and Player_Board[2][5] == 'O':
        return 2
    else:
        pass

#Function For Game Replay
def Replay():
    while True:
            Response = raw_input("Would You Like To Play Again? (Y/N): ")
            if Response in ('y', 'Y', 'Yes', 'yes'):
                print("\n\n\n")
                Game_Start()
                break

            elif Response in ('n', 'N', 'No', 'no'):
                print 'Have A Great Day - GoodBye'
                break

            else:
                print 'Invalid Response Provided. Please Try Again'

#Game Play Function
def Game_Start():
    global Player_Board
    global Counter
    print "This is a Tic-Tac-Toe Game To Be Played Between Two Players."
    print "This Game is Played with a Keypad Using the Numbers 1 Through 9"
    print "Which Represent Board Locations as Follows;"
    print '           | 7 | 8 | 9 |'
    print '           | 4 | 5 | 6 |'
    print '           | 1 | 2 | 3 |'
    print "Player 1 Begins By Placing an 'X' Marker On the Board." 
    print "Player 2 Then Places an 'O' Marker On the Board."
    print "The Game Will End At Any Time Either Player Succeeds In Landing Three Markers In Series"
    print "This Can Be Done Horizontally, Vertically, Or Diagonally."
    print "If At Any Time a Player Selects An Already Filled Position An Error Message Will Appear On The Screen"
    print "The Player Will Then Take Another Turn And the Game Will Resume Until Either Player Wins "
    print '\n'
    Player_Board = [['|',' ','|',' ','|',' ','|'],['|',' ','|',' ','|',' ','|'], ['|',' ','|',' ','|',' ','|']]

    print             "Game Start"
    Print_Player_Board()
    Counter = 0 # Counter used to keep count of play moves. Use for Tie Game Logic

    while Check_For_Win() not in (1, 2) and Counter < 9:

        Map_1st_Player_Input_to_Player_Board()
        Counter +=1
        if Check_For_Win() == 1:
            Print_Player_Board()
            print '!!!!Player One Has Won!!!!'
            break   
        else:
            Print_Player_Board()
            pass
        if Counter < 9:
            Map_2nd_Player_Input_to_Player_Board()
            Counter +=1
            if Check_For_Win() == 2:
                Print_Player_Board()
                print '!!!!Player Two Has Won!!!!'
                break
            else:
                Print_Player_Board()
                pass

    if Counter > 8 and Check_For_Win() not in (1,2):
        print '!!!TIE GAME!!!'
        Replay()

    if Check_For_Win() in (1,2):
        Replay()
\$\endgroup\$

migrated from stackoverflow.com Feb 2 '17 at 16:23

This question came from our site for professional and enthusiast programmers.

2
\$\begingroup\$

The Check_For_Win function can be written a lot more compact:

# Function to check for possible win.
# Returns the symbol of the player who has Won
# Returns False if nobody has won
def Check_For_Win(board):
    # check for win in a row
    for row in board:
        if row[1] == row[3] == row[5] and row[1] != ' ':
            return row[1]

    # Check for win in a column
    for i in [1, 3, 5]:
        if board[0][i] == board[1][i] == board[2][i] and board[0][i] != ' ':
            return board[0][i]

    # Check for diagonal win:
    if board[0][0] == board[1][1] == board[2][2] or board[0][2] == board[1][1] == board[2][0]:
        return board[1][1] if board[1][1] != ' ' else False

You can also rewrite the input methods for getting inputs like @ImperialJustinian suggested. I have rewritten your Game_Start method:

# Game Play Function
def Game_Start():
    print "This is a Tic-Tac-Toe Game To Be Played Between Two Players."
    print "This Game is Played with a Keypad Using the Numbers 1 Through 9"
    print "Which Represent Board Locations as Follows;"
    print '           | 7 | 8 | 9 |'
    print '           | 4 | 5 | 6 |'
    print '           | 1 | 2 | 3 |'
    print "Player 1 Begins By Placing an 'X' Marker On the Board."
    print "Player 2 Then Places an 'O' Marker On the Board."
    print "The Game Will End At Any Time Either Player Succeeds In Landing Three Markers In Series"
    print "This Can Be Done Horizontally, Vertically, Or Diagonally."
    print "If At Any Time a Player Selects An Already Filled Position An Error Message Will Appear  On The Screen"
    print "The Player Will Then Take Another Turn And the Game Will Resume Until Either Player Wins     "
    print '\n'
    print "Game Start"

    Player_Board = [['|',' ','|',' ','|',' ','|'],['|',' ','|',' ','|',' ','|'], ['|',' ','|','','|',' ','|']]
    Print_Player_Board(Player_Board) # Print_Player_Board now takes the board as an parameter to avoid these globals

    Counter = 0 # Counter used to keep count of play moves. Use for Tie Game Logic
    current_player = "X"
    winner = False

    while not winner and Counter < 9:
        # the new input method should take the board and the current player and return the new board
        Player_Board = get_input(board, current_player)
        Print_Player_Board(Player_Board)
        winner = Check_For_Win(Player_Board)
        current_player = "X" if current_player == "0" else "0"
        Counter += 1

    if not winner:
        print '!!!TIE GAME!!!'
    else:
        print "!!!!Player '{}' Has Won!!!!".format(winner)
    Replay()

To make this work you have to change Print_Player_Board to:

# Function to print out the playing board
def Print_Player_Board(board):
    print '\n'.join([' '.join(row) for row in board])

and you have write the function get_input(board, player) yourself

\$\endgroup\$
6
\$\begingroup\$

First, I would like to say that I am not familiar with Python itself. However, I am familiar with basic programming principles that are the same between games.

Second, you have far too many if statements. There should only be one if statement when entering a position, and that is to check if the position you have chosen is valid; ie, there is an X or O in there. (or better, if I understand the python initialiser right, is not ' '). Instead of what you have, you should be converting the number the user types in to the coordinate in the array. Ie:

x = Entry / 3;
y = Entry % 3;

I checked, and the modulo is the same in python as other languages like C#. Modulo retrieves the remainder from a divide operation. You will likely need to change the order of which number corresponds to which location in the visible grid.

In addition, the code for checking whether or not the position is clear is near identical for both players, and could be moved into a separate function (returning a bool that the players choice was correct) that takes in the players character to write, which would have the advantage of ensuring that code for both players is identical.

I know there has to be a better way to check the winning condition than the if statements, but I'm not sure what it is off the top of my head. Like the above, the check itself can be moved into its own function that checks based on character, rather than repeating each if for both players. This function can then be called for each player.

There will be other optimisations based on python itself, which I am not aware of. But those are the basics that should help with efficiency in any language.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.