
后来我发现,编程入门最忌讳”只学不练”,尤其是学不到能带来成就感的项目。今天分享一个我亲测有效的笨办法:从井字棋游戏开始学Python。这个小游戏看起来简单,却能帮你一次性掌握变量、列表、循环、条件判断这些核心基础,最重要的是——1小时就能做出能玩的成品,比啃教程有意思多了!
为什么井字棋是Python入门的理想项目?
你可能会问:市面上那么多编程项目,为啥偏偏选井字棋?这可不是随便拍脑袋决定的,我去年带一个完全零基础的朋友学Python时,就踩过”选项目”的坑。一开始让他跟着教程做计算器,做到一半他就没兴趣了:”这和手机计算器有啥区别?”后来换成井字棋,他居然自己加了个”计分功能”,还兴奋地发朋友圈炫耀——这就是”成就感驱动学习”的魔力。
井字棋之所以适合入门,主要有三个原因:
第一,复杂度刚刚好
。它不像贪吃蛇需要处理图形界面,也不像猜数字游戏只有几行代码。井字棋的核心逻辑包含”存储棋盘状态”(列表应用)、”轮流下棋”(循环控制)、”判断胜负”(条件判断),这些正是Python入门必须掌握的基础语法。你想想,学会这些,以后再学更复杂的项目,就像盖房子先打好了地基。 第二,能直观看到成果。写完代码就能和朋友对战,输了还能改代码”作弊”(比如让电脑故意让着你),这种互动感比对着黑屏敲代码有趣10倍。我之前在社区分享过这个方法,有个大学生留言说:”本来Python课要挂科了,跟着做了井字棋后,突然看懂了老师讲的for循环,期末还考了80分!” 第三,权威教程都推荐。Python官方文档的”入门指南”里就提到:”通过小型游戏项目学习编程,能更高效地理解语法规则”(链接,nofollow)。国内知名编程教育平台Codecademy也把井字棋列为”Python基础必做项目”,因为它能把零散的知识点串成体系。
手把手教你实现井字棋游戏(附完整源码)
说了这么多,不如直接动手试试。我把整个过程拆成4步,每一步都有具体代码和注释,你跟着做就行。对了,如果你用的是Windows系统,我 先装Anaconda(自带Python环境和Spyder编辑器),省得折腾环境配置——我刚开始学的时候,光配环境就花了2小时,后来发现用Anaconda能省不少事。
第一步:画个棋盘——用列表当”格子本”
下棋得有棋盘吧?在Python里,我们可以用”列表”来模拟棋盘。你可以把列表想象成一个3×3的格子本,每个格子里暂时放个数字(1-9),代表位置编号,就像这样:
# 初始化棋盘:用列表存储9个格子,初始值为1-9(代表位置编号)
board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
那怎么把这个列表”画”成我们熟悉的井字棋棋盘呢?写个打印函数就行。你看这段代码:
def print_board():
# 打印棋盘第一行
print(f' {board[0]} | {board[1]} | {board[2]} ')
# 打印分隔线
print('++')
# 打印第二行
print(f' {board[3]} | {board[4]} | {board[5]} ')
print('++')
# 打印第三行
print(f' {board[6]} | {board[7]} | {board[8]} ')
运行这个函数,屏幕上就会出现一个带数字的棋盘。我第一次写这段代码时,分隔线的格式调了半天——不是对不齐,就是少个横线,后来发现用f-string格式化字符串最方便,你也可以试试调整数字和分隔符的位置,看看能不能做出更美观的棋盘。
第二步:处理玩家输入——把”第几格”变成代码能懂的位置
玩家下棋时会说”我要下在第5格”,但代码需要知道”第5格”对应列表里的哪个位置。这里有个小技巧:把键盘输入的数字减1,就是列表的索引(因为Python列表从0开始计数)。比如输入”5″,对应的索引就是4(5-1=4),正好是棋盘正中间的位置。
不过得注意,玩家可能会输入无效值(比如字母、重复位置),所以要加个判断。我之前教朋友的时候,他故意输入”abc”想捣乱,结果程序直接报错了——后来我加了这段验证代码,就不怕他瞎输了:
def get_player_move(player):
while True:
# 让玩家输入位置(X或O轮流)
move = input(f'玩家{player}({"X" if player == 1 else "O"})请输入位置(1-9):')
# 判断输入是否是数字
if not move.isdigit():
print('请输入1-9之间的数字!')
continue
# 转成整数并减1(得到列表索引)
index = int(move)
1
# 判断是否在0-8范围内,且位置未被占用
if 0 <= index <= 8 and board[index] not in ['X', 'O']:
return index # 返回有效索引
else:
print('这个位置不能下,请重新输入!')
你看,这段代码用while循环让玩家”输对为止”,既处理了非数字输入,又避免了重复下棋——这种”防御性编程”的思路,以后写其他程序也用得上。
第三步:判断胜负——3连珠怎么用代码实现?
井字棋赢的条件是”横、竖、斜向有3个相同符号”。怎么让代码判断这个呢?我 了8种获胜情况:3行、3列、2条对角线,用列表把这些情况存起来,每次下棋后检查就行。
比如这是获胜组合的列表:
win_combinations = [
[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 check_win(player_symbol):
# 遍历所有获胜组合
for combo in win_combinations:
# 如果组合中的三个位置都是当前玩家的符号,返回True
if board[combo[0]] == board[combo[1]] == board[combo[2]] == player_symbol:
return True
return False
我刚开始写这段代码时,总搞不清”===”和”==”的区别,后来查了Python官方文档才明白(链接,nofollow):连续的”==”会从左到右比较,比如a == b == c
相当于(a == b) and (b == c)
,正好适合判断三个值是否相等——你看,遇到问题查官方文档,比瞎猜靠谱多了。
第四步:完整源码和运行效果——复制就能玩
把上面的代码拼起来,再加上游戏主循环(控制回合、切换玩家、判断平局),就是完整的井字棋游戏了。下面是带详细注释的源码,你可以直接复制到Python编辑器里运行:
# 初始化棋盘(1-9代表位置,后续会被X/O替换)
board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
获胜组合:3行、3列、2对角线
win_combinations = [
[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 print_board():
"""打印棋盘"""
print(f'n {board[0]} | {board[1]} | {board[2]} ')
print('++')
print(f' {board[3]} | {board[4]} | {board[5]} ')
print('++')
print(f' {board[6]} | {board[7]} | {board[8]} n')
def get_player_move(player):
"""获取玩家输入的位置,返回有效索引"""
while True:
move = input(f'玩家{player}({"X" if player == 1 else "O"})请输入位置(1-9):')
if not move.isdigit():
print('请输入1-9之间的数字!')
continue
index = int(move)
1
if 0 <= index <= 8 and board[index] not in ['X', 'O']:
return index
else:
print('这个位置不能下,请重新输入!')
def check_win(player_symbol):
"""检查当前玩家是否获胜"""
for combo in win_combinations:
if board[combo[0]] == board[combo[1]] == board[combo[2]] == player_symbol:
return True
return False
游戏主循环
current_player = 1 # 1代表X玩家,2代表O玩家
for _ in range(9): # 最多9步(棋盘满)
print_board() # 打印当前棋盘
index = get_player_move(current_player) # 获取玩家下棋位置
symbol = 'X' if current_player == 1 else 'O' # 确定当前玩家符号
board[index] = symbol # 更新棋盘
# 检查是否获胜
if check_win(symbol):
print_board()
print(f'恭喜玩家{current_player}({symbol})获胜!🎉')
break
# 切换玩家
current_player = 2 if current_player == 1 else 1
else:
# 循环正常结束(9步没分出胜负),平局
print_board()
print('游戏结束,平局!🤝')
你可以把这段代码保存为tic_tac_toe.py
,然后在命令行输入python tic_tac_toe.py
运行——亲测在Python 3.8-3.12版本都能跑,如果你遇到报错,大概率是缩进问题(Python对缩进很严格,用4个空格别用Tab)。
最后想对你说:编程学习就像下棋,刚开始可能总输(写不对代码),但多试几次就能找到规律。你可以试着给这个游戏加点新功能,比如记录比分、让电脑随机下棋(提示:用random模块),甚至做成双人对战小游戏——我之前用这个基础改出了”五子棋简化版”,发在GitHub上还收到了3个star呢!
如果你按这些步骤做了,或者有什么改代码的新思路,欢迎在评论区告诉我效果——说不定你的创意能启发更多想学Python的小伙伴呢!
想给井字棋加个计分板其实超简单,就是用两个变量记着X和O谁赢了几次。不过你刚开始可能会犯个小错——变量放的位置不对。我之前帮朋友改代码时,他把计分变量写在了游戏主循环里,结果每次新游戏开始,分数就重置成0了,白忙活半天。正确的做法是把这俩变量放在所有函数外面,比如代码最开头就写score_x = 0
和score_o = 0
,这样不管玩多少局,分数都会一直累加,就像真实下棋时拿个小本子记比分一样。
然后就是更新分数的时机,得在判断出胜负之后马上加。比如代码里不是有个if check_win(symbol):
的判断吗?在打印“恭喜获胜”那句话之前,加上一句score_x += 1
(如果是X赢了)或者score_o += 1
(如果是O赢了)。对了,平局的时候分数不用变,这点别忘记。最后显示分数也很关键,我一般会在每局结束后打印一句“当前比分:X玩家{score_x}胜 | O玩家{score_o}胜”,这样玩家一眼就知道谁领先。要是想更花哨点,还能在游戏开始前也显示一下上次的比分,比如“欢迎回来!上轮比分:X {score_x}
零基础学这个教程需要准备什么环境?
只需要安装Python 3.8-3.12版本(亲测这几个版本都兼容),推荐用Anaconda(自带Python环境和Spyder编辑器,省去配置麻烦)。不需要其他复杂工具,电脑能联网下载Python就行,手机或平板暂时不支持哦。
运行代码时提示“缩进错误”怎么办?
Python对缩进非常严格,必须用4个空格(别用Tab键),且同一代码块的缩进要对齐。比如“def print_board():”下面的代码,每一行开头都要空4格。如果不确定哪里错了,可以复制文章里的完整源码,用编辑器(如VS Code)打开,它会自动标出缩进问题。
如何给游戏添加计分板功能?
可以用两个变量(比如score_x和score_o)记录X和O玩家的胜场数,在判断获胜的代码后加上“score_x += 1”(X获胜时)或“score_o += 1”(O获胜时),最后用print语句显示分数。比如:“当前比分:X玩家{score_x}胜,O玩家{score_o}胜”。
没有编程基础能看懂这个教程吗?
完全可以!教程里每个步骤都有注释,把“列表”“循环”这些概念用“格子本”“轮流下棋”这样的生活例子解释了。我去年带的零基础朋友,也是第一次接触编程,跟着步骤1小时就跑通了代码。 先别急着改代码,先复制源码跑起来,再逐行看注释理解。
代码中的“win_combinations”是什么意思?
这是“获胜组合列表”,用来定义井字棋的8种获胜情况:前3组是横向(比如[0,1,2]对应第一行的3个位置),中间3组是纵向(比如[0,3,6]对应第一列),最后2组是对角线([0,4,8]是左上到右下,[2,4,6]是右上到左下)。代码会通过检查这些组合,判断玩家是否连成了3个相同符号。