news 2026/10/17 1:15:43

Python猜拳小游戏实战:从零到一掌握编程核心逻辑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python猜拳小游戏实战:从零到一掌握编程核心逻辑

1. 为什么选择用Python写猜拳小游戏

1.1 从“最小可运行项目”说起

很多人学Python学到一半就卡住了,语法书翻了两三遍,视频课也刷了不少,但一合上电脑,脑子里空空如也,不知道能拿这门语言做点什么。这种状态我太熟悉了,因为我自己也经历过。后来我发现,问题不在于学得不够多,而在于缺少一个“从零到一”的完整项目体验。猜拳小游戏就是这样一个绝佳的切入点——它足够小,小到一两个小时就能跑通;又足够完整,完整到涵盖了输入输出、条件判断、循环控制、随机数、异常处理这些编程核心概念。

你可能会想,猜拳有什么好写的,不就是石头剪刀布吗?但恰恰是这种看似简单的东西,最能检验一个人对编程逻辑的理解是否扎实。我见过太多人,能背出Python的所有语法,却写不出一个健壮的猜拳程序。为什么?因为真实场景下的猜拳游戏要考虑的东西远比想象中多:用户输入了乱七八糟的东西怎么办?怎么让游戏可以反复玩而不是玩一局就退出?怎么统计胜率?怎么让电脑的出拳不那么容易被猜到?这些问题,才是编程思维真正落地的地方。

1.2 这个项目适合谁,能解决什么问题

这个项目适合所有已经掌握了Python基础语法、但还没有完整项目经验的人。不管你是刚学完大学计算机导论课的学生,还是转行自学编程的职场人,或者是想给孩子找个编程入门练习的家长,猜拳小游戏都是一个非常好的练手项目。它不需要你安装任何第三方库,不需要配置复杂的环境,打开Python自带的IDLE或者任何编辑器就能开始写。

从解决问题的角度来说,这个项目能帮你打通几个关键节点:第一,理解程序如何与用户交互,也就是输入输出的完整流程;第二,掌握条件分支和循环的组合使用,这是所有程序逻辑的基础;第三,学会用随机数模块模拟不确定性,这在游戏开发和数据分析中都很常见;第四,建立基本的异常处理意识,让你的程序不会因为用户乱输入就崩溃。这些能力,在你后续写更复杂的项目时,会反复用到。

1.3 我为什么反复推荐这个练手项目

说实话,我教过不少人学Python,也看过很多人的学习路径。那些进步最快的,往往不是看了最多教程的人,而是动手写了最多小项目的人。猜拳游戏的好处在于它的反馈极其即时——你写完几行代码,马上就能运行,马上就能看到结果。这种即时反馈对初学者来说太重要了,它能让你保持兴趣,让你觉得“我真的在写程序,而不是在背语法”。

另外,猜拳游戏的扩展性非常好。你可以在基础版本上不断增加功能:加个计分板、加个难度选择、加个图形界面、甚至加个简单的AI让电脑学会你的出拳习惯。每一次扩展,都是一次新的学习机会。我自己的习惯是,每学到一个新知识点,就想想能不能把它用到猜拳游戏里。比如学了字典,就用字典来存储出拳规则;学了函数,就把游戏逻辑拆成函数;学了类,就用面向对象的方式重写一遍。这种“以项目驱动学习”的方式,效率比单纯看书高得多。

2. 核心逻辑拆解与设计思路

2.1 猜拳游戏的规则抽象

在动手写代码之前,我们得先把现实中的猜拳规则抽象成计算机能理解的逻辑。现实中的猜拳很简单:石头赢剪刀,剪刀赢布,布赢石头,相同则平局。但计算机不会“理解”这些,它只能做比较和判断。所以我们需要把“赢”这个关系用数字或字符串表示出来。

