井字棋(Tic-Tac-Toe)的棋盘只有 3×3,规则简单到一句话:谁先连成一线谁赢。但把它写成程序,你要处理输入校验、轮流切换、胜负判定、平局检测——这些正是所有棋类游戏(乃至更复杂的博弈 AI)的公共骨架。认真做完,你对"状态机"的理解会深一层。

玩法介绍

棋盘 9 个格子按 0~8 编号。两名玩家(X 和 O)轮流输入格子编号落子,不能落在已有棋子的位置;任意一方在横、竖、斜方向连成 3 个即获胜;9 格下满仍无人连成一线则平局。本教程做"人机对战":玩家执 X,电脑(随机落子)执 O。

第 1 步:棋盘表示与打印

用长度为 9 的列表 board 表示棋盘,空位是空格字符串,落子后存 "X" 或 "O"。打印时按 3 个一行输出,加上分隔线,看起来就像真正的棋盘。

board = [" "] * 9

def show():
    for row in range(3):
        line = board[row * 3 : row * 3 + 3]
        print(" | ".join(line))
        if row < 2:
            print("---------")

show()

第 2 步:玩家落子与合法性校验

玩家输入 0~8 的编号,需要校验两条规则:编号在范围内、该格为空。不满足就提示并重新输入。

while True:
    text = input("轮到 X,请选择格子(0-8): ")
    if not text.isdigit():
        print("请输入数字!")
        continue
    pos = int(text)
    if pos < 0 or pos > 8:
        print("编号要在 0 到 8 之间!")
        continue
    if board[pos] != " ":
        print("这个格子已经有棋子了!")
        continue
    board[pos] = "X"
    break

第 3 步:胜负判定

3×3 一共只有 8 种赢法:3 行 + 3 列 + 2 条对角线。把所有赢法写成常量列表,逐个检查是否被同一方占满。这种"穷举所有可能"的思路,在状态空间小时是最简单可靠的。

LINES = [
    [0, 1, 2], [3, 4, 5], [6, 7, 8],   # 三行
    [0, 3, 6], [1, 4, 7], [2, 5, 8],   # 三列
    [0, 4, 8], [2, 4, 6],              # 两条对角线
]

def winner():
    for a, b, c in LINES:
        if board[a] == board[b] == board[c] != " ":
            return board[a]   # 返回 'X' 或 'O'
    return None

board[a] == board[b] == board[c] != " " 是 Python 特有的链式比较:三个值相等且不等于空格。连写比 and 拼接更简洁,也不容易漏括号。

第 4 步:电脑随机落子

先收集所有空格,用 random.choice 随机选一个。这个 AI 很"笨",但足以让游戏完整跑起来;想让电脑变聪明,请看文末的改进方向。

import random

empty = [i for i in range(9) if board[i] == " "]
move = random.choice(empty)
board[move] = "O"
print(f"电脑落在了 {move} 号格子")

第 5 步:主循环与平局判断

用 while 循环轮流走棋,每步后检查胜负;所有格子下满且无人获胜就是平局。完整版代码:

import random

board = [" "] * 9
LINES = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]

def show():
    for row in range(3):
        print(" | ".join(board[row*3:row*3+3]))
        if row < 2:
            print("---------")

def winner():
    for a, b, c in LINES:
        if board[a] == board[b] == board[c] != " ":
            return board[a]
    return None

def player_move():
    while True:
        text = input("轮到 X,请选择格子(0-8): ")
        if not text.isdigit():
            print("请输入数字!")
            continue
        pos = int(text)
        if pos < 0 or pos > 8 or board[pos] != " ":
            print("无效位置,重新选!")
            continue
        board[pos] = "X"
        return

while True:
    show()
    player_move()
    if winner():
        print(f"\n{winner()} 获胜!")
        break
    if " " not in board:
        print("\n平局!")
        break
    empty = [i for i in range(9) if board[i] == " "]
    board[random.choice(empty)] = "O"

show()

第 6 步:完整代码与运行

第 5 步的代码就是完整版,保存为 tictactoe.py,运行 python3 tictactoe.py 与电脑对战。想和朋友一起玩,把电脑落子的两行换成"让 O 玩家输入"即可变成双人模式——这个改动也顺便帮你理解了"程序结构服务于游戏规则"。

💡 改进方向:①让电脑优先堵住玩家的必胜线(检查对手差一格连成三线的情况),难度立刻上一个台阶;②用 minimax 回溯算法让电脑永不输;③支持"再来一局"并记录总比分;④把棋盘扩展成 4×4 甚至 5×5,练习用循环动态生成赢法列表。