
本文讲解如何用二维列表重构战舰游戏棋盘,使玩家能通过输入行列坐标(如 a5、c2)精准选择并标记网格,解决单列表重复打印导致的状态不可控问题。
本文讲解如何用二维列表重构战舰游戏棋盘,使玩家能通过输入行列坐标(如 a5、c2)精准选择并标记网格,解决单列表重复打印导致的状态不可控问题。
在经典 Battleship(战舰)游戏中,一个核心交互是:玩家输入坐标(如 "B4" 或 "E7"),系统需准确识别该位置,并在棋盘上更新标记(如将 "#" 替换为 "X" 表示命中)。原始代码中仅使用单一 row 列表并循环打印 10 次,虽能显示 10×10 网格外观,但所有行实际引用同一内存地址——修改任意一行的某个元素,其余行同步变化,无法独立追踪每个格子状态。
✅ 正确做法:采用 10×10 二维列表(list of lists) 表示真实棋盘,每个单元格可独立读写:
# 初始化空棋盘:10 行 × 10 列,每个格子为 "#"(未探测) board = [["#" for _ in range(10)] for _ in range(10)]
这样 board[3][6] 就唯一对应第 4 行(索引 3)、第 7 列(索引 6)的格子,修改它不会影响其他位置。
接下来需支持用户以自然方式输入(如 "C5"),并转换为数组索引:
- 字母 'A'–'J' → 列索引 0–9(利用 str.upper() 统一大小写 + ord() 或字典映射)
- 数字 '0'–'9' → 行索引 0–9(注意:用户看到的第 1 行实际是 board[0])
完整坐标解析与标记示例:
def get_coordinate_input():
while True:
coord = input("Enter coordinate (e.g., A5, C2): ").strip()
if len(coord) < 2:
print("Invalid format. Use letter + number (e.g., B4).")
continue
col_char, row_str = coord[0], coord[1:]
if not col_char.isalpha() or not row_str.isdigit():
print("Letter and number required.")
continue
if col_char.upper() not in "ABCDEFGHIJ":
print("Column must be A–J.")
continue
row = int(row_str)
if not (0 <= row <= 9):
print("Row must be 0–9.")
continue
col = ord(col_char.upper()) - ord('A') # A→0, B→1, ..., J→9
return row, col
# 使用示例
row, col = get_coordinate_input()
board[row][col] = "X" # 标记为命中最后,重写 GameScreen() 中的打印逻辑,使其按真实二维结构渲染:
def print_board(board):
print(" A B C D E F G H I J")
for i, row in enumerate(board):
# 每行前加行号,格子间加空格对齐
row_display = f"{i} " + " ".join(f"{cell}" for cell in row)
print(row_display)
# 调用示例
print_board(board)⚠️ 注意事项:
- 原始代码中 row = [" # ", "# ", ...] 是浅拷贝陷阱:board = [row] * 10 会导致 10 行指向同一列表,务必用列表推导式生成独立子列表;
- 用户输入应做健壮校验(空格、大小写、越界),避免 IndexError;
- 后续扩展(如放置战舰、判断击沉、防重复点击)均依赖此二维结构,它是状态管理的基础。
通过以上重构,你不仅实现了“选择并标记网格”的基础功能,更构建了可扩展的游戏数据模型——这才是 Battleship 项目稳健演进的关键一步。


















