- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。
用列表乱序shuffle来洗牌抓拍玩升级拖拉机
回忆
- 上次我们了解了
- 定点插入 insert
- 相对原来的 追加append
- 定点删除 pop
- 相对原来的 按值删除 remove

- 排好序 之后 可以
打乱顺序吗?
乱序

- 好像来自我们熟悉的包
- random
random.shuffle
import random
nl = list(range(4))
random.shuffle(nl)
nl
random.shuffle(nl)
nl
- 效果

- shuffle 之前 见过吗?
回忆
- 以前用的是
- random.randint
- 得到 随机整数
- random.choice
- 选择 一个 列表项

- shuflle怎么理解?
help
import random
help(random.shuffle)
- 在原地
- 打乱列表的次序

- 次序
乱了 有啥好的吗?
shuffle
- 随机安排角色

- 随机抓牌

- shuffle 本身就是洗牌的意思
洗牌
- 一副牌54张

- 每张牌一个编号
- 把牌洗开
洗牌
import random
poker_list = list(range(54))
random.shuffle(poker_list)
print(poker_list)
- 牌洗好了
- 不过洗的是牌的序号

- 扑克字符
扑克字符
- 要先 把 扑克牌 换成 字符

- unicode中包含扑克的字符

- 把 相关范围 都 遍历一遍
遍历范围
import random
for n in range(0x1f0a0, 0x1f0ff):
print(chr(n), end = " ")
- 输出结果

- 为什么JQK之外还有C?
花色来历
- 唐宋的叶子戏

- 传入波斯、阿拉伯
- 经过意大利、德国
- 骑士牌 (Cavalier/Knight)
- 是欧洲传统扑克牌的一部分
- 现在是英法花色 成为主流
- 在此基础上 构成了 美式扑克
- 这些排面有什么说法?
排面
- 人物也完成了 本地化

- 四大天王(king) 都来自英法

- 人物有什么含义
人物含义
|----|-----|--------|------------------|
| 牌面 | 花色 | 对应角色 | 核心身份 |
| K | 红桃♥ | 查理曼大帝 | 法兰克国王,西欧统一者 |
| | 黑桃♠ | 大卫王 | 以色列国王,《圣经》人物 |
| | 梅花♣ | 亚历山大大帝 | 马其顿国王,欧亚非征服者 |
| | 方块♦ | 凯撒大帝 | 罗马独裁官,罗马帝国奠基者 |
| Q | 红桃♥ | 朱迪思 | 犹太女英雄,《圣经》外典人物 |
| | 黑桃♠ | 雅典娜 | 希腊神话智慧与战争女神 |
| | 梅花♣ | 阿金尼 | 传说爱神(原型关联伊丽莎白一世) |
| | 方块♦ | 拉结 | 《圣经》中雅各的妻子 |
| J | 红桃♥ | 拉海尔 | 法国骑士,圣女贞德追随者 |
| | 黑桃♠ | 奥吉尔 | 查理曼大帝的圣骑士 |
| | 梅花♣ | 兰斯洛特 | 亚瑟王圆桌骑士,圣杯守护者 |
| | 方块♦ | 赫克托尔 | 特洛伊王子,神话勇士 |
- King > Queen > Jack(侍从)

- 为什么是 黑红梅方 四个花色?
花色
- 4组花色
- 代表四季

- 为什么是54张?
54张牌
- 52张正牌正好代表
- 一年中有52个星期

- 为什么 黑桃A 那么不同?
印花税
- 1712年
- 英国开始征收
- 印花税
- stamp duty
- 每一副牌必须有纳税的痕迹才能离开工厂

- 执行人 给
- 缴税纸牌的第一张
- 也就是黑桃A
- 盖上墨水戳
- 牌面 比K还大
- 想要 洗
真正的牌
- 可以吗?
提问

代码

# 生成仅含 Unicode 字符的 54 张扑克牌列表
deck = []
# 花色偏移:0=黑桃 1=红桃 2=梅花 3=方块
suits_offset = [0, 1, 2, 3]
# 牌面偏移:对应 A-K,跳过无效的 12、15
ranks_offset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14]
# 生成 4花色×13张牌,同时记录草花K的编码
club_k_code = None
for suit in suits_offset:
for rank in ranks_offset:
code = 0x1F0A0 + suit * 16 + rank
deck.append(chr(code))
# 捕获草花K的编码(花色偏移2,牌面偏移14)
if suit == 2 and rank == 14:
club_k_code = code
# 小王编码 = 草花K编码 + 1
joker_small_code = 0x1F0DF
# 大王编码 = 小王编码 + 12(按 Unicode 实际排版逻辑)
joker_big_code = 0x1F0CF
# 添加大小王
deck.append(chr(joker_small_code))
deck.append(chr(joker_big_code))
# 验证长度和输出
print(f"牌组长度: {len(deck)}")
print(f"草花K编码: 0x{club_k_code:X}, 字符: {chr(club_k_code)}")
print(f"小王编码: 0x{joker_small_code:X}, 字符: {chr(joker_small_code)}")
print(f"大王编码: 0x{joker_big_code:X}, 字符: {chr(joker_big_code)}")
print("\n完整牌组:")
print(" ".join(deck))
print(len(deck))
调整颜色

