NOTE: This post explains the logic behind programming a game of tic tac toe. It includes a step-by-step guide on making a CUI version of tic tac toe and its implementation in Scala, which can be played directly in the console window. This post does not include a guide to make a GUI version in python, but includes a link at the end from where one may download a python file that allows you to play a GUI version of tic tac toe (using Tkinter).

Tic Tac Toe is one of the simplest and most versatile games that one can play. Melancholy grey afternoon? Tic tac toe. Stuck waiting for an appointment? Tic tac toe. Bored during class? Draw up a grid (at your own risk)! It also makes for a great ice-breaker. Not surprisingly, it is one of the simplest games to code. Coding a game of tic tac toe also helps you understand many basic and intermediate programming concepts such as multidimensional arrays, nesting loops, case matching, defining and calling functions etc. To take it a level further, you could also program an artificial intelligence algorithm that the user can play against! But this post will only cover the programming of a two player game. So, how do we go about doing this?

NOTE: The link to the post about coding an AI to play tic tac toe is given at the end.

The Logic Behind Tic Tac Toe

Every game of tic tac toe goes the same way: You draw a grid. You start and place an O in one of the nine boxes. Your opponent continues and places an X in one of the remaining boxes. Your turn again – you place an O. This continues until you and your opponent fill up all 9 boxes and/or one of you get 3 of your own symbols in a row – vertically, horizontally or diagonally. The first one to get 3 in a row stands the winner. If none of you get 3 in a row, and all boxes are filled, the game is tied. This is the overlying logic we need to keep in mind when we try to program a game of tic tac toe in any language. Below is a flowchart that depicts the series of events in a game of tic tac toe:

A flowchart depicting the sequence of events in a game of tic tac toe. The player’s turn switches after every successive move.

Step-by-Step Procedure of Making a CUI Version of Tic Tac Toe

The first thing we need to do is create an object named, for example, tictactoe. We can then initialise global variables accessible by all functions under the object. We will need to have 7 basic functions – a main function which runs all the other functions in a while loop, a function to print out instructions at the beginning, a function that prints the updated grid after every move, a function that reads input to let a player move, a function to check if anyone wins, a function to check if the game is tied, and finally, a function to change whose turn it is. Additionally, we can define a function to end the game and congratulate the winner if the game is not tied. Explanations of each of the functions are given below:

NOTE: The names of the functions need not be as given and can be modified as per your own will.

main()

This is the main function which runs all the other functions. It runs the print_instructions() function in the beginning. It then runs the remaining functions, either indirectly or directly, in a while loop that runs until a boolean value(gameOver = false) signifying whether the game is over or not is changed (to true).

print_instructions()

This function prints out the instructions to play the game. It includes a grid representing coordinates to be inputted by the users to place their symbols.

print_grid(grid: Array(Array[String]) )

This function is called to print out the updated grid after each successive move. It takes the global variable grid as its parameter. It prints out the grid using a nested for loop.

player_move(turn: String, grid: Array(Array[String]))

It takes 2 parameters: the whoseTurn global variable to represent which player’s turn it is, and the grid variable as mentioned in the print_grid() function. This function reads the coordinate entered by the player and changes the coordinate value in the grid variable to the value of the turn parameter, i.e., X or O. It then calls the functions that check for a winner, check for a tie and the function that switches the turn. It makes sure that the coordinate to be updated in the grid was previously empty, otherwise it calls itself again.

switch_turn()

It switches the players’ turn using a simple if…else conditional statement.

check_for_win()

It checks if either X or O have won by matching all win cases in an if….else if statement. There are 8 win cases each for X and O (3 vertical, 3 horizontal and 2 diagonal), giving a total of 16 cases to be checked. If one of the win cases returns a match, it ends the game and displays the winner, or calls a function there_is_a_winner() to do the same.

check_if_tie()

It gets called only if neither player has won. It checks if all the coordinates in the grid are filled, and if so, ends the game. If not, it does nothing and hence the while loop runs again.

A Scala Implementation of the Above Procedure

object tictactoe {

  //assignment of global variables
  var whoseTurn = "O"
  var winner = " "
  var gameOver = false
  var grid: Array[Array[String]] = Array(Array(" ", " ", " "),
                                         Array(" ", " ", " "),
                                         Array(" ", " ", " ") )

  //the main function that runs
  def main(args: Array[String]): Unit ={
    print_instructions()

    //loop that continues the game while the game is not over
    while(!gameOver){
      print_grid(grid)
      player_move(whoseTurn, grid)
    }
  }
  