最直观的方式是用数字编码:石头用0表示,剪刀用1表示,布用2表示。这样有一个很巧妙的地方——判断胜负可以用数学运算来实现。你想想,如果玩家出0(石头),电脑出1(剪刀),玩家赢;玩家出1(剪刀),电脑出2(布),玩家赢;玩家出2(布),电脑出0(石头),玩家赢。发现规律了吗?当玩家出的数字比电脑出的数字小1的时候,玩家赢。但这里有个边界情况:玩家出0,电脑出2的时候,0比2小,但实际上是电脑赢。所以我们需要用取模运算来处理这个循环关系。

具体来说,判断条件可以写成:(玩家出拳 - 电脑出拳) % 3。如果结果是1,说明玩家赢;结果是2,说明电脑赢;结果是0,说明平局。这个公式非常优雅,三行代码就能搞定所有胜负判断。我第一次发现这个规律的时候,觉得特别有意思,因为它把现实规则转化成了数学关系,这正是编程思维的核心——用计算的方式描述世界。

2.2 随机数模块的选择与使用

Python标准库里的random模块是我们实现电脑随机出拳的关键。random模块提供了多种随机数生成函数,最常用的是random.randint(a, b),它可以生成一个包含a和b的随机整数。比如random.randint(0, 2)就会随机返回0、1、2中的一个,正好对应我们的三种出拳。

这里有个细节值得注意:random模块生成的其实是“伪随机数”,也就是说,它基于一个种子值通过确定性算法计算出来的。默认情况下,种子值来自系统时间,所以每次运行程序的结果都不一样。但如果你设置了固定的种子,比如random.seed(42),那么每次运行程序,电脑的出拳顺序都会完全一样。这个特性在调试的时候特别有用——你可以复现每一次运行的结果,方便定位问题。

另外,如果你想让电脑的出拳不那么“随机”,比如让它更倾向于出某个拳,可以用random.choices()函数,它允许你指定每个元素的权重。比如random.choices([0, 1, 2], weights=[0.5, 0.3, 0.2])会让电脑有50%的概率出石头,30%出剪刀,20%出布。这种加权随机在游戏设计中很常见,可以让电脑的行为看起来更“像人”。

2.3 用户输入的处理策略

用户输入是猜拳游戏里最容易出问题的环节。你永远想不到用户会输入什么——可能是中文“石头”,可能是英文“rock”,可能是数字“0”,可能是大小写混搭的“Rock”,甚至可能是一串乱码。如果程序不做任何处理,用户随便输入一个东西,程序就可能报错崩溃。

我的处理策略是:先接收原始输入,然后做标准化处理。具体来说,用input()函数获取用户输入后,先用strip()去掉首尾空格,再用lower()统一转成小写。然后建立一个映射字典,把各种可能的输入都映射到对应的数字编码上。比如{"石头": 0, "0": 0, "rock": 0, "r": 0},这样不管用户怎么输入,只要在字典里,就能正确识别。

如果用户的输入不在字典里,就提示用户重新输入,并且给出正确的输入示例。这里可以用一个while循环,直到用户输入合法为止。这种“防御性编程”的思路非常重要,它能让你的程序在面对意外输入时依然保持稳定。我见过很多新手写的程序,功能逻辑都对,但用户一乱输入就崩溃,这就是缺少输入验证导致的。

2.4 游戏循环与退出机制的设计

一个完整的猜拳游戏不应该只玩一局就结束,而应该让用户可以选择继续玩或者退出。这就需要一个主循环来控制游戏的流程。常见的做法是用一个while True循环包裹整个游戏逻辑,然后在循环内部询问用户是否继续。如果用户选择退出,就用break语句跳出循环。

但这里有个细节:如果用户输入了非预期的选项,比如问“是否继续”的时候输入了“maybe”,程序应该怎么处理?我的做法是,把“是否继续”也做成一个输入验证的环节,只接受“y”、“yes”、“n”、“no”这几种输入,其他输入一律提示重新输入。这样虽然多写了几行代码,但用户体验会好很多。

另外,我还喜欢在退出的时候加一个统计功能,显示用户玩了多少局、赢了多少局、输了多少局、平了多少局,以及胜率是多少。这个功能虽然简单,但能让用户有成就感,也能让程序看起来更完整。统计数据的存储可以用几个变量来记录,每次游戏结束后更新,退出时统一显示。