效果

BLACK_FG = "\033[30m" # 黑色前景
RED_FG = "\033[31m" # 红色前景
WHITE_BG = "\033[47m" # 白色背景
RESET = "\033[0m" # 重置所有样式
deck = []
colored_deck = []
# 花色偏移: 0=黑桃 1=红桃 2=方块 3=梅花,绑定对应前景色
suits = {
0: BLACK_FG,
1: RED_FG,
2: RED_FG,
3: BLACK_FG
}
# 有效牌面偏移 (A-K)
ranks_offset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14]
# 生成 4花色×13张牌,记录草花K编码
club_k_code = None
for suit_offset, fg_color in suits.items():
for rank in ranks_offset:
code = 0x1F0A0 + suit_offset * 16 + rank
card_char = chr(code)
deck.append(card_char)
# 拼接:前景色+白色背景+字符+重置
colored_card = f"{fg_color}{WHITE_BG}{card_char}{RESET}"
colored_deck.append(colored_card)
# 捕获草花K编码
if suit_offset == 2 and rank == 14:
club_k_code = code
# 处理大小王
joker_small_code = 0x1F0DF # 小王:草花K+1
joker_big_code = 0x1F0CF # 大王标准编码
# 小王:白背景+黑前景;大王:保持原样
joker_small = f"{BLACK_FG}{WHITE_BG}{chr(joker_small_code)}{RESET}"
joker_big = chr(joker_big_code)
# 加入两个列表
deck.append(chr(joker_small_code))
deck.append(chr(joker_big_code))
colored_deck.append(joker_small)
colored_deck.append(joker_big)
# 验证与输出
for card in colored_deck:
print(card, end=" ")
洗牌
- 洗牌

import random
BLACK_FG = "\033[30m" # 黑色前景
RED_FG = "\033[31m" # 红色前景
WHITE_BG = "\033[47m" # 白色背景
RESET = "\033[0m" # 重置所有样式
deck = []
colored_deck = []
# 花色偏移: 0=黑桃 1=红桃 2=方块 3=梅花,绑定对应前景色
suits = {
0: BLACK_FG,
1: RED_FG,
2: RED_FG,
3: BLACK_FG
}
# 有效牌面偏移 (A-K)
ranks_offset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14]
# 生成 4花色×13张牌,记录草花K编码
club_k_code = None
for suit_offset, fg_color in suits.items():
for rank in ranks_offset:
code = 0x1F0A0 + suit_offset * 16 + rank
card_char = chr(code)
deck.append(card_char)
# 拼接:前景色+白色背景+字符+重置
colored_card = f"{fg_color}{WHITE_BG}{card_char}{RESET}"
colored_deck.append(colored_card)
# 捕获草花K编码
if suit_offset == 2 and rank == 14:
club_k_code = code
# 处理大小王
joker_small_code = 0x1F0DF # 小王:草花K+1
joker_big_code = 0x1F0CF # 大王标准编码
# 小王:白背景+黑前景;大王:保持原样
joker_small = f"{BLACK_FG}{WHITE_BG}{chr(joker_small_code)}{RESET}"
joker_big = chr(joker_big_code)
# 加入两个列表
deck.append(chr(joker_small_code))
deck.append(chr(joker_big_code))
colored_deck.append(joker_small)
colored_deck.append(joker_big)
random.shuffle(colored_deck)
# 验证与输出
for card in colored_deck:
print(card, end=" ")
洗牌结果

- 扑克有啥玩法呢?
升级
- 4个人
- 每人抓12轮
- 总共抓48张
- 还剩6张
- 扣为底牌

