恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

AI辅助开发:用Python打造终端回合制战术游戏Shove

  • 首页
  • 资讯中心
  • /
  • AI辅助开发:用Python打造终端回合制战术游戏Shove

相关资讯

EQTransformer实战:AI驱动的震相拾取与地震数据处理指南 2026/9/8 6:01:18
Redis正式接入AI:从缓存到AI基础设施的核心实践 2026/9/8 6:01:18
高效驱动更新方案:从批量安装到硬件ID精确定位的完整指南 2026/9/8 6:01:18

最新资讯

英伟达OpenAI千亿合作背后的AI算力变革与开发者应对策略
大一新生如何备战电子设计竞赛?零基础到获奖的全流程心得
图像处理项目工程化实践:模块化架构与性能优化
微信小程序自助洗衣房预约系统技术拆解:状态管理与支付联动
ComfyUI整合包部署指南:从环境配置到工作流实战
GNN实战指南:PyTorch Geometric环境配置与GCN/GraphSAGE/GAT代码解析

今日推荐

Redis缓存与离线预计算在大数据处理中的实战应用
Android 12热启动闪屏排查:从冷热启动差异到官方SplashScreen避坑指南
加密资产价值投资:原理、方法与实战策略

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

AI辅助开发:用Python打造终端回合制战术游戏Shove