3. 完整代码实现与逐段解析

3.1 基础版本:三十行代码跑通核心逻辑

先来看一个最精简的版本,这个版本去掉了所有花哨的功能,只保留最核心的游戏逻辑。我建议你先把这个版本跑通,理解每一行代码的作用,然后再逐步添加功能。

import random def get_computer_choice(): return random.randint(0, 2) def get_user_choice(): mapping = { "0": 0, "石头": 0, "rock": 0, "r": 0, "1": 1, "剪刀": 1, "scissors": 1, "s": 1, "2": 2, "布": 2, "paper": 2, "p": 2 } while True: user_input = input("请出拳(0-石头,1-剪刀,2-布):").strip().lower() if user_input in mapping: return mapping[user_input] print("输入无效,请重新输入。") def judge(user, computer): result = (user - computer) % 3 if result == 0: return "平局" elif result == 1: return "你赢了" else: return "你输了" def main(): print("=== 猜拳小游戏 ===") while True: user = get_user_choice() computer = get_computer_choice() names = ["石头", "剪刀", "布"] print(f"你出了{names[user]},电脑出了{names[computer]}") print(judge(user, computer)) if input("是否继续?(y/n):").strip().lower() != "y": break print("游戏结束,感谢游玩!") if __name__ == "__main__": main()

这段代码虽然短,但五脏俱全。get_computer_choice函数负责生成电脑的出拳,get_user_choice函数负责获取并验证用户输入,judge函数负责判断胜负,main函数负责串联整个流程。每个函数只做一件事,职责清晰,方便后续修改和扩展。

3.2 输入验证的强化处理

上面的版本已经做了基本的输入验证,但还不够完善。比如用户输入了“石头 ”(后面带空格),strip()能处理;但如果用户输入了“石 头”(中间有空格),就识别不了了。再比如用户输入了“Rock”,lower()能处理;但如果用户输入了“ROCK”,也能处理。但如果用户输入了“石头!”(带标点符号),就没办法了。

我的做法是,在标准化处理的时候,把常见的标点符号也去掉。可以用str.translate()方法,或者简单地用replace()替换掉常见标点。另外,我还会在提示信息里把可接受的输入都列出来,让用户知道该怎么输入。比如提示语可以写成:“请输入石头/剪刀/布,或者对应的数字0/1/2,或者英文rock/scissors/paper”。

还有一个细节:如果用户直接按回车,输入的是空字符串,也应该被判定为无效输入。这个用strip()之后判断是否为空就能处理。我见过一些程序,用户按回车之后程序就崩溃了,就是因为没有处理空输入的情况。

3.3 计分板与胜率统计的实现

加计分板其实很简单,只需要在main函数里定义几个变量来记录局数、胜局、负局、平局,然后在每局结束后更新这些变量,退出时统一显示。

def main(): print("=== 猜拳小游戏 ===") total = 0 wins = 0 losses = 0 draws = 0 names = ["石头", "剪刀", "布"] while True: user = get_user_choice() computer = get_computer_choice() print(f"你出了{names[user]},电脑出了{names[computer]}") result = judge(user, computer) print(result) total += 1 if result == "你赢了": wins += 1 elif result == "你输了": losses += 1 else: draws += 1 if input("是否继续?(y/n):").strip().lower() != "y": break print(f"\n共玩了{total}局") print(f"赢:{wins}局,输:{losses}局,平:{draws}局") if total > 0: print(f"胜率:{wins / total * 100:.1f}%") print("游戏结束,感谢游玩!")

胜率的计算要注意除以零的问题。如果用户一局都没玩就退出,total是0,直接做除法会报错。所以要先判断total是否大于0。这种边界情况的处理,是区分新手和有经验程序员的重要标志。

3.4 用字典优化胜负判断逻辑

前面我们用取模运算来判断胜负,代码很简洁。但如果你觉得取模运算不够直观,也可以用字典来存储胜负关系。比如:

