# Tic Tac Toe code could probably be optimized more

I recently got some help from Stack Overflow on my Tic-Tac-Toe code for the win conditions, but I think it could be optimized a little more. Any tips?

moves = [["1", "2", "3"],
["1", "2", "3"],
["1", "2", "3"]]
acc = 0
def win(letter):
for i in range(3):
if ((moves[i][0] == moves[i][1] == moves[i][2] == letter) or
(moves[0][i] == moves[1][i] == moves[2][i] == letter)):
print("~~~ " + letter + " WON!!! CONGRATS!!!! ~~~")
quit()
if (set(moves[i][i] for i in range(3)) == set([letter])):
print("~~~ " + letter + " WON!!! CONGRATS!!!! ~~~")
quit()
if (set(moves[i][2-i] for i in range(3)) == set([letter])):
print("~~~ " + letter + " WON!!! CONGRATS!!!! ~~~")
quit()
if (acc == 5):
print("TIE YOU BOTH LOSE")
quit()
def playerInput():
global acc
player1 = input("Where do you want to place your X, player 1? (row number, space, number)")
moves[int(player1[0]) - 1][int(player1[2]) - 1] = "X"
acc += 1
win("X")
player2 = input("Where do you want to place your O, player 2? (row number, space, number)")
moves[int(player2[0]) - 1][int(player2[2]) - 1] = "O"
boardDraw()
def boardDraw():
print("1| "+moves[0][0]+" | "+moves[0][1]+" | "+moves[0][2]+" |")
print(" |---+---+---|")
print("2| "+moves[1][0]+" | "+moves[1][1]+" | "+moves[1][2]+" |")
print(" |---+---+---|")
print("3| "+moves[2][0]+" | "+moves[2][1]+" | "+moves[2][2]+" |")
win("X")
win("O")
playerInput()
print("OK SO....\nPlayer 1 is X\nPlayer 2 is O\nGOOOOO!!")
boardDraw()


Recently, "Tic-tac-toe" game is gaining popularity on CR.
It may even deserve a separate playlist like "Tic-tac-toe" Refactorings on various programming languages.
You may find how other guys on CR already succeeded with different implementations (some on pure Python, some - involving numpy functionality).

• moves list. It's better named as board (as a game field).
Instead of typing all board items it could be easily initiated with board = [['1','2','3'] for _ in range(3)]
• win function. It sounds like affirmative but it's actually testing for a win.
Thus a better name would be check_win

• set(moves[i][i] for i in range(3)) == set([letter]) condition. Instead of generating 2 set objects - use a convenient all function:

all(board[i][i] == letter for i in range(3))

• for loop (in check_win function) that checks for crossed row can be replaced with any call to serve a more wide consolidation.

• 2 statements:

print("~~~ " + letter + " WON!!! CONGRATS!!!! ~~~")
quit()


are duplicated across 3 different conditions. That's an explicit case for Consolidate conditional expression technique - we'll combine the conditions that share the same "body" with logical operator.
Eventually the optimized check_win function would look as:

def check_win(letter):
if any((board[i][0] == board[i][1] == board[i][2] == letter) or
(board[0][i] == board[1][i] == board[2][i] == letter) for i in range(3)) \
or all(board[i][i] == letter for i in range(3)) \
or all(board[i][2 - i] == letter for i in range(3)):
print(f"~~~ {letter} WON!!! CONGRATS!!!! ~~~")
quit()
if acc == 5:
print("TIE YOU BOTH LOSE")
quit()

• playerInput and boardDraw should be renamed to player_input and board_draw to follow naming conventions

• printing game's board in board_draw function looks really sad and painful.
Python provides a good string formatting features.
Just use them, as shown below:

def board_draw():
board_fmt = '''
1| {} | {} | {} |
|---+---+---|
2| {} | {} | {} |
|---+---+---|
3| {} | {} | {} |
'''
print(board_fmt.format(*[v for row in board for v in row]))

check_win("X")
check_win("O")
player_input()

• Thanks! Learned some things about python in the process :) Commented Nov 5, 2019 at 18:42
• @James, welcome. It's good to be helpful for someone ... Commented Nov 5, 2019 at 18:45