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()
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Feb 2, 2017 at 14:46
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Almost all of my suggestions in the other question apply here, maybe have a look? (Especially how to check winning board) codereview.stackexchange.com/questions/154105/… \$\endgroup\$ Commented Feb 2, 2017 at 21:30

2 Answers 2

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

answered Feb 3, 2017 at 22:27
\$\endgroup\$
5
\$\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.

answered Feb 2, 2017 at 17:39
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.