win_rules = { 0: 1, # 石头赢剪刀 1: 2, # 剪刀赢布 2: 0 # 布赢石头 } def judge(user, computer): if user == computer: return "平局" elif win_rules[user] == computer: return "你赢了" else: return "你输了"

这种写法的好处是可读性更强,一眼就能看出谁赢谁。缺点是代码稍微长一点,而且如果以后要加新的出拳类型(比如“蜥蜴”和“斯波克”),需要修改字典。取模运算的版本则更通用,只要出拳类型是3的倍数,公式都成立。两种写法各有优劣,你可以根据自己的喜好选择。

3.5 让电脑学会“读心术”:简单的AI策略

如果你想让游戏更有挑战性,可以给电脑加一个简单的AI。这个AI会记录用户最近几次的出拳,然后预测用户下一次可能出什么,并选择能赢那个拳的出法。比如用户最近三次都出了石头,那AI就预测用户下次还会出石头,于是AI出布。

from collections import Counter class SimpleAI: def __init__(self): self.history = [] def predict(self): if len(self.history) < 3: return random.randint(0, 2) recent = self.history[-3:] most_common = Counter(recent).most_common(1)[0][0] # 预测用户会出most_common,选择能赢它的拳 counter = {0: 2, 1: 0, 2: 1} return counter[most_common] def record(self, choice): self.history.append(choice)

这个AI虽然简单,但已经能让电脑看起来“聪明”不少。当然,如果用户发现了这个规律,也可以故意改变出拳习惯来反制。这种博弈的过程,正是猜拳游戏的乐趣所在。

4. 常见问题与排查技巧实录

4.1 输入验证类问题速查

问题现象可能原因解决方法
用户输入中文时程序报错没有做输入标准化处理用strip().lower()处理,并建立映射字典
用户按回车后程序崩溃没有处理空输入判断strip()后是否为空字符串
用户输入数字0-2以外的数字没有做范围检查在映射字典中只保留合法输入
用户输入带标点符号没有去除标点用replace()或translate()去除常见标点
用户输入大小写混搭没有统一大小写用lower()统一转小写

4.2 逻辑判断类问题排查

最常见的问题是胜负判断写反了。比如把“石头赢剪刀”写成了“剪刀赢石头”。这种错误往往很难发现,因为程序不会报错,只是结果不对。我的建议是,写完之后手动测试所有九种组合(三种用户出拳乘以三种电脑出拳),确保每一种组合的结果都正确。

另一个常见问题是取模运算的边界情况。比如(0 - 2) % 3的结果是1,表示玩家赢,这是正确的,因为石头赢布。但如果你不小心写成了(computer - user) % 3,结果就完全反了。所以写取模运算的时候,一定要想清楚谁减谁。

4.3 循环控制类问题排查

如果程序陷入了死循环,最常见的原因是while循环的退出条件没有正确设置。比如在输入验证的循环里,如果用户一直输入无效内容,程序就会一直循环。这本身不是bug,但如果没有给用户一个退出的方式,体验就很差。我的做法是,在输入验证的循环里加一个计数器,如果用户连续输入错误超过5次,就自动退出或者给出更明确的提示。

另一个问题是break语句的位置。如果break写在了错误的位置,可能会导致循环提前退出或者无法退出。比如在嵌套循环里,break只能跳出最内层的循环。如果需要跳出多层循环,可以用标志变量或者函数返回来实现。

4.4 代码组织类问题排查

新手常犯的一个错误是把所有代码都写在main函数里,导致main函数越来越长,越来越难维护。我的建议是,每个独立的功能都封装成函数。比如获取用户输入是一个函数,生成电脑出拳是一个函数,判断胜负是一个函数,显示统计结果是一个函数。这样不仅代码更清晰,而且方便单独测试每个功能。

另外,全局变量的使用也要谨慎。比如计分板的变量,如果定义在全局,任何函数都能修改,容易出问题。更好的做法是把它们定义在main函数内部,通过参数传递给需要的函数,或者封装成一个类。虽然这样写起来稍微麻烦一点,但能避免很多潜在的bug。

4.5 我踩过的那些坑

第一个坑是中文编码问题。早期Python版本对中文支持不好,如果源代码里有中文字符串,可能会报编码错误。现在Python 3默认使用UTF-8编码,这个问题基本不存在了。但如果你在Windows上运行,控制台的编码可能是GBK,输出中文可能会乱码。解决办法是在代码开头加上# -*- coding: utf-8 -*-,或者在输出中文之前先设置控制台编码。

第二个坑是random模块的种子问题。有一次我调试程序,发现每次运行电脑的出拳顺序都一样,查了半天才发现是之前设置了random.seed()没有取消。这个坑让我明白了一个道理:调试用的代码一定要记得删掉,不然可能会影响正式运行的结果。

第三个坑是用户输入的数字和字符串混淆。比如用户输入了“0”,我直接用int()转换,结果用户输入了“石头”,int()就报错了。后来我改用映射字典,不管用户输入什么,只要在字典里就能正确转换,不在字典里就提示重新输入。这个方案虽然多写了几行代码,但健壮性好了很多。

5. 从命令行到图形界面:进阶扩展方向

5.1 用tkinter做一个可视化猜拳游戏

命令行版本的猜拳游戏虽然逻辑完整,但界面比较简陋。如果你想让它看起来更像一个“真正的游戏”,可以用Python自带的tkinter库做一个图形界面。tkinter是Python的标准GUI库,不需要额外安装,直接import就能用。

基本思路是:创建一个主窗口,在窗口里放置三个按钮,分别对应石头、剪刀、布。用户点击按钮后,程序生成电脑的出拳,然后在一个标签里显示结果。还可以加一个计分板标签,实时显示胜负统计。整个界面的布局可以用grid()或pack()来管理。

import tkinter as tk import random class GameGUI: def __init__(self): self.window = tk.Tk() self.window.title("猜拳小游戏") self.wins = 0 self.losses = 0 self.draws = 0 self.result_label = tk.Label(self.window, text="请出拳", font=("Arial", 16)) self.result_label.pack(pady=20) self.score_label = tk.Label(self.window, text="赢:0 输:0 平:0", font=("Arial", 12)) self.score_label.pack(pady=10) button_frame = tk.Frame(self.window) button_frame.pack(pady=20) tk.Button(button_frame, text="石头", width=8, command=lambda: self.play(0)).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="剪刀", width=8, command=lambda: self.play(1)).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="布", width=8, command=lambda: self.play(2)).pack(side=tk.LEFT, padx=5) self.window.mainloop() def play(self, user_choice): computer_choice = random.randint(0, 2) names = ["石头", "剪刀", "布"] result = (user_choice - computer_choice) % 3 if result == 0: self.draws += 1 outcome = "平局" elif result == 1: self.wins += 1 outcome = "你赢了" else: self.losses += 1 outcome = "你输了" self.result_label.config(text=f"你出{names[user_choice]},电脑出{names[computer_choice]},{outcome}") self.score_label.config(text=f"赢:{self.wins} 输:{self.losses} 平:{self.draws}") if __name__ == "__main__": GameGUI()

