CSCE1035课程Python战舰游戏select_and_assign_vessels函数卡顿求助
CSCE 1035战舰游戏问题修复方案
问题概述
开发Python版战舰游戏时,菜单可正常显示,create_board函数执行正常,但select_and_assign_vessels函数会卡在第一艘船的分配环节,无法完成放置,同时存在其他逻辑错误导致游戏无法正常运行,计划将修复方案分享给同班同学。
核心问题修复(卡死原因)
select_and_assign_vessels函数的两个致命错误导致循环无法退出:
- 棋盘初始值不匹配:
create_board生成的棋盘单元格值为'empty',但代码中检查重叠时用的是board[ship1_row][i] != '-',永远不会匹配,导致判定重叠为True,循环无限重试。 - 范围检查越界:检查重叠时用了
range(ship1_col, ship1_col + ship1['length'] + 1),多了一个额外的位置,可能超出棋盘范围或者错误检查不属于船只的位置,进一步导致无法找到合法位置。
修复方式:
- 将重叠检查的判定改为
board[ship1_row][i] != 'empty' - 移除范围中的
+1,改为range(ship1_col, ship1_col + ship1['length'])(垂直方向同理)
其他关键问题修复
game_board函数显示逻辑错误:- 代码中判断
col == 'C'等符号,但select_and_assign_vessels给棋盘赋值的是船只名称(如'aircraft carrier'),应改为判断船只名称 - 错误使用
col['X'](字符串不能用字典索引),调整为根据解决方案模式直接显示对应符号
- 代码中判断
fire_missile函数逻辑错误:- 输入的row是字母(A-H),需要转换为数字索引(0-7);col是字符串数字,需要转换为int
- 无法直接访问
select_and_assign_vessels.vessels,需让select_and_assign_vessels返回vessels字典 - 修改全局变量
missles和ships_total时需加global声明,否则会创建局部变量 - 检查是否已射击的条件错误,应判断单元格是否为
'hit'或'miss' - 新增船只坐标记录,在
select_and_assign_vessels中为每艘船添加'coordinates'列表,记录所有占据的单元格
play_game函数逻辑错误:- 循环条件错误:
while ships_total == 2 or missles != 0应改为while ships_total > 0 and missles > 0,否则游戏会提前结束或无限运行 - 输入验证错误:
row != ['A', ...]应改为row not in ['A','B','C','D','E','F','G','H'],且处理大小写问题 - 新增输入转换失败的处理逻辑,避免非法输入导致崩溃
- 循环条件错误:
完整修复代码
import random ships_total = 2 missles = 20 # 创建一个新的8x8游戏板,供其他函数使用 def create_board(): new_board = [] for i in range(8): row = ['empty'] * 8 new_board.append(row) return new_board # 使用新创建的游戏板打印并填充内容 def game_board(board, solution=False): # 为函数提供一个用于游戏板的符号字典 symbols = { 'empty': '-', 'miss': 'O', 'hit': 'X', 'aircraft carrier': 'C', 'battleship': 'B', 'submarine': 'S', 'destroyer': 'D' } # 打印带列标签的顶行 print(' ', end=' ') for i in range(8): print(str(i), end=' ') print() # 遍历游戏板的每一行和每一列 for i, row in enumerate(board): print(chr(i + ord('A')), end=' ') for col in row: if col in symbols: if solution: print(symbols[col], end=' ') else: if col == 'hit' or col == 'miss': print(symbols[col], end=' ') else: print(symbols['empty'], end=' ') else: print(symbols['empty'], end=' ') print() def select_and_assign_vessels(board): # 定义船只及其属性 vessels = { 'aircraft carrier': {'name': 'aircraft carrier', 'length': 5, 'hits': 5, 'coordinates': []}, 'battleship': {'name': 'battleship', 'length': 4, 'hits': 4, 'coordinates': []}, 'submarine': {'name': 'submarine', 'length': 3, 'hits': 3, 'coordinates': []}, 'destroyer': {'name': 'destroyer', 'length': 2, 'hits': 2, 'coordinates': []} } # 随机选择第一艘船及其朝向 ship1_name = random.choice(['aircraft carrier', 'battleship']) ship1 = vessels[ship1_name] ship1['orientation'] = random.choice(['horizontal', 'vertical']) # 放置第一艘船到游戏板 while True: # 随机选择起始行和列 ship1_row = random.randint(0, len(board) - 1) ship1_col = random.randint(0, len(board[0]) - 1) # 检查船只是否能放在游戏板上 if ship1['orientation'] == 'horizontal' and ship1_col + ship1['length'] <= len(board[0]): overlap = False # 检查船只是否与已有船只重叠 for i in range(ship1_col, ship1_col + ship1['length']): if board[ship1_row][i] != 'empty': overlap = True break if not overlap: # 将船只分配到游戏板并记录坐标 for i in range(ship1_col, ship1_col + ship1['length']): board[ship1_row][i] = ship1_name ship1['coordinates'].append((ship1_row, i)) break elif ship1['orientation'] == 'vertical' and ship1_row + ship1['length'] <= len(board): overlap = False # 检查船只是否与已有船只重叠 for i in range(ship1_row, ship1_row + ship1['length']): if board[i][ship1_col] != 'empty': overlap = True break if not overlap: # 将船只分配到游戏板并记录坐标 for i in range(ship1_row, ship1_row + ship1['length']): board[i][ship1_col] = ship1_name ship1['coordinates'].append((i, ship1_col)) break # 如果船只放不下或重叠,重试 else: continue # 随机选择第二艘船及其朝向 ship2_name = random.choice(['submarine', 'destroyer']) ship2 = vessels[ship2_name] ship2['orientation'] = random.choice(['horizontal', 'vertical']) # 放置第二艘船到游戏板 while True: # 随机选择起始行和列 ship2_row = random.randint(0, len(board) - 1) ship2_col = random.randint(0, len(board[0]) - 1) # 检查船只是否能放在游戏板上 if ship2['orientation'] == 'horizontal' and ship2_col + ship2['length'] <= len(board[0]): overlap = False # 检查船只是否与已有船只重叠 for i in range(ship2_col, ship2_col + ship2['length']): if board[ship2_row][i] != 'empty': overlap = True break if not overlap: # 将船只分配到游戏板并记录坐标 for i in range(ship2_col, ship2_col + ship2['length']): board[ship2_row][i] = ship2_name ship2['coordinates'].append((ship2_row, i)) break elif ship2['orientation'] == 'vertical' and ship2_row + ship2['length'] <= len(board): overlap = False # 检查船只是否与已有船只重叠 for i in range(ship2_row, ship2_row + ship2['length']): if board[i][ship2_col] != 'empty': overlap = True break if not overlap: # 将船只分配到游戏板并记录坐标 for i in range(ship2_row, ship2_row + ship2['length']): board[i][ship2_col] = ship2_name ship2['coordinates'].append((i, ship2_col)) break else: continue return vessels def fire_missile(row_idx, col_idx, board, vessels): global missles, ships_total cell = board[row_idx][col_idx] if cell == 'hit' or cell == 'miss': print('Missile already fired at this location!') return board, vessels hit = False for vessel in vessels.values(): if (row_idx, col_idx) in vessel['coordinates']: print(f'You hit the {vessel["name"]}!') vessel['hits'] -= 1 missles -= 1 if vessel['hits'] == 0: print(f'You sank the {vessel["name"]}!') ships_total -= 1 board[row_idx][col_idx] = 'hit' hit = True break if not hit: print('You missed!') missles -= 1 board[row_idx][col_idx] = 'miss' return board, vessels def play_game(): global ships_total, missles game_on = True # 打印标题栏 print('+--------------------------------------------------------+') print('| Computer Science and Engineering |') print('| CSCE 1035 - Computer Programming I |') print('| |') print('+--------------------------------------------------------+') print('Welcome to BattleShip! Here\'s how to play: a board will be') print('generated that contains two hidden ships somewhere on it. You') print('will be given 20 missles to try and sink both ships. Both ships') print('will require multiple shots to take down depending on their') print('length. You will enter your shots using a letter A-H and a number') print('0-7 you will be told if your missles hit and or miss and the board') print('will show you as well. Well thats all have fun!!') while game_on: print('Would you like to play a game?') print('******************* M E N U *****************+') print('| Select a service: |') print('| 1. New Game |') print('| 2. New Game (dev mode) |') print('| 3. Exit/Logout |') print('*********************************************+') selection = input('Make your choice: ') if selection.isdigit() and (1 <= int(selection) <= 3): selection = int(selection) if selection == 1 or selection == 2: # 重置全局变量 ships_total = 2 missles = 20 new_game_board = create_board() vessels = select_and_assign_vessels(new_game_board) print('Game Start!') game_board(new_game_board, solution=(selection==2)) while ships_total > 0 and missles > 0: print(f'Remaining missiles: {missles} | Remaining ships: {ships_total}') # 处理行输入 while True: row = input('Enter the row you\'d like to target (A-H): ').upper() if row in ['A','B','C','D','E','F','G','H']: row_idx = ord(row) - ord('A') break else: print('Invalid row! Please enter a letter from A to H.') # 处理列输入 while True: col = input('Enter the column you\'d like to target (0-7): ') if col.isdigit() and 0 <= int(col) <=7: col_idx = int(col) break else: print('Invalid column! Please enter a number from 0 to 7.') new_game_board, vessels = fire_missile(row_idx, col_idx, new_game_board, vessels) game_board(new_game_board, solution=(selection==2)) # 游戏结束提示 if ships_total == 0: print('Congratulations! You sank all ships!') else: print('Game over! You ran out of missiles.') elif selection ==3: print('Exiting game. Goodbye!') game_on = False else: print('Invalid selection! Please enter 1, 2, or 3.') if __name__ == '__main__': play_game()
备注
- 修复后的代码支持正常的船只放置、射击判定、游戏结束逻辑
- 开发模式(选项2)会显示所有船只位置,方便调试
- 输入验证逻辑完善,处理了非法输入的情况
内容的提问来源于stack exchange,提问作者Derek Xavier
相关产品推荐
相关产品推荐

