构建战舰游戏首先需要定义游戏的基本元素和初始化流程。这包括欢迎玩家、创建游戏地图、以及玩家和电脑船只的初始部署。
1.1 用户欢迎与地图创建游戏开始时,首先获取玩家昵称并显示欢迎信息。游戏地图通过二维列表表示,初始状态下所有格子均为空(_)。
from random import randrange # 船只类型定义 ship_initial = ["B", "C", "F", "A", "S"] ship_names = ["Battleship", "Cruiser", "Frigate", "Aircraft Carrier", "Sub"] map_size = 10 # 地图大小 def get_username(): """获取玩家昵称""" while True: user_name = input("请输入您的名字: ") if user_name: print(f"欢迎来到战舰游戏, {user_name}!") return user_name else: print("请勿输入空值。") def create_battlefield(size): """根据指定大小创建游戏地图""" return [["_"] * size for _ in range(size)] def display_battlefield(board): """显示当前地图状态""" for row in board: print(" ".join(row))1.2 玩家与电脑船只部署
玩家手动输入坐标放置船只,电脑则随机放置。为避免船只重叠,玩家放置时需检查坐标是否已被占用;电脑放置时则需确保目标格子为空。
def player_ship_coordinate(player_board, occupied_coords): """ 玩家手动放置船只。 参数: player_board: 玩家自己的地图。 occupied_coords: 一个集合,存储已被占用的坐标,防止船只重叠。 """ print("请放置您的船只:") for i, ship_name in enumerate(ship_names): while True: try: row = int(input(f"请输入 {ship_name} 的行坐标 (0-9): ")) col = int(input(f"请输入 {ship_name} 的列坐标 (0-9): ")) if 0 <= row < map_size and 0 <= col < map_size and (row, col) not in occupied_coords: player_board[row][col] = ship_initial[i] occupied_coords.add((row, col)) break else: print("无效坐标或该位置已被占用。请重新输入。") except ValueError: print("输入无效。请输入一个整数。") return player_board, occupied_coords def comp_ship_coordinate(comp_board): """ 电脑随机放置船只。 参数: comp_board: 电脑的地图。 """ for ship_char in ship_initial: while True: row = randrange(0, map_size) col = randrange(0, map_size) if comp_board[row][col] == "_": comp_board[row][col] = ship_char break return comp_board2. 实现回合制游戏循环
游戏的核心是回合制循环,玩家和电脑轮流攻击,直到一方所有船只被击沉。
2.1 游戏主循环结构在 if __name__ == "__main__": 块中,我们初始化游戏并进入一个无限循环,直到有玩家获胜。player_hits 和 comp_hits 变量用于跟踪双方击沉的船只数量。
if __name__ == "__main__": user = get_username() player_board = create_battlefield(map_size) comp_board = create_battlefield(map_size) dummy_board = create_battlefield(map_size) # 玩家视角的电脑地图,初始为空 occupied_coords = set() print("\n玩家部署船只:") player_ship_coordinate(player_board, occupied_coords) print("\n您的战场:") display_battlefield(player_board) print("\n电脑部署船只:") comp_ship_coordinate(comp_board) # display_battlefield(comp_board) # 测试时可以显示电脑地图,实际游戏中应隐藏 print("\n电脑的战场 (您的攻击目标):") display_battlefield(dummy_board) # 玩家只能看到虚拟地图 player_hits = 0 # 玩家击中电脑船只的数量 comp_hits = 0 # 电脑击中玩家船只的数量 while True: print(f"\n--- {user} 的回合 ---") # 玩家攻击 hit_status = check_player_hit(comp_board, dummy_board, user) player_hits += hit_status print("\n电脑的战场 (您的攻击结果):") display_battlefield(dummy_board) if player_hits == len(ship_initial): # 如果玩家击沉所有船只 print(f"\n恭喜 {user},您击沉了所有敌舰,赢得游戏!") break print("\n--- 电脑的回合 ---") # 电脑攻击 hit_status = check_comp_hit(player_board) comp_hits += hit_status print("\n您的战场 (电脑的攻击结果):") display_battlefield(player_board) if comp_hits == len(ship_initial): # 如果电脑击沉所有船只 print("\n很遗憾,电脑击沉了您的所有船只,电脑赢得游戏!") break3. 玩家射击与“虚拟”敌方战场
为了提供更好的游戏体验,玩家不应直接看到电脑的船只部署。我们引入一个“虚拟战场”(dummy_board),它只显示玩家的攻击结果(命中或未命中)。
3.1 check_player_hit 函数这个函数负责处理玩家的攻击。它接收电脑的真实地图 (comp_board) 和玩家视角的虚拟地图 (dummy_board)。
- 玩家输入攻击坐标。
- 根据 comp_board 判断是否命中。
- 如果命中,dummy_board 对应位置标记为 'X',comp_board 上的船只标记为小写字母(表示已击中)。
- 如果未命中,dummy_board 对应位置标记为 '*'。
- 函数返回 1 表示命中,0 表示未命中。
def check_player_hit(comp_board, dummy_board, user_name): """ 玩家攻击敌方船只。 参数: comp_board: 电脑的真实地图。 dummy_board: 玩家可见的虚拟地图。 user_name: 玩家昵称,用于提示信息。 返回: 1 表示命中,0 表示未命中。 """ while True: try: print(f"{user_name},请选择您的攻击坐标。") row = int(input("请输入攻击的行坐标 (0-9): ")) col = int(input("请输入攻击的列坐标 (0-9): ")) if 0 <= row < map_size and 0 <= col < map_size: # 检查是否重复攻击同一位置 if dummy_board[row][col] != '_' : print("您已经攻击过这个位置了。请选择其他坐标。") continue break else: print("无效坐标。请重新输入 (0-9)。") except ValueError: print("输入无效。请输入一个整数。") hit = 0 # 默认未命中 target_char = comp_board[row][col] if target_char in ship_initial: # 命中船只 comp_board[row][col] = target_char.lower() # 标记为已击中(小写) dummy_board[row][col] = "X" # 虚拟地图显示命中 print(f"命中!电脑的 {ship_names[ship_initial.index(target_char)]} 被击中了!") hit = 1 else: # 未命中 dummy_board[row][col] = "*" # 虚拟地图显示未命中 print("未命中!") return hit4. 电脑AI射击逻辑
电脑的攻击需要一定的智能性,至少要避免重复攻击已命中或已尝试过的位置。
4.1 check_comp_hit 函数这个函数处理电脑的攻击。
- 电脑随机选择一个坐标,但会确保该坐标之前未被攻击过(即不是 '*' 或已击中的小写船只字符)。
- 根据 player_board 判断是否命中。
- 如果命中,player_board 上的船只标记为小写字母。
- 如果未命中,player_board 对应位置标记为 '*'。
- 函数返回 1 表示命中,0 表示未命中。
def check_comp_hit(player_board): """ 电脑攻击玩家船只。 参数: player_board: 玩家的真实地图。 返回: 1 表示命中,0 表示未命中。 """ hit = 0 # 默认未命中 while True: # 随机选择一个未曾攻击过的位置 row = randrange(0, map_size) col = randrange(0, map_size) # 确保电脑不会重复攻击已经命中或尝试过的位置 if player_board[row][col] not in ["*", "a", "b", "c", "f", "s"]: break print(f"电脑选择了坐标 ({row}, {col}) 进行攻击。") target_char = player_board[row][col] if target_char in ship_initial: # 命中船只 player_board[row][col] = target_char.lower() # 标记为已击中(小写) print(f"您的 {ship_names[ship_initial.index(target_char)]} 被击中了!") hit = 1 else: # 未命中 player_board[row][col] = "*" # 标记为未命中 print("电脑未命中!") return hit5. 游戏胜利条件判断
游戏胜利的条件是当一方击沉了对方所有船只。在本教程中,我们假设每艘船只占据一个格子,共有5艘船。因此,当 player_hits 或 comp_hits 达到5时,游戏结束。
在主游戏循环中,每次攻击后都会检查胜利条件:
# ... (玩家攻击代码) ... player_hits += hit_status # ... (显示玩家视角电脑地图) ... if player_hits == len(ship_initial): # 如果玩家击沉所有船只 print(f"\n恭喜 {user},您击沉了所有敌舰,赢得游戏!") break # ... (电脑攻击代码) ... comp_hits += hit_status # ... (显示玩家地图) ... if comp_hits == len(ship_initial): # 如果电脑击沉所有船只 print("\n很遗憾,电脑击沉了您的所有船只,电脑赢得游戏!") break6. 注意事项与代码优化建议
- 错误处理增强: 当前代码已包含基本的 try-except 进行输入验证,但可以进一步细化,例如对玩家输入坐标的范围进行更严格的检查,并提供更友好的提示。
- 船只大小与方向: 现有实现中所有船只都只占据一个格子。要实现更真实的战舰游戏,需要扩展船只类,使其具有长度和方向(水平或垂直),并在放置船只时进行碰撞检测和边界检查。
- 游戏状态管理: 可以引入一个更复杂的船只对象来管理每艘船的状态(如生命值、是否被击沉),而不是仅仅通过地图上的字符变化来判断。
- 更智能的电脑AI: 当前电脑AI只是随机攻击未曾攻击过的位置。更高级的AI可以在击中船只后,优先攻击相邻的格子,以“追踪”并击沉船只。
- 用户界面: 对于命令行游戏,可以考虑使用ANSI转义序列来为输出添加颜色,提升可读性。如果希望更复杂的界面,可以考虑使用Pygame等图形库。
- 模块化: 随着游戏复杂度的增加,可以将不同的功能(如船只管理、玩家操作、电脑AI)拆分到不同的模块或类中,提高代码的可维护性。例如,可以创建 Ship 类、Player 类和 Computer 类。
- 代码可读性: 确保变量命名清晰,函数功能单一,并添加足够的注释。
通过本教程,我们构建了一个Python战舰游戏的基础框架,涵盖了从游戏初始化、船只部署到回合制战斗循环和胜利条件判断的核心逻辑。关键改进包括引入“虚拟战场”以隐藏电脑船只位置,以及优化电脑AI使其避免重复攻击。这个基础版本为进一步扩展和提升游戏体验奠定了坚实的基础,例如实现多格船、更复杂的AI策略以及图形用户界面等。
以上就是Python战舰游戏开发教程:构建核心游戏循环与智能命中检测的详细内容,更多请关注知识资源分享宝库其它相关文章!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。