这个图形界面版本虽然简单,但已经具备了完整的游戏功能。你可以在此基础上继续美化界面,比如添加图片、音效、动画效果等。

5.2 用类来重构代码

如果你想让代码更符合面向对象的编程思想,可以把游戏逻辑封装成一个类。这样做的好处是,游戏的状态(比如计分板)和操作(比如出拳、判断胜负)都绑定在一起,代码更内聚,也更容易扩展。

class RockPaperScissors: def __init__(self): self.total = 0 self.wins = 0 self.losses = 0 self.draws = 0 self.names = ["石头", "剪刀", "布"] def get_computer_choice(self): return random.randint(0, 2) def judge(self, user, computer): result = (user - computer) % 3 if result == 0: self.draws += 1 return "平局" elif result == 1: self.wins += 1 return "你赢了" else: self.losses += 1 return "你输了" def play_round(self, user_choice): computer_choice = self.get_computer_choice() result = self.judge(user_choice, computer_choice) self.total += 1 return f"你出{self.names[user_choice]},电脑出{self.names[computer_choice]},{result}" def get_stats(self): if self.total == 0: return "还没有玩过" return f"共{self.total}局,赢{self.wins}局,输{self.losses}局,平{self.draws}局,胜率{self.wins/self.total*100:.1f}%"

