Lesson 23 of 35Python
Python · Lesson 23 · 45 minutes
Project: tic-tac-toe
What you'll learn
- Represent a board as a list of lists
- Check rows, columns and diagonals
- Split a game into clear functions
A board made of lists
A tic-tac-toe board has 3 × 3 squares. In Python you build something like that as a list of lists – a list with three rows, each row a list with three squares:
board = [
["X", "O", "X"],
[" ", "X", "O"],
["O", " ", "X"],
]
print(board[0][2]) # row 0, column 2
print(board[1]) # the whole middle rowThe first index picks the row, the second the column.
Showing the board nicely
def draw(board):
for number, row in enumerate(board):
print(" " + " | ".join(row))
if number < 2:
print("---+---+---")
draw([["X", "O", "X"], [" ", "X", "O"], ["O", " ", "X"]])When has someone won?
There are eight winning lines: three rows, three columns and two diagonals. A good trick: collect all eight lines in a list and then check them all with the same loop – instead of writing eight separate if checks.
a, b, c = "X", "X", "X"
print(a == b == c) # Python can chain comparisons!
print("O" == "O" == "X")The whole game
With your winner function it becomes a game for two people:
def winner(board):
lines = [board[i] for i in range(3)] + [[board[0][i], board[1][i], board[2][i]] for i in range(3)]
lines += [[board[0][0], board[1][1], board[2][2]], [board[0][2], board[1][1], board[2][0]]]
for line in lines:
if line[0] != " " and line[0] == line[1] == line[2]:
return line[0]
return None
board = [[" "] * 3 for _ in range(3)]
player = "X"
for move in range(9):
for row in board:
print(" " + " | ".join(row))
# Keep asking until a number from 1 to 9 comes
while True:
entry = input(f"{player} – square 1 to 9: ")
try:
number = int(entry) - 1
except ValueError:
print("Please type a number.")
continue
if 0 <= number <= 8:
break
print("Only squares 1 to 9!")
board[number // 3][number % 3] = player
if winner(board):
print(player, "wins!")
break
player = "O" if player == "X" else "X"
else:
print("It's a draw!")Keep building: check whether the square is already taken. Or build a computer opponent that picks a free square with
random.choice.
Your task
Your turn
Write the function winner(board). The board is a list of three rows with three entries each ("X", "O" or " "). The function returns "X" or "O" if someone has three in a row, column or diagonal – otherwise None.
def winner(board):
pass
board = [
["X", "O", " "],
["X", "O", " "],
["X", " ", "O"],
]
print(winner(board))- Something to think about
Column i consists of
board[0][i],board[1][i]andboard[2][i]. - Which command helps?
The diagonals:
board[0][0],board[1][1],board[2][2]andboard[0][2],board[1][1],board[2][0].Three empty squares
" "aren't a win – check that the first square of the line isn't" ". - Gap code – fill in the ___
def winner(board): lines = ___ for i in ___: ___ ___ ___ ___ for line in ___: if ___: return ___ return ___ board = [ ["X", "O", " "], ["X", "O", " "], ["X", " ", "O"], ] print(winner(board))
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
def winner(board):
lines = []
for i in range(3):
lines.append(board[i]) # row
lines.append([board[0][i], board[1][i], board[2][i]]) # column
lines.append([board[0][0], board[1][1], board[2][2]]) # diagonal
lines.append([board[0][2], board[1][1], board[2][0]]) # other diagonal
for line in lines:
if line[0] != " " and line[0] == line[1] == line[2]:
return line[0]
return None
board = [
["X", "O", " "],
["X", "O", " "],
["X", " ", "O"],
]
print(winner(board))