上节课我们通过加入字典完成了道具字典的映射。目前游戏中,我们可以重复捡到同一把斧头或盾牌;探索地点也是随机的,如果我们需要地点不能被修改,该怎么办呢?今天我们将学习 元组(Tuple) 和 集合(Set),通过它们特性优化我们的背包系统(项目 v3.0)!课程目录
一、为什么还需要其他数据结构?
在现实中,有些事物一旦设定就不能更改,比如“血量等于0时游戏结束”、“游戏固定四个探索地点”。如果用列表存地点,一不小心在后面的代码中 `locations.append("外星系")` 被修改了,会导致意外的错误。
另外,游戏中如果是特殊唯一道具(例如神斧、神盾),你只能拥有一件。如果用列表存道具,不断 append 则会有很多完全一样的道具填满包裹。我们希望可以做到:当包裹里已有“木盾”,再捡到“木盾”就不会重复添加。
二、元组 (Tuple):不可变的序列
元组 和列表非常像,最大的区别是:元组就像是一份“打印出来的只读菜单”,一旦创建就无法修改(不能增加、删除或修改内部的元素)。它的标志是圆括号 ()。
# 创建元组locations = ("山谷", "森林", "山顶", "洞穴")print(locations[0]) # 输出: 山谷 (和列表一样的切片访问操作)# 下面这行会报错!元组不允许修改# locations[0] = "海滩" # TypeError# locations.append("海滩") # AttributeError
小贴士
如果元组只有一个元素,必须以逗号作为结尾:single_tuple = ("山谷",),不然圆括号会被当成普通的数学括号处理哦。
当你想保存不希望被意外修改的核心配置信息(比如游戏关卡、固定的NPC名字)时,优先使用元组!
三、集合 (Set):天然去重的好帮手
集合 就像是一个“只认新面孔的俱乐部”。它内部的元素没有固定的顺序,但最厉害的一点是:绝对不会有重复的数据,它会自动帮你把重复的部分扔掉!。它的标志是花括号 {}(注意里面直接写元素,没有冒号 :,有冒号的是字典)。
# 创建集合 (用花括号即可)unique_items = {"potion", "axe", "potion"}print(unique_items) # 输出: {'potion', 'axe'},多余的potion自动被去重了!# 添加和删除unique_items.add("shield") # 集合中用 add 添加元素unique_items.remove("axe")# 检查是否包含if "potion" in unique_items: print("有恢复药水!")
四、数据结构总结:“四大天王”怎么选?
很多初学者容易记混这四个“天王”,别怕!老师给大家画了一张总结对比表,以后写代码时忘了随时来看看:
| | | | |
|---|
| 列表 (List) | [ ] | | | |
| 字典 (Dict) | {键: 值} | | | 像查字典,通过特殊的“名字”精准查找对应的“详细信息”。 |
| 元组 (Tuple) | ( ) | | | 像“被封印的列表”,一旦创建绝对安全,非常适合当配置文件。 |
| 集合 (Set) | { } | | | 像个“魔法口袋”,放进100个相同的苹果,里面也永远只有1个! |
五、课堂随堂练习(理论实操巩固)
练习1:亲自尝试打破元组
在编辑器中定义 locations = ("山谷", "森林")。然后尝试运行 locations.append("密室") 或 locations[0] = "海滩"。看看控制台的报错长什么样,亲自体会元组的“不可篡改”特性。
练习2:感受集合的“秒去重”魔法
自己编写一个有很多重复元素的列表,比如 items = ["木剑", "木剑", "破盾牌", "木剑", "回血药"]。试着用 print(set(items)) 打印出来,观察它是如何在一瞬之间清理掉所有重复数据的。
六、阶段基础项目:徽章收集器(简单易懂,核心实战)
为了巩固刚才的新知识,我们准备了一个极简的阶段小项目。这个项目代码非常少,只包含本节课最重要的知识点:元组(不变的奖池)和集合(去重的收藏夹)。
在这个小游戏里,你可以不断抽奖,由于奖池是元组不可变,而你的收藏夹是集合,所以抽到重复徽章时,集合会自动帮你把重复的过滤掉,你不需要写复杂的判断代码!
import random# 固定的徽章奖池(元组,不可改变,防止作弊)badge_pool = ("勇敢徽章", "智慧徽章", "幸运徽章")# 玩家收集到的徽章(集合,自动去重,同样徽章只能拿一个)my_badges = set()print("=== 欢迎来到徽章寻宝小游戏 ===")while True: print(f"\n当前收集进度:{len(my_badges)} / {len(badge_pool)}") print("1. 探索寻找徽章") print("2. 查看我的徽章柜") print("3. 退出") choice = input("请选择操作:") if choice == "1": # 随机从元组中抽取一个 new_badge = random.choice(badge_pool) print(f"【寻宝结果】你找到了:{new_badge}!") # 尝试加入集合中,如果已有该徽章,集合会自动去重,不会增加 my_badges.add(new_badge) elif choice == "2": # 查看集合里的徽章 print(f"【我的徽章柜】: {my_badges}") elif choice == "3": print("游戏结束,再见!") break else: print("输入错误,请重新输入。")
七、进阶综合挑战:背包去重系统 v3.0(可选自学)
对于学有余力的同学,我们可以结合前几节课的知识,将所有的内容进行一次终极串联。不用害怕下面代码变长!它其实就是把上一节课的代码,把存放地点的 [] 换成了 (),把存放背包数据的 [] 换成了 set() 集合而已。
import random# 玩家基础状态player_hp = 100player_attack = 5# 固定的游戏地点(元组,防修改)locations = ("山谷", "森林", "山顶", "洞穴")# 背包改用集合,此处我们用 set() 初始化一个空集合backpack = set()# 道具数据库(字典)item_db = { "potion": {"desc": "小型恢复药水", "type": "heal", "value": 30}, "axe": {"desc": "木斧", "type": "attack", "value": 10}, "hammer": {"desc": "铁锤", "type": "attack", "value": 15}, "shield": {"desc": "木盾", "type": "defense", "value": 1}}while True: print("====== 冒险菜单 v3.0 ======") print("1. 外出探索") print("2. 查看背包") print("3. 使用道具") print("4. 查看状态") print("5. 退出游戏") print("===========================") choice = input("请输入选择:").strip() if choice == "1": # 从固定的地点元组中随机挑选一个地方去探索 current_loc = random.choice(locations) drops = ["potion", "axe", "hammer", "shield"] got_item = random.choice(drops) # 利用集合天然可判断,但要定制提示 if got_item in backpack: print(f"你探索了 {current_loc},发现了 {got_item},但你已经拥有它了,所以丢弃了重复的道具!") else: backpack.add(got_item) print(f"你探索了 {current_loc},获得新道具:{got_item}") elif choice == "2": if len(backpack) == 0: print("背包是空的") else: print("【当前背包(所有道具均具有唯一性)】") # 集合同样支持 for 循环遍历,虽然它无序但我们不在乎展示的顺序 for item_name in backpack: info = item_db.get(item_name, {"desc": "未知道具"}) print(f"- {item_name}:{info['desc']}") elif choice == "3": if len(backpack) == 0: print("背包是空的") print() continue print("【当前背包】") for item_name in backpack: info = item_db.get(item_name, {"desc": "未知道具"}) print(f"- {item_name}:{info['desc']}") target = input("请输入要使用的道具名:").strip().lower() if target not in backpack: print("你背包里没有这个道具") else: info = item_db.get(target) if info is None: print("这个道具没有配置功能") else: item_type = info["type"] item_value = info["value"] if item_type == "heal": player_hp += item_value print(f"你使用了 {target},恢复 {item_value} 点生命。当前生命:{player_hp}") backpack.remove(target) elif item_type == "attack": player_attack += item_value print(f"你装备了 {target},攻击 +{item_value}。当前攻击:{player_attack}") backpack.remove(target) elif item_type == "defense": print(f"你使用了 {target},获得一次防御效果。") backpack.remove(target) else: print("这个道具暂时没有可用效果") elif choice == "4": print(f"生命:{player_hp} | 攻击:{player_attack} | 背包数量:{len(backpack)}") elif choice == "5": print("游戏结束,欢迎下次再来。") break else: print("输入错误,请重新输入。") print()
八、本节课总结
- 掌握了 元组(Tuple) 的概念,用于存储不可被修改的信息。
- 掌握了 集合(Set) 的特性,学习了它无序且天然去重的强大能力。
- 复习了四大基础数据结构。你现在拥有了构建复杂状态流处理的能力!
- 完成了项目 v3.0:背包防重复优化,并在其中结合了
if / elif / while / in 的综合使用。
下节课我们将学习字符串更深度的处理方法,加入用户输入的容错环节,提升游戏的健壮性,敬请期待!