You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python如何在类中存储数据实现推箱子游戏的重启与撤销功能

问题根因

你遇到的多变量同步更新问题是Python可变对象的引用传递特性导致的:二维列表属于嵌套可变对象,直接赋值、浅拷贝都只会传递内存引用,修改任意一个引用指向的内容,所有关联变量都会同步变化。

解决思路

  1. 用深拷贝(copy.deepcopy)完成嵌套列表的独立复制,切断不同变量之间的内存关联
  2. 用栈结构存储每一步操作前的棋盘状态,支持撤销和重启功能
  3. 调整restart方法逻辑,直接修改当前实例的属性,不需要返回新实例(原有逻辑返回的新实例没有被main函数接收,会导致重启不生效)

完整修改代码

import copy

class Sokoban:
    """Your code here"""
    def __init__(self, board):
        # 深拷贝初始棋盘,避免和外部传入的列表共享引用
        self.__board = copy.deepcopy(board)
        # 深拷贝存储初始棋盘,供重启使用
        self.__original_board = copy.deepcopy(board)
        self.__steps = 0
        # 历史状态栈,存储每一步操作前的棋盘状态
        self.__history = []
        # 初始化玩家位置
        self.__position = self.find_player()

    # 你已实现的方法示例,保留原有逻辑即可
    def find_player(self):
        for row_idx, row in enumerate(self.__board):
            if 'P' in row:
                return (row_idx, row.index('P'))
        return (0,0)

    def complete(self):
        # 原有实现不变,判断所有箱子是否都在目标点
        for row in self.__board:
            if '#' in row:
                return False
        return True

    def get_steps(self):
        return self.__steps

    def move(self, direction):
        # 先把当前状态压入历史栈,再执行移动逻辑
        self.__history.append(copy.deepcopy(self.__board))
        # -------------------
        # 原有移动逻辑保留即可
        # -------------------
        self.__steps += 1
        self.__position = self.find_player()

    def restart(self):
        # 直接重置当前实例属性,不需要返回新对象
        self.__board = copy.deepcopy(self.__original_board)
        self.__steps = 0
        self.__history.clear()
        self.__position = self.find_player()

    def undo(self):
        # 历史栈为空时不执行撤销
        if not self.__history:
            return
        # 弹出最近一次状态覆盖当前棋盘
        self.__board = self.__history.pop()
        self.__steps -= 1
        self.__position = self.find_player()

    def __str__(self):
        # 实现打印棋盘的魔法方法,原有逻辑保留即可
        return '\n'.join(''.join(row) for row in self.__board) + '\n'


def main(board):
    game = Sokoban(board)
    message = 'Press w/a/s/d to move, r to restart, or u to undo'
    print(message)
    while not game.complete():
        print(game)
        move = input('Move: ').lower()
        while move not in ('w', 'a', 's', 'd', 'r', 'u'):
            print('Invalid move.', message)
            move = input('Move: ').lower()
        if move == 'r':
            game.restart()
        elif move == 'u':
            game.undo()
        else:
            game.move(move)
    print(game)
    print(f'Game won in {game.get_steps()} steps!')


test_board = [
    ['*', '*', '*', '*', '*', '*', '*', '*'],
    ['*', ' ', ' ', ' ', ' ', ' ', ' ', '*'],
    ['*', 'P', ' ', '#', ' ', ' ', ' ', '*'],
    ['*', '*', '*', '*', '*', ' ', '#', '*'],
    ['*', 'o', ' ', ' ', ' ', ' ', ' ', '*'],
    ['*', ' ', ' ', ' ', ' ', ' ', 'o', '*'],
    ['*', '*', '*', '*', '*', '*', '*', '*']
]
main(test_board)

内容的提问来源于stack exchange,提问作者ame

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 00:06:02