Merl's Blog

Tic Tac Toe 2

Let’s Talk about the finished product. An unbeatable tic tac toe game! I finished!

It’s definitely not perfect, however it is an incredibly more improved game than the first time I created it. First of all it is much cleaner. My first time, I must say the functions were decently named. However, the white space was not consistent and also my equations were not spaced properly x+= 2 compared to x += 2. I had fewer and larger functions, most of my functions did multiple things which made it tough to test, run, and debug.

Now my functions are smaller, properly named, and have a consistent clean look to them. Initially when I wanted to share my code, I would literally copy and paste, now I can send a link to Github, showing my progress.

Nice changes after rigorously learning about Clean Code and TDD for a month.

Here is some of my previous code when it came to running the AI, compared to my new code.

#first time
while True:
  if letterXO == "o":
    move()
  if game_over():
    sys.exit()


  elif letterXO == "x":
    moveO()
    if game_over():
      sys.exit()
  def move():
    time.sleep(1)
    print("\n"*2)
    computer()
    global counter
    counter +=1
    grid()
    if game_over():
      sys.exit()
    get_int()
    counter +=1
    print()
    grid()


    print("\n"*2+"Okay, it's my turn")


  time.sleep(1)
  exceptions()
  end_move()
  if game_over():
    sys.exit()


def moveO():
  global counter


  get_int()
  counter +=1
  print()
  grid()


  if game_over():
    sys.exit()


  time.sleep(1)
  exceptions()
  end_move()


  if game_over():
    sys.exit()
    time.sleep(1)


  computerO()
  counter +=1
  print("\n"*2+"Okay, it's my turn")
  print("\n"*2)


  if game_over():
    sys.exit()
  grid()
  print("\n"*2)


#new code


def play_computer(game_board, number_of_moves, X_turn):
  while True:
    print(gb.display_Game(game_board))


    if X_turn:
      ai_move = mm.minimax(game_board, number_of_moves, X_turn)[1]
      game_board = ui.update_board(ai_move, game_board, X_turn)
    Else:
      game_board = ui.parse_input(game_board, X_turn)
    if cgo.is_game_over(game_board):
    congrats_message(game_board)
    break
    X_turn = not X_turn

Way cleaner in general, and let me also compare my previous computer logic with the Minimax algorithm.

#hundreds of lines like
def computer():
list[0] = "x"


#branch 1
if list[1] == "o" and counter >=2 and list[6] != "o" and list[8] != "o" and list[4] != "o":
list[4] = "x"


#branch2
elif list[2] == "o" and counter>=2:
list[6] = "x"


if list[3] == "o" and counter >=4:
list[8] ="x"
#branch 4
elif list[4] == "o" and counter >=2:
list[8] = "x"
#branch4.2
if list[2] == "o" and counter >=4:
list[6] ="x"
#branch4.6
elif list[6] == "o" and counter >=4:
list[2] ="x"
#branch4.1
elif list[1] == "o" and counter >=4:
list[7] = "x"


if list[6] == "o" and counter >=5 :
list[2] = "x"


if list[5] =="o" and counter >=5:
list[3] ="x"



#Compare that too
 def minimax(gamestate, depth ,isX):
depth += 1

  if cg.is_game_over(gamestate):
    value = Value(gamestate)
    return value / depth, None


  if isX :
    best_value = -100000000
    for action in cg.actions(gamestate):
      new_gamestate = copy.deepcopy(gamestate)
      new_gamestate = ui.update_board(action, new_gamestate, isX)
      value = minimax(new_gamestate, depth, not isX)[0]

      if value > best_value:
        best_value = value
        best_action = action
        return best_value, best_action

  else:
    best_value = 100000000
    for action in cg.actions(gamestate):
      new_gamestate = copy.deepcopy(gamestate)
      new_gamestate = ui.update_board(action, new_gamestate, isX)
      value = minimax(new_gamestate, depth, not isX)[0]

      if value < best_value:
        best_value = value
        best_action = action
        return best_value, best_action

I know I have a long way to go, but for now I am enjoying the victory of this second iteration.

Best, Merl