发布时间:2026/9/8 6:01:18
AI辅助开发:用Python打造终端回合制战术游戏Shove CLI 游戏指完全运行在终端窗口里的程序。Shove 是一个回合制战术小游戏核心规则很直接玩家和敌人在一张网格地图上移动玩家可以把敌人朝某个方向推挤如果敌人被推到墙上就会受到伤害。听起来简单但把“推”设计成决策后一局游戏会同时涉及位置判断、行动顺序、胜负判定和终端交互。整个设计、构建、试玩过程我是在 Claude Fable 5 的辅助下完成的先让 AI 生成规则草案再生成 Python 骨架最后在终端里完整跑通并修正逻辑。这篇文章会把 Shove 从规则到代码全部拆开给出可直接运行的 Python 实现也会说明哪些地方不能依赖 AI 自动生成必须人工核对。1. 为什么做终端战术游戏Shove 的规则又是怎么来的1.1 终端游戏为什么依然值得做终端游戏没有图形界面反而把交互压缩到了最小。对回合制战术游戏来说界面越简单越容易把注意力放在位置和决策上。CLI 游戏天然具备三个优势输出确定每回合地图和状态都可以用纯文本完整显示。依赖极少一个 Python 文件就能运行方便分享和复盘。调试直观可以在任意回合插入打印语句直接把坐标和状态打出来。Shove 选择终端而不是网页或桌面窗口并不是因为做不出图形界面而是因为“推挤”这个机制本身很适合用网格和方向键来表达。玩家不需要看动画只需要知道自己和敌人的相对位置以及下一步该往哪个方向走。1.2 Shove 的核心规则推挤、撞墙和行动顺序Shove 的地图是一张被墙壁包围的矩形网格。玩家用 WASD 控制上下左右移动敌人每回合会向玩家靠近。真正有战术深度的地方在推挤判定行为条件结果玩家移动目标格为空玩家移动到目标格玩家推击目标格有敌人敌人后方为空敌人后移一格玩家进入敌人原格推击撞墙目标格有敌人敌人后方是墙或边界敌人扣除 1 点生命值玩家不移动推击被阻挡敌人后方有另一个敌人双方都不移动敌人攻击敌人与玩家相邻玩家扣除 1 点生命值敌人移动存在比当前位置更接近玩家的空地敌人移动一步这套规则的关键在于“撞墙伤害”。玩家不能直接攻击敌人只能通过走位和方向选择让敌人撞向墙壁。这样每一回合都变成一道小谜题我是先绕到敌人背后还是等敌人主动靠近后把它推向墙边。1.3 Claude Fable 5 参与设计的方式Shove 的初始规则文本是由 Claude Fable 5 生成的。设计过程不是让 AI 一次性给出完整成品而是先给它一个足够具体的需求描述请设计一个终端回合制战术游戏 Shove 1. 使用 7x5 的网格地图四周是墙。 2. 玩家用 WASD 移动。 3. 玩家不能直接攻击敌人但可以把敌人推向墙壁敌人撞墙后掉血。 4. 敌人每回合向玩家靠近如果相邻则攻击玩家。 5. 游戏在终端中渲染不依赖第三方 Python 库。 6. 需要明确的胜利和失败条件。AI 返回的初版规则偏向“推箱子”就是玩家把敌人推到目标点消除。但人工调整后我否定了“目标点”方案因为目标点会让游戏变成固定解法缺少随机博弈。最终改为“撞墙掉血”这样地图只需要墙和空地敌人 AI 的走位本身就会影响玩家的推击策略。这个例子说明AI 能快速给出可运行的规则骨架但游戏好不好玩仍然需要人来判断。2. 环境准备和最小可运行骨架2.1 环境要求Shove 只依赖 Python 标准库不需要安装任何第三方包。建议使用 Python 3.9 及以上版本因为代码中使用了dataclasses和类型标注这些在更早版本中支持不够完整。项目要求操作系统Linux、macOS、Windows 均可Python3.9 或更高第三方库无终端任意支持标准输入输出的终端字符编码UTF-8Windows 下建议设置PYTHONIOENCODINGutf-8可以先检查 Python 环境python --version在部分 Linux 或 macOS 系统上python可能指向 Python 2需要使用python3 --version2.2 项目结构这个阶段不需要复杂的工程结构一个文件足够shove/ shove.py README.mdshove.py保存全部游戏逻辑。等后续加入关卡文件、单元测试、打包配置后再拆成多个模块。过早拆分目录对一个小游戏反而是负担。2.3 第一步一张地图和一个输入循环先写一个最简版本只做地图渲染和玩家移动不处理敌人。这样能优先验证输入输出链路。import os WIDTH, HEIGHT 7, 5 EMPTY, WALL, PLAYER ., #, P DIRS { w: (-1, 0), s: (1, 0), a: (0, -1), d: (0, 1), } class Game: def __init__(self): self.grid [[EMPTY] * WIDTH for _ in range(HEIGHT)] for x in range(WIDTH): self.grid[0][x] WALL self.grid[HEIGHT - 1][x] WALL for y in range(HEIGHT): self.grid[y][0] WALL self.grid[y][WIDTH - 1] WALL self.player [1, 1] def render(self): os.system(cls if os.name nt else clear) grid [row[:] for row in self.grid] py, px self.player grid[py][px] PLAYER for row in grid: print( .join(row)) def run(self): while True: self.render() cmd input(WASD ).strip().lower() if cmd q: break if cmd not in DIRS: continue dr, dc DIRS[cmd] ny, nx self.player[0] dr, self.player[1] dc if 0 ny HEIGHT and 0 nx WIDTH and self.grid[ny][nx] ! WALL: self.player [ny, nx] if __name__ __main__: Game().run()这个版本不包含敌人但已经具备三个重要基础地图使用字符串矩阵表示grid[y][x]可以直接读取坐标。玩家位置用[y, x]保存方便修改。输入命令统一转小写避免大写 W、A、S、D 不生效。运行后地图会显示为# # # # # # # # P . . . . # # . . . . . # # . . . . . # # # # # # # #输入d可以让玩家向右移动一格。输入q退出。3. 把推击、敌人 AI 和胜负循环补完整3.1 用数据结构和类表示单位先定义Enemy类。虽然这里可以用元组保存敌人坐标但敌人有生命值后面还可能扩展种类所以用数据类更清晰。from dataclasses import dataclass dataclass class Enemy: y: int x: int hp: int 2游戏中核心字段如下名称类型说明gridlist[list[str]]静态地图保存墙和空地playerlist[int, int]玩家坐标格式是[y, x]enemieslist[Enemy]当前存活的敌人player_hpint玩家生命值turnsint已进行回合数地图使用字符矩阵而不是把玩家和敌人直接写进矩阵原因在于单位会频繁移动。如果直接修改矩阵每次移动都要清理旧坐标容易遗漏。更好的做法是渲染时临时把单位覆盖到网格副本上。3.2 玩家回合移动和推击分支玩家回合核心方法是player_turn。它需要处理三种情况目标格是空地、目标格是敌人、目标是墙。def player_turn(self, cmd): dr, dc DIRS[cmd] py, px self.player ty, tx py dr, px dc if self.is_wall(ty, tx): return enemy self.enemy_at(ty, tx) if enemy is None: self.player [ty, tx] return ny, nx enemy.y dr, enemy.x dc if self.is_wall(ny, nx): enemy.hp - 1 if enemy.hp 0: self.enemies.remove(enemy) return if self.enemy_at(ny, nx) is not None: return enemy.y, enemy.x ny, nx self.player [ty, tx]这个方法的顺序很重要。先判断墙再判断是否撞到敌人最后判断敌人后方是否被堵住。如果把“敌人后方是否有另一个敌人”放在“敌人后方是墙”之前就会导致边界判断出错。is_wall方法必须同时处理越界和地图中的墙def is_wall(self, y, x): if y 0 or y self.height or x 0 or x self.width: return True return self.grid[y][x] WALL把越界直接视为墙可以避免索引报错也让“边界”和“墙壁”在推击判定中保持一致。3.3 敌人回合用曼哈顿距离做简单决策敌人不需要太聪明否则新手很难赢。这里使用曼哈顿距离作为接近玩家的依据。曼哈顿距离就是横纵坐标差的绝对值之和def enemy_turn(self): for enemy in self.enemies: ey, ex enemy.y, enemy.x best_y, best_x ey, ex best_dist abs(self.player[0] - ey) abs(self.player[1] - ex) for dy, dx in ((-1, 0), (1, 0), (0, -1), (0, 1)): ny, nx ey dy, ex dx if self.is_wall(ny, nx) or self.enemy_at(ny, nx): continue dist abs(self.player[0] - ny) abs(self.player[1] - nx) if dist best_dist: best_dist dist best_y, best_x ny, nx if best_y ey and best_x ex: continue if best_y self.player[0] and best_x self.player[1]: self.player_hp - 1 else: enemy.y, enemy.x best_y, best_x这里有一个容易混淆的点如果敌人下一步会踩到玩家不是在判断目的地时提前拦截而是先计算距离再判断best是否等于玩家坐标。如果等于就攻击玩家不移动。否则移动。使用曼哈顿距离而不是 BFS 寻路是为了让敌人行为有可读性。玩家可以预判敌人的大致行动方向从而设计推击路线。换成 BFS 后敌人会绕墙初学者很难找到规律。3.4 完整代码和运行方式把前面各节代码合并后保存为shove.pyimport os from dataclasses import dataclass EMPTY . WALL # PLAYER P ENEMY E DIRS { w: (-1, 0), s: (1, 0), a: (0, -1), d: (0, 1), } dataclass class Enemy: y: int x: int hp: int 2 class Game: def __init__(self, width7, height5): self.width width self.height height self.grid [[EMPTY] * width for _ in range(height)] self._build_walls() self.player [1, 1] self.enemies [ Enemy(1, 3), Enemy(3, 3), ] self.player_hp 3 self.turns 0 def _build_walls(self): for x in range(self.width): self.grid[0][x] WALL self.grid[self.height - 1][x] WALL for y in range(self.height): self.grid[y][0] WALL self.grid[y][self.width - 1] WALL def is_wall(self, y, x): if y 0 or y self.height or x 0 or x self.width: return True return self.grid[y][x] WALL def enemy_at(self, y, x): for enemy in self.enemies: if enemy.y y and enemy.x x: return enemy return None def player_turn(self, cmd): dr, dc DIRS[cmd] py, px self.player ty, tx py dr, px dc if self.is_wall(ty, tx): return enemy self.enemy_at(ty, tx) if enemy is None: self.player [ty, tx] return ny, nx enemy.y dr, enemy.x dc if self.is_wall(ny, nx): enemy.hp - 1 if enemy.hp 0: self.enemies.remove(enemy) return if self.enemy_at(ny, nx) is not None: return enemy.y, enemy.x ny, nx self.player [ty, tx] def enemy_turn(self): for enemy in self.enemies: ey, ex enemy.y, enemy.x best_y, best_x ey, ex best_dist abs(self.player[0] - ey) abs(self.player[1] - ex) for dy, dx in ((-1, 0), (1, 0), (0, -1), (0, 1)): ny, nx ey dy, ex dx if self.is_wall(ny, nx) or self.enemy_at(ny, nx): continue dist abs(self.player[0] - ny) abs(self.player[1] - nx) if dist best_dist: best_dist dist best_y, best_x ny, nx if best_y ey and best_x ex: continue if best_y self.player[0] and best_x self.player[1]: self.player_hp - 1 else: enemy.y, enemy.x best_y, best_x def is_over(self): return self.player_hp 0 or not self.enemies def render(self): os.system(cls if os.name nt else clear) grid [row[:] for row in self.grid] py, px self.player grid[py][px] PLAYER for enemy in self.enemies: grid[enemy.y][enemy.x] ENEMY print( - * (self.width * 4 - 1) ) for row in grid: print(| | .join(row) |) print( - * (self.width * 4 - 1) ) print(fPlayer HP: {self.player_hp} Enemies: {len(self.enemies)} Turn: {self.turns}) def run(self): while not self.is_over(): self.render() cmd input(WASD ).strip().lower() if cmd q: return if cmd not in DIRS: continue self.player_turn(cmd) if self.is_over(): break self.enemy_turn() self.turns 1 self.render() if not self.enemies: print(You win.) else: print(You lose.) if __name__ __main__: Game().run()运行命令python shove.py玩法的基本思路如下初始阶段不要主动贴近敌人先观察两个敌人的行动路线。把敌人引到墙边然后站到敌人的反方向位置。输入方向键让敌人被推向墙壁。敌人被推一次掉 1 点生命值初始 2 点生命值需要撞墙两次才能消灭。4. 和 Claude Fable 5 协作时真正要人工把关的地方4.1 提示词模板与需求拆解用 AI 辅助开发终端游戏时提示词越接近“需求文档”越好。模糊描述会得到非常空泛的结果。下面这个模板可以复用请帮我实现一个 Python 终端游戏。 功能要求 - 使用标准库不安装第三方依赖。 - 游戏地图是 7x5 的二维列表四周是墙。 - 玩家使用 WASD 移动遇到墙不能穿过。 - 玩家可以推动敌人敌人被推入墙时减少生命值。 - 敌人每回合向玩家靠近相邻时攻击玩家。 - 渲染时先复制地图再把玩家和敌人绘制到副本上。 - 增加回合数、玩家血量和剩余敌人数量的显示。 - 输入 q 退出。这个提示词有三个特点每一条都对应一个明确行为而不是笼统的“做一个有趣的游戏”。指定了渲染方式避免 AI 把单位直接写进地图导致坐标残留。指定了标准库和退出方式减少依赖和环境问题。4.2 人工核对清单AI 生成的代码能运行不代表逻辑正确。以下是我这次重点核对的地方行动顺序是否固定为玩家先、敌人后。推敌人撞墙时玩家是否移动。敌人后方有另一个敌人时是否被正确阻挡。所有索引是否在访问矩阵前先做了边界判断。胜利或失败后循环是否能正常退出。其中最容易出错的是“玩家是否移动”的问题。规则设定是推敌人撞墙时玩家不移动。原因在于敌人没有被推开玩家如果占据敌人原格就会和敌人重叠产生渲染混乱。AI 初版代码曾经写成“敌人撞墙扣血但玩家仍然移动到敌人原格”这导致玩家和敌人显示在同一格。人工核对后改成玩家保持原位这样才符合“撞不动”的直觉。4.3 为规则补测试小型 CLI 游戏也需要测试至少覆盖最核心的推击逻辑。下面是一些可以直接运行的测试用例使用pytest或 Python 自带的unittest都可以。from shove import Game, Enemy def test_wall_blocks_player(): game Game() game.player [1, 1] game.player_turn(a) assert game.player [1, 1] def test_push_enemy_into_empty(): game Game() game.player [1, 2] game.enemies [Enemy(1, 3)] game.player_turn(d) assert game.enemies[0].y 1 assert game.enemies[0].x 4 assert game.player [1, 3] def test_push_enemy_to_wall_reduces_hp(): game Game() game.player [1, 4] game.enemies [Enemy(1, 5)] old_hp game.enemies[0].hp game.player_turn(d) assert game.enemies[0].hp old_hp - 1 assert game.player [1, 4]这些测试的价值在于以后修改地图尺寸或加入新敌人类型时能第一时间发现推击规则被破坏。5. 运行验证与终端里的常见坑5.1 从零跑通的操作步骤完整跑通一次 Shove只需要四步mkdir shove cd shove # 将完整代码保存为 shove.py python shove.py进入游戏后输入小写w、a、s、d移动输入q退出。如果输入的是大写字母程序会通过.lower()自动转成小写。5.2 一局完整对局的输出启动后大概会看到这样的界面--------------------- | # | # | # | # | # | | # | P | . | E | . | | # | . | . | . | . | | # | . | . | E | . | | # | # | # | # | # | --------------------- Player HP: 3 Enemies: 2 Turn: 0 WASD当玩家把右侧敌人推到墙边一次后敌人会掉血但仍存活。再次推撞才能消灭。如果玩家血量为 0终端会显示失败如果敌人列表为空终端会显示胜利。5.3 常见问题排查问题现象常见原因检查方式处理建议输入方向键没有反应程序只识别 WASD不识别方向键检查输入字符是否是小写 wasd使用英文输入法输入 wasd或在代码中额外映射方向键字符python命令找不到系统默认 Python 版本不对执行python --version和python3 --version使用python3 shove.py敌人推到边界后程序崩溃索引越界在is_wall中加入越界判断把越界坐标直接视为墙统一返回True玩家和敌人显示在同一格推击撞墙后错误移动了玩家检查player_turn中撞墙分支撞墙时不要修改玩家坐标终端每次渲染有残留内容清屏指令不生效观察旧输出是否叠加Windows 使用cls其他平台使用clear或直接保留滚动输出6. 从原型到可维护设计Shove 还能怎么成长6.1 学习环境与生产环境的差别Shove 现在是一个适合学习和演示的原型。如果想让它在不同电脑上稳定运行或者把它发布成命令行工具至少还要做几件事把地图数据从代码中剥离改为读取文本关卡文件。把敌人 AI 独立成类方便替换成 BFS 或更复杂的策略。增加命令行参数例如--width、--height、--enemy来控制初始局面。增加日志或回放功能记录每一步输入和结果。这些改动不会让游戏更好玩但会让代码更容易测试和扩展。学习阶段不需要一次做完可以先保证原型可玩再逐步拆分。6.2 发布前的检查清单无论是否发布每次改完代码都可以用下面的清单快速自检检查项说明基础移动四个方向都能移动墙不能穿越推击分支空地、撞墙、被第二个敌人阻挡三条路径都验证敌人行为敌人能移动、能攻击、不会走出墙外胜负条件敌人清空后显示胜利血量归零后显示失败非正常输入空输入、大小写、q退出都不报异常跨平台至少在 Windows 和 Linux 或 macOS 中验证一次6.3 扩展方向Shove 的机制很小但扩展空间很大。这些方向可以按顺序尝试关卡文件化用文本文件描述墙和敌人位置实现多关卡。连锁推击让敌人被推后撞到另一个敌人产生连锁伤害。地形元素加入冰面、炸弹、传送门改变推击方向。敌人 AI 升级使用 BFS 绕过障碍或让敌人保持队形包围玩家。显示增强引入rich或textual把网格和生命值渲染得更清楚。对战回放记录每一步命令之后用--replay参数重复播放。如果第一次做终端游戏建议不要直接上复杂 AI。先把推击、撞墙、胜负和输入循环跑通再逐步增加机制。Claude Fable 5 可以帮你生成骨架但最终的可玩性判断还是要靠自己在终端里反复试玩。Shove 只用了不到两百行代码却已经形成了完整的回合制战术循环这也是 CLI 游戏最适合入门的原因反馈快、逻辑透明、出的问题都能一眼定位。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号