Python战舰游戏generate_nship函数保存状态恢复失效问题
战舰游戏generate_*ship函数问题修复
核心问题分析
- 部分放置后才回滚:当前代码逐个位置检查并放置舰船,遇到冲突时已修改棋盘部分位置,且
savestate = board.copy()是浅拷贝(仅复制外层列表,内部列表仍为引用),回滚操作无效,递归重启函数时原棋盘已被部分修改。 - sum获取单个元素的错误:用
sum(pos[1])获取列表单个元素完全逻辑错误,仅因pos[1]是单元素列表巧合运行,正确做法是直接通过索引取元素,如pos[1][0]。 - 棋盘初始化重复添加:
print_board和print_pboard每次调用都会向棋盘添加新行,导致棋盘尺寸异常增大。
修复步骤及代码修改
1. 分离棋盘初始化与打印逻辑
单独写初始化函数,避免打印时修改棋盘:
def init_board(): return [["O"] * 10 for _ in range(10)] board = init_board() pboard = init_board()
2. 抽象通用舰船生成函数
消除重复代码,先校验所有放置坐标是否可用,再批量放置,避免部分修改棋盘:
def generate_ship(board, length): while True: orientation = random.choice(["horizontal", "vertical"]) coords = [] if orientation == "horizontal": # 水平放置时,x起始位置需保证能放下整艘船 x_start = random.randint(length - 1, 9) y = random.randint(0, 9) for i in range(length): coords.append((x_start - i, y)) else: # 垂直放置时,y起始位置需保证能放下整艘船 x = random.randint(0, 9) y_start = random.randint(length - 1, 9) for i in range(length): coords.append((x, y_start - i)) # 检查所有坐标是否为空白 if all(board[x][y] == "O" for x, y in coords): # 批量放置舰船 for x, y in coords: board[x][y] = str(length) break
3. 简化fill_board函数
调用通用生成函数替代多个重复的generate_nship:
def fill_board(): generate_ship(board, 5) generate_ship(board, 4) generate_ship(board, 4) generate_ship(board, 3) generate_ship(board, 3) generate_ship(board, 3) generate_ship(board, 2) generate_ship(board, 2) generate_ship(board, 2) generate_ship(board, 2)
4. 修复打印函数
让打印函数仅负责输出棋盘,不修改数据:
def print_board(board): print("Enemy Board:") print(" " + " ".join(col)) for idx, row_data in enumerate(board): print(f"{row[idx]} " + " ".join(row_data)) def print_pboard(board): print("Your Board:") print(" " + " ".join(col)) for idx, row_data in enumerate(board): print(f"{row[idx]} " + " ".join(row_data))
5. 修正命中判断逻辑
原代码命中判断条件错误,修复后正确识别舰船并标记:
def is_hit(x, y): if board[x][y] != "O" and board[x][y] != "X": print("Hit!") pboard[x][y] = "X" board[x][y] = "X" elif pboard[x][y] == "X": print("Already hit!") else: print("Miss!") pboard[x][y] = "M"
修复后的完整代码
import random row = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] col = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] def init_board(): return [["O"] * 10 for _ in range(10)] board = init_board() pboard = init_board() def print_board(board): print("Enemy Board:") print(" " + " ".join(col)) for idx, row_data in enumerate(board): print(f"{row[idx]} " + " ".join(row_data)) def print_pboard(board): print("Your Board:") print(" " + " ".join(col)) for idx, row_data in enumerate(board): print(f"{row[idx]} " + " ".join(row_data)) print("Welcome to Battleship!") def get_coords(): coord = str(input("Enter coordinates (e.g., A1): ").upper()) if len(coord) == 3: if coord[2] == "0": return row.index(coord[0]), 9 if len(coord) != 2: print("Invalid input. Please enter a letter followed by a number (e.g., A1).") return get_coords() if coord[0] not in row or not coord[1].isdigit() or int(coord[1]) < 1 or int(coord[1]) > 10: print("Invalid coordinates. Please try again.") return get_coords() return row.index(coord[0]), int(coord[1]) - 1 def generate_ship(board, length): while True: orientation = random.choice(["horizontal", "vertical"]) coords = [] if orientation == "horizontal": x_start = random.randint(length - 1, 9) y = random.randint(0, 9) for i in range(length): coords.append((x_start - i, y)) else: x = random.randint(0, 9) y_start = random.randint(length - 1, 9) for i in range(length): coords.append((x, y_start - i)) if all(board[x][y] == "O" for x, y in coords): for x, y in coords: board[x][y] = str(length) break def fill_board(): generate_ship(board, 5) generate_ship(board, 4) generate_ship(board, 4) generate_ship(board, 3) generate_ship(board, 3) generate_ship(board, 3) generate_ship(board, 2) generate_ship(board, 2) generate_ship(board, 2) generate_ship(board, 2) def is_hit(x, y): if board[x][y] != "O" and board[x][y] != "X": print("Hit!") pboard[x][y] = "X" board[x][y] = "X" elif pboard[x][y] == "X": print("Already hit!") else: print("Miss!") pboard[x][y] = "M" def get_win_condition(): for i in range(10): for j in range(10): if board[i][j] not in ["O", "X"]: return False return True def get_misses(): misses = 0 for i in range(10): for j in range(10): if pboard[i][j] == "M": misses += 1 return misses def get_hits_left(): hits_left = 0 for i in range(10): for j in range(10): if board[i][j] not in ["O", "X"]: hits_left += 1 return hits_left fill_board() while True: print_board(board) x, y = get_coords() is_hit(x, y) print_pboard(pboard) hits_left = get_hits_left() print(f"Hits left: {hits_left}") if get_win_condition(): print("You win!") print(f"You missed {get_misses()} times!") break print("Game Over!")
关键修改说明
- 通用生成函数彻底解决了部分放置后回滚的问题,先校验所有坐标再批量放置。
- 移除了错误的sum用法,直接生成坐标元组,逻辑更清晰。
- 分离初始化与打印逻辑,避免棋盘尺寸异常。
- 修正了命中判断的逻辑错误,确保正确识别舰船命中状态。
内容的提问来源于stack exchange,提问作者user30229020
相关产品推荐
相关产品推荐