用类重构之后,你会发现代码的可读性和可维护性都提升了一个档次。而且如果你以后想加一个“双人对战”模式,只需要在类里加一个方法,让两个玩家分别输入出拳,然后调用judge方法判断胜负即可。

5.3 添加难度选择和游戏模式

基础版本的猜拳游戏只有一个难度,就是电脑完全随机出拳。你可以添加难度选择功能,让玩家可以选择“简单”、“普通”、“困难”三个难度。简单模式下,电脑完全随机;普通模式下,电脑有30%的概率预测玩家的出拳;困难模式下,电脑有60%的概率预测玩家的出拳。

实现思路是,在游戏开始前让玩家选择难度,然后根据难度设置一个预测概率。每次电脑出拳时,先生成一个0到1之间的随机数,如果小于预测概率,就使用AI预测的出拳,否则随机出拳。这样既增加了游戏的挑战性,又不会让玩家觉得电脑在作弊。

另外,你还可以添加“三局两胜”或“五局三胜”的游戏模式。这种模式下,游戏不再是无限循环,而是先赢够指定局数的玩家获胜。实现起来也很简单,只需要在循环里加一个判断,当某一方的胜局达到指定数量时,跳出循环并宣布获胜者。

5.4 用文件存储游戏记录

如果你想让游戏记录可以跨会话保存,可以把每局的结果写入文件。比如用CSV格式存储,每行记录一局的时间、玩家出拳、电脑出拳、结果。这样你可以在游戏结束后分析自己的出拳习惯,看看自己是不是总是出石头。

