there's different ways of implementing undoing, some more simpler than others, but the main ones are:
- storing a copy of the level every time a move is made
- easiest to implement but can be very memory intensive depending on complexity and how many moves overall
- keeping track of the deltas/changes (or having the inverse of a specific action)
- harder to implement and manage but uses less memory and may be faster
really depends on what you want to do and what's happening in the puzzle (like with complexity)
for your game the former would work best