Skip to content

2D Lists Tic-Tac-Toe

Played perfectly, tic-tac-toe always ends in a tie — which makes it a terrible tournament game and a great programming project. Before your program can play a single move, it has to remember the whole board: every X, every O, every empty space. That memory is a 2D list.


Overview

You'll write a complete two-player tic-tac-toe game: a 2D list holds the board, and three functions — display, move, and check — handle drawing it, taking turns, and deciding when the game is over.

Builds on: 2D List Practice — you'll reuse reading and updating a 2D list by row and column.

You've got it when…

  • display prints the board with lines between the spaces.
  • move accepts only legal, empty spaces and keeps prompting until it gets one.
  • check correctly reports a win, a tie, or a game still in progress.
  • Two players can alternate turns until the game ends.

Collaboration & AI

Work: On your own. Playtest each other's games; write your own code.

AI — AIAS Level 1, No AI: The check function is the workout this lab exists for, so do the lifting yourself. What the levels mean.


2D List Review

You practiced all of this in 2D List Practice; here is the short version for reference.

A 2D list is a list that contains other lists as its elements. You can think of it as a table with rows and columns — just like a spreadsheet, grid, or matrix.

numbers = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

Here:

  • There are 3 rows (each inner list).
  • Each row has 3 columns.
  • numbers[0] → [1, 2, 3] (the first row)
  • numbers[1][2] → 6 (row 1, column 2 — remember counting starts at 0!)

You can use nested loops (a loop inside another loop) to access every element:

for row in numbers:
    for value in row:
        print(value)
    print()

And you can modify individual elements the same way you read them:

numbers[0][1] = 42

State

In programming, the term state refers to the current condition or contents of a program's data at a specific moment in time.

We will use a 2D list to represent a tic-tac-toe board. The state is the arrangement of X's, O's, and empty spaces on that board — in other words, what the board looks like right now.

board = [
    ["X", "O", "X"],
    ["O", "X", "O"],
    ["O", "X", "X"]
]

We will use the space character to represent a blank tic-tac-toe space. Each tic-tac-toe space may contain only one of these characters: " " (the space character), "X", or "O".


Functions

We'll create three functions to handle the tasks of running the game.

  1. Create a function named display which accepts the board as an input and prints it to the screen.

    1. Use characters like |, -, and + to draw the tic-tac-toe board lines between the values.
    2. Test it by passing the board above to your function.
    3. This function does not return anything.
    4. An example of one possible approach to displaying the board. This is the output printed to the screen:

       X | O |
      ---+---+---
       O | X | O
      ---+---+---
       X |   | O
      
  2. Create a function named move which accepts the board as the first argument and a character representing the current player (either "X" or "O") as a second argument.

    1. Get input from the player for which row they want and which column they want. Only accept legal inputs (0, 1, or 2), and continue prompting the user until a legal input is entered.
    2. Check if the player's chosen space is empty. If not, continue to prompt the player for a valid space.
    3. Update the chosen space with the player character that was passed in to your function, which should be "X" or "O".
    4. This function does not return anything.
  3. Create a function named check which accepts the board as an argument. This function checks the game board to see if there is a winner or a tie.

    1. Return None if the game is not over.
    2. Return "win" if there is a winner.
    3. Return "tie" if all the spaces are taken without a winner.

Hint: breaking down check

This function is all about accessing 2D lists. Break it down into smaller problems:

  • A win occurs when there are three of the same character in sequence, and that character is not a space.
    • Does any row have three of the same character, any one of which is not a space?
    • Does any column have three of the same character, any one of which is not a space?
    • Does either diagonal have three of the same character, any one of which is not a space?
    • If any of the above are true, return "win".
  • If a win has not occurred and there are any blank spaces left, the game is not over yet. Return None.
  • Otherwise, a win has not occurred and there are no spaces left to play. Return "tie".

Main Program

We will begin structuring our main programs into their own function named main, like this:

def main():
    # Main program code goes here.

main()  # this calls the main function and starts the program

Your main program should do these things:

  1. Create a variable for the board as shown above. All tic-tac-toe spaces should initially be the space character " ".
  2. Create a variable named player to keep track of the current player (X or O). In tic-tac-toe, X goes first, so set this variable to "X" initially.
  3. Create an infinite loop which does the following:

    1. Call your display function to show the board.
    2. Call your move function, passing it the board and player.
    3. Call your check function to see if the game is over.
      1. If it returns "win" or "tie", print that result and break out of the infinite loop. The game is over.
      2. Otherwise, switch player (if it is "X", set it to "O", or vice-versa) for the next loop.

Turn It In

  • Your Python (.py) file containing the tic-tac-toe game.

How It's Graded

This lab is worth up to 4 points. One score covers everything you turn in.

Score What it looks like
4 — Excellent A complete, playable game: display draws the board with lines, move refuses illegal and occupied spaces until it gets a real one, check catches all eight win lines and the tie, and the main loop alternates players, announces the result, and stops. You playtested wins in a row, a column, and both diagonals — check earned its keep.
3 — Above Average The game plays to a finish, with a slip — one win line check misses, or a tie declared a move early.
2 — Average display and move work but check is incomplete — the game never ends, or only row wins are caught.
1 — Below Average The board prints but there's no playable turn loop, or the program doesn't run.
0 — Failing Nothing submitted, or no evidence of the game.