  //This function prints out instructions at the beginning
  def print_instructions(): Unit ={
    println("INSTRUCTIONS:")
    println("The grid is of the form")
    println("|-----|-----|-----|")
    for (i <- 0 to 2; j <- 0 to 2){
      if (j == 0){
        print("|")
      }
      print(s"($i,$j)")
      if (j == 2){
        println("|")
        println("|-----|-----|-----|")
      }
      else{
        print("|")
      }
    }
    println("To place your symbol, you must enter the coordinate where you wish to place your symbol.")
    println("Input must be given in the form x,y with no space or brackets")
    println("For example, if you wish to place your symbol in the middle, you must enter '1,1'")
    println("Example: ")
    println("Where would you like to place your O? 1,1")
    println("In case of illegal placement, the system will prompt you to try again.")
    println("That's all. Have fun!")
    println()
    println()
    println("GAME BEGINS")
  }

  //this function prints the grid after every move
  def print_grid(grid: Array[Array[String]]): Unit ={
    println("|---|---|---|")
    for (i <- 0 to 2; j <- 0 to 2){
      if (j == 0){
        print("| ")
      }
      print(grid(i)(j))
      if (j == 2){
        println(" | ")
        println("|---|---|---|")
      }
      else{
        print(" | ")
      }
    }
  }

  //this function makes a player's move
  def player_move(turn: String, grid: Array[Array[String]]): Unit ={
    var coordinate_input = scala.io.StdIn.readLine(s"Where would you like to place your $turn? ")
    var coordinate = coordinate_input.split(",").map(_.toInt)
    if (grid(coordinate(0))(coordinate(1)) == " "){
      grid(coordinate(0))(coordinate(1)) = turn
      switch_turn()
      check_for_win()
      check_if_tie()
    }
    else{
      println("Oops! Illegal move. Try again!")
      player_move(turn, grid)
    }

  }

  //this function switches the players' turns
  def switch_turn(): Unit ={
    if (whoseTurn == "O"){whoseTurn = "X"}
    else {whoseTurn = "O"}
  }

  //this function checks if any player has won
  def check_for_win(): Unit ={
    if (grid(0)(0) == "O" && grid(0)(1) == "O" && grid(0)(2) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(1)(0) == "O" && grid(1)(1) == "O" && grid(1)(2) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(2)(0) == "O" && grid(2)(1) == "O" && grid(2)(2) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(0) == "O" && grid(1)(0) == "O" && grid(2)(0) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(1) == "O" && grid(1)(1) == "O" && grid(2)(1) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(2) == "O" && grid(1)(2) == "O" && grid(2)(2) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(0) == "O" && grid(1)(1) == "O" && grid(2)(2) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(2) == "O" && grid(1)(1) == "O" && grid(2)(0) == "O"){winner = "O"; there_is_a_winner()}
    else if (grid(0)(0) == "X" && grid(0)(1) == "X" && grid(0)(2) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(1)(0) == "X" && grid(1)(1) == "X" && grid(1)(2) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(2)(0) == "X" && grid(2)(1) == "X" && grid(2)(2) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(0)(0) == "X" && grid(1)(0) == "X" && grid(2)(0) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(0)(1) == "X" && grid(1)(1) == "X" && grid(2)(1) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(0)(2) == "X" && grid(1)(2) == "X" && grid(2)(2) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(0)(0) == "X" && grid(1)(1) == "X" && grid(2)(2) == "X"){winner = "X"; there_is_a_winner()}
    else if (grid(0)(2) == "X" && grid(1)(1) == "X" && grid(2)(0) == "X"){winner = "X"; there_is_a_winner()}
  }

  //this function checks if there is a tie ,and if so, ends the game
  def check_if_tie(): Unit ={
    if (grid(0)(0) != " " && grid(0)(1) != " " && grid(0)(2) != " " && grid(1)(0) != " " && grid(1)(1) != " "
        && grid(1)(2) != " " && grid(2)(0) != " " && grid(2)(1) != " " && grid(2)(2) != " " && !gameOver){
      gameOver = true
      print_grid(grid)
      println("GAME OVER")
      println("Well played! It is a tie!")
    }
  }

  //this function congratulates the winner and ends the game
  def there_is_a_winner(): Unit ={
    print_grid(grid)
    println("GAME OVER")
    println(s"$winner is the winner!")
    gameOver = true
  }

}

The github link for the above program is:

https://github.com/adityapentyala/Scala/blob/master/tictactoe.scala

For instructions on installing Scala, visit https://www.scala-lang.org/download/


The github link for the python GUI version (with explanation in comments) is:

https://github.com/adityapentyala/Python/blob/master/tic%20tac%20toe_complete%20(1).py


To code a single player vs AI game of tic tac toe, visit the following link:

Visits: 253

One Reply to “Tic Tac Toe”

Leave a Reply

Your email address will not be published. Required fields are marked *