5
\$\begingroup\$

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()
\$\endgroup\$
3
\$\begingroup\$

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).

But let's return to your current variation.

  • 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()
    
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks! Learned some things about python in the process :) \$\endgroup\$ – James Nov 5 at 18:42
  • 1
    \$\begingroup\$ @James, welcome. It's good to be helpful for someone ... \$\endgroup\$ – RomanPerekhrest Nov 5 at 18:45

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.