import csv from datetime import datetime def save_record(user, computer, result): with open("game_records.csv", "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow([datetime.now().strftime("%Y-%m-%d %H:%M:%S"), user, computer, result])

这个功能虽然简单,但能让你的项目看起来更“专业”。而且通过分析游戏记录,你可能会发现一些有趣的规律,比如自己在输了一局之后倾向于出剪刀,或者电脑在连续出两次石头之后倾向于出布。这些规律本身就是很好的数据分析练习。

6. 从猜拳游戏延伸出的编程思维

6.1 状态管理的重要性

猜拳游戏虽然简单,但它涉及到一个核心的编程概念:状态管理。游戏的状态包括当前是第几局、玩家赢了多少局、电脑赢了多少局、平了多少局。这些状态需要在程序的整个生命周期内保持一致,不能出现“赢了但计分板没加”或者“退出了但统计没显示”的情况。

在实际开发中,状态管理是一个很容易出问题的地方。我的经验是,尽量把相关的状态放在一起管理,比如用一个字典或者一个类来存储所有状态变量。每次修改状态的时候,都要想清楚这个修改会不会影响到其他状态。比如增加胜局的同时,也要增加总局数,这两个操作应该绑定在一起,不能分开写。

6.2 防御性编程的习惯

猜拳游戏让我养成了一个很重要的习惯:永远不要相信用户的输入。用户可能会输入任何东西,你的程序必须能处理所有可能的输入,而不是假设用户会按照你的期望输入。这种“防御性编程”的思路,在实际工作中非常重要。

具体来说,防御性编程包括几个方面:第一,对所有外部输入做验证,确保它们在合法范围内;第二,对可能出错的操作做异常处理,比如文件读写、网络请求;第三,对边界情况做特殊处理,比如除以零、空列表、空字符串。这些习惯看起来是小事,但能避免很多线上事故。

6.3 从简单项目中发现深层原理

猜拳游戏看似简单,但如果你深入思考,会发现它涉及很多计算机科学的基础概念。比如随机数的生成原理、伪随机数的周期性、取模运算的数学性质、状态机的设计模式、用户交互的流程控制。这些概念在更复杂的项目中会反复出现,如果你能在猜拳游戏这个简单的场景里把它们理解透彻,以后遇到复杂问题时就能更快地找到解决方案。

我个人的体会是,学习编程不要一味追求“高大上”的项目,有时候把一个小项目做深做透,收获反而更大。猜拳游戏我写过很多遍,每一遍都有新的体会。第一遍学会了基本的输入输出和条件判断,第二遍学会了函数封装和异常处理,第三遍学会了面向对象和图形界面,第四遍学会了状态管理和数据持久化。每一次重写,都是对编程理解的一次深化。

6.4 测试驱动开发的初步体验

如果你想让猜拳游戏的代码质量更高,可以尝试测试驱动开发(TDD)的思路。具体来说,就是先写测试用例,再写实现代码。比如对于judge函数,你可以先写几个测试用例:judge(0, 1)应该返回“你赢了”,judge(1, 0)应该返回“你输了”,judge(0, 0)应该返回“平局”。然后运行测试,看着它们失败,再写实现代码让测试通过。

这种开发方式虽然一开始会慢一点,但能帮你写出更健壮的代码。因为你在写实现之前,就已经想清楚了所有可能的输入和输出。而且当你以后修改代码时,只要重新运行测试,就能知道有没有破坏原有的功能。Python自带的unittest模块或者第三方库pytest都可以用来写测试。

import unittest class TestJudge(unittest.TestCase): def test_win(self): self.assertEqual(judge(0, 1), "你赢了") self.assertEqual(judge(1, 2), "你赢了") self.assertEqual(judge(2, 0), "你赢了") def test_lose(self): self.assertEqual(judge(1, 0), "你输了") self.assertEqual(judge(2, 1), "你输了") self.assertEqual(judge(0, 2), "你输了") def test_draw(self): self.assertEqual(judge(0, 0), "平局") self.assertEqual(judge(1, 1), "平局") self.assertEqual(judge(2, 2), "平局") if __name__ == "__main__": unittest.main()

写完这些测试用例之后,你会发现你对judge函数的理解更加清晰了,而且以后不管怎么修改这个函数,只要测试通过,就能保证逻辑是正确的。

6.5 代码风格与可读性

最后再聊一个容易被忽视但很重要的话题:代码风格。猜拳游戏虽然代码量不大,但正是练习良好代码风格的好机会。比如变量命名要有意义,不要用a、b、c这种名字;函数要短小精悍,一个函数只做一件事;注释要写清楚“为什么”而不是“是什么”;代码缩进要统一,不要一会儿用空格一会儿用Tab。

我见过很多新手写的代码,功能是对的,但读起来非常费劲。变量名是拼音缩写,函数名是拼音全拼,注释要么没有要么写的是废话。这种代码自己过两个月再看都看不懂,更别说给别人看了。所以从猜拳游戏开始,就养成写“干净代码”的习惯,对你以后的编程生涯会有很大的帮助。

我个人在实际操作中的体会是,猜拳游戏虽然简单,但它是一个非常好的“编程实验室”。你可以在里面尝试各种新的想法和技术,不用担心搞砸,因为代码量小,重写成本低。而且每次重写,你都会发现自己对编程的理解又深了一层。这种不断迭代、不断精进的过程,才是学习编程最有趣的地方。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 1:15:20

单纯形法与大M法实战:从SciPy调库到手写Python实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:15:19

P1070道路游戏:对角线前缀和+单调队列优化DP详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:15:07

Hyperledger Fabric核心概念全解析:从交易生命周期到账本、MSP与链码

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:13:57

MP2642GR-Z与STM32F411RE双电池均衡系统设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:13:54

双串联锂电池硬件均衡方案:MP2642GR-Z与PIC18F45K80协同设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:11:02

Windows 10深度学习环境搭建:Anaconda3+TensorFlow+PyCharm避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华