- 底牌归当前轮的庄家
抓牌
import random
BLACK_FG = "\033[30m" # 黑色前景
RED_FG = "\033[31m" # 红色前景
WHITE_BG = "\033[47m" # 白色背景
RESET = "\033[0m" # 重置所有样式
deck = []
colored_deck = []
# 花色偏移: 0=黑桃 1=红桃 2=方块 3=梅花,绑定对应前景色
suits = {
0: BLACK_FG,
1: RED_FG,
2: RED_FG,
3: BLACK_FG
}
# 有效牌面偏移 (A-K)
ranks_offset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14]
# 生成 4花色×13张牌,记录草花K编码
club_k_code = None
for suit_offset, fg_color in suits.items():
for rank in ranks_offset:
code = 0x1F0A0 + suit_offset * 16 + rank
card_char = chr(code)
deck.append(card_char)
# 拼接:前景色+白色背景+字符+重置
colored_card = f"{fg_color}{WHITE_BG}{card_char}{RESET}"
colored_deck.append(colored_card)
# 捕获草花K编码
if suit_offset == 2 and rank == 14:
club_k_code = code
# 处理大小王
joker_small_code = 0x1F0DF # 小王:草花K+1
joker_big_code = 0x1F0CF # 大王标准编码
# 小王:白背景+黑前景;大王:保持原样
joker_small = f"{BLACK_FG}{WHITE_BG}{chr(joker_small_code)}{RESET}"
joker_big = chr(joker_big_code)
# 加入两个列表
deck.append(chr(joker_small_code))
deck.append(chr(joker_big_code))
colored_deck.append(joker_small)
colored_deck.append(joker_big)
random.shuffle(colored_deck)
dong = colored_deck[0:48:4]
nan = colored_deck[1:48:4]
xi = colored_deck[2:48:4]
bei = colored_deck[3:48:4]
di = colored_deck[-6:]
print("\n东:" + " ".join(dong))
print("南:" + " ".join(nan))
print("西:" + " ".join(xi))
print("北:" + " ".join(bei))
print("底:" + " ".join(di))
- 抓牌結果

- 牌抓到手里 还是要理一理的
最終代碼
import random
BLACK_FG = "\033[30m" # 黑色前景
RED_FG = "\033[31m" # 红色前景
WHITE_BG = "\033[47m" # 白色背景
RESET = "\033[0m" # 重置所有样式
deck = []
colored_deck = []
# 花色偏移: 0=黑桃 1=红桃 2=方块 3=梅花,绑定对应前景色
suits = {
0: BLACK_FG,
1: RED_FG,
2: RED_FG,
3: BLACK_FG
}
# 有效牌面偏移 (A-K)
ranks_offset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14]
# 生成 4花色×13张牌,记录草花K编码
club_k_code = None
for suit_offset, fg_color in suits.items():
for rank in ranks_offset:
code = 0x1F0A0 + suit_offset * 16 + rank
card_char = chr(code)
deck.append(card_char)
# 拼接:前景色+白色背景+字符+重置
colored_card = f"{fg_color}{WHITE_BG}{card_char}{RESET}"
colored_deck.append(colored_card)
# 捕获草花K编码
if suit_offset == 2 and rank == 14:
club_k_code = code
# 处理大小王
joker_small_code = 0x1F0DF # 小王:草花K+1
joker_big_code = 0x1F0CF # 大王标准编码
# 小王:白背景+黑前景;大王:保持原样
joker_small = f"{BLACK_FG}{WHITE_BG}{chr(joker_small_code)}{RESET}"
joker_big = chr(joker_big_code)
# 加入两个列表
deck.append(chr(joker_small_code))
deck.append(chr(joker_big_code))
colored_deck.append(joker_small)
colored_deck.append(joker_big)
random.shuffle(colored_deck)
dong = colored_deck[0:48:4]
nan = colored_deck[1:48:4]
xi = colored_deck[2:48:4]
bei = colored_deck[3:48:4]
di = colored_deck[-6:]
dong.sort()
nan.sort()
xi.sort()
bei.sort()
print("\n东:" + " ".join(dong))
print("南:" + " ".join(nan))
print("西:" + " ".join(xi))
print("北:" + " ".join(bei))
print("底:" + " ".join(di))
- 这样同样花色就被理顺了
列表函數总结
- 列表所有方法

- 再复习一遍
|----------|---------|----------------------|
| 功能类别 | 方法名称 | 操作说明(简化) |
| 🔹 元素添加 | append | 列表末尾添加单个元素(任意类型) |
| | extend | 末尾批量添加可迭代对象元素(展开) |
| | insert | 指定索引位置插入单个元素,后续元素后移 |
| 🔹 元素删除 | remove | 查找并删除第一个匹配 value 的元素 |
| | pop | 删除并返回指定索引元素,默认删最后一个 |
| | clear | 清空列表所有元素,保留列表对象 |
| 🔹 查找与统计 | index | 查找并返回第一个匹配 value 的索引 |
| | count | 统计 value 元素出现的次数 |
| 🔹 排序与反转 | sort | 原地排序,支持自定义规则 |
| | reverse | 原地反转列表元素顺序 |
| 🔹 复制操作 | copy | 返回列表的浅拷贝新列表 |
- 需要有所突破了
总结
- 这次 我们了解了
无序
- 排序 可以 让列表
有序 - 随机 可以 让列表
无序
- 无序有序都用
- 有序带来理性的方便
- 无序带来混沌的快乐

- 洗牌、码牌、抓牌、看牌
- 理牌 可以让手里的牌
- 有适合出牌的次序

- 目前 列表 都是 一维的
- 可以 升到 有
更高维度吗? 🤔
-
下次再说 👋
-
本文来自 oeasy Python 系统教程。
-
想完整、扎实学 Python,
-
搜索 oeasy 即可。