52 — Game: tic-tac-toe
Guide 51 built a board; guide 26 showed how ask, while True, and break make a game loop. Tic-tac-toe joins them: two players take turns picking a row and a column, and after every move a function checks for three in a row.
Steps
- The whole game in one file,
tictactoe.nme. The board andshow_boardcome from 51;check_winnerscans rows, columns, and both diagonals and returns the winning mark, orNonewhile no line is complete;ask numberreads a row and a column as integers,continuere-asks a taken square, andmoves == 9declares a draw:
run it →# tictactoe.nme — a two-player tic-tac-toe game. # Run: nme r tictactoe # The board is a list of rows (guide 51). A turn places a mark, # and check_winner looks for three in a row, column, or diagonal. board = [["-", "-", "-"], ["-", "-", "-"], ["-", "-", "-"]] def show_board(board): for row in board: show row def check_winner(board): # Rows: three equal marks side by side. for row in board: if row[0] == row[1] and row[1] == row[2] and row[0] != "-": return row[0] # Columns: three equal marks straight down. for col in range(3): if board[0][col] == board[1][col] and board[1][col] == board[2][col] and board[0][col] != "-": return board[0][col] # Diagonals: corner to corner. if board[0][0] == board[1][1] and board[1][1] == board[2][2] and board[0][0] != "-": return board[0][0] if board[0][2] == board[1][1] and board[1][1] == board[2][0] and board[0][2] != "-": return board[0][2] return None player = "X" moves = 0 show "Tic-tac-toe! Rows and columns are 0, 1, or 2." show "Line up three marks to win. X goes first." while True: show_board(board) ask number row, f"Player {player}, row (0-2): " ask number col, f"Player {player}, column (0-2): " if board[row][col] != "-": show "That square is taken. Pick another." continue board[row][col] = player moves = moves + 1 winner = check_winner(board) if winner is not None: show f"After {moves} moves:" show_board(board) show f"Player {winner} wins!" break if moves == 9: show f"After {moves} moves:" show_board(board) show "It is a draw." break if player == "X": player = "O" else: player = "X" - Run a whole game through a pipe — row then column for five moves. X fills a row and wins on the last move:
printf '0\n0\n1\n0\n0\n1\n2\n0\n0\n2\n' | nme r tictactoeTic-tac-toe! Rows and columns are 0, 1, or 2. Line up three marks to win. X goes first. ['-', '-', '-'] ['-', '-', '-'] ['-', '-', '-'] Player X, row (0-2): Player X, column (0-2): ['X', '-', '-'] ['-', '-', '-'] ['-', '-', '-'] Player O, row (0-2): Player O, column (0-2): ['X', '-', '-'] ['O', '-', '-'] ['-', '-', '-'] Player X, row (0-2): Player X, column (0-2): ['X', 'X', '-'] ['O', '-', '-'] ['-', '-', '-'] Player O, row (0-2): Player O, column (0-2): ['X', 'X', '-'] ['O', '-', '-'] ['O', '-', '-'] Player X, row (0-2): Player X, column (0-2): After 5 moves: ['X', 'X', 'X'] ['O', '-', '-'] ['O', '-', '-'] Player X wins!The last board shows the winning row:
Xacross the top. The game ends withbreak, so the winning move is the last move.
Try it yourself
Play a game O wins and one that ends in a draw, then make check_winner also name the winning line, such as "row 0".
What you learned
ask numberreads a row and column as integers;board[row][col]writes a mark.- A function checks rows, columns, and diagonals for three equal marks.
continuerejects a taken square;breakends the game.moves == 9with no winner declares a draw.