How can I implement an "undo move" function in a grid-based puzzle game where I need to keep track of multiple objects?

tldr; In my game, every time the player moves one tile, different objects make different moves at the same time. How can I keep track of every single one and undo all of them one move back at the same time?

I’m making a puzzle game where you move around in a grid-based space, i.e. like a checkerboard. The player character can move one tile at a time using the arrow keys. I want the player to be able to undo their moves if they make a mistake, get stuck etc.

Now, if it were only for the player character, making an undo function is easy, I’ve already made it actually. I basically use the command pattern to record the character’s position every time it moves, and add them to a Stack. When I want to undo, I just delete the last item on the stack and call the one before it. However, in my game, there is more stuff happening on different objects with each move of the player.

For example, there are doors that open and close every time the player moves. There are also collapsing tiles which disappear after the player steps onto them and steps off. There are also special blocks which move the opposite way as the player i.e. if the player moves up, the block moves down, if the player moves right, the block moves left etc.

So as you can see, I have a lot of elements that I need to keep track of, and there’s also the case of the player “dying”. Instead of having to restart the level all over, I would like to give the player the chance to undo just one mistake so that they can continue where they left off. But I don’t know how to keep track of every element’s behaviour every time the player moves, let alone how to undo them at the same time.

I’ve heard about using .json files but I don’t know if that would work or how I could implement that. I would appreciate any kind of help! Thank you very much!