【问题标题】:undo operation implementation in 2048 game2048游戏中的undo操作实现
【发布时间】:2018-07-21 02:19:40
【问题描述】:

我已经用 C++ 实现了 2048 游戏,github 链接:2048

为了实现撤消操作,即回到之前的游戏状态,我维护了一个用于之前棋盘配置的矩阵,但如果我允许连续进行许多撤消操作,我就无法维护这么多矩阵。

有什么方法可以改进这种方法?

我认为的一种方法是只保留以前的移动(上、下、左或右),但如果我在这种方法中遗漏了某些东西,或者它可能是扩展,请提出一种方法来做到这一点。

【问题讨论】:

  • “我无法维持这么多矩阵。” 4x4 的数字矩阵只有几个字节大。
  • 这不是重点,我只是想减少空间,非常感谢您的帮助。
  • 每个棋盘状态的副本是 2048 年游戏历史的最紧凑表示。您不仅需要存储移动方向,还必须存储每个元素移动的距离,包括合并的元素对。
  • 一旦你认为你的游戏已经达到了“足够好”的状态,我建议你提交给CodeReview以获得反馈:)

标签: c++ undo game-theory 2048


【解决方案1】:

您可以将棋盘的当前状态存储到堆栈中,因此每次用户移动时,将更改棋盘状态,只需将其放入堆栈,这样您就会得到一个堆栈,其中包含棋盘当前状态的矩阵用户的动作和从最近的一个在顶部排序。因此,当您想撤消他们的最新操作时,只需从堆栈中弹出即可,这将为您提供他们最新的操作。

...
std::stack<std::array<int, 16>> boardStates;
std::array<16, int> currentBoardState;
// whenever user makes a move
makeMove(currentBoardState)

//when they want to undo    
tempBoardState = undoMove();
if(tempBoardState != nullptr)
{
   currentBoardState = tempBoardState;
}
else
{
   std::cout << "No previous move available" << std::endl
}
...

void makeMove(std::array<int, 16> currentState)
{
   boardStates.push(currentState);
}

std::array<int, 16> undoMove()
{
    if(!boardStates.empty())
    {
        return boardStates.pop();
    }

    return nullptr;
}

【讨论】:

    【解决方案2】:

    实现历史记录,以存储后续板状态更改。

    //maximum history size (can be whatever reasonable value)
    const int MAX_UNDO = 2048;
    
    //give a shorter name to the type used to store the board status
    typedef std::array<int, 16> snapshot; 
    
    //use a double ended queue to store the board statuses
    std::deque<snapshot> history;
    
    //this function saves the current status, has to be called each time 
    //the board status changes, i.e. after the board initialization 
    //and after every player move
    void save()
    {
        //make a copy of g, the current status
        snapshot f;
        std::copy(&g[0][0], &g[0][0] + 16, f.begin());
    
        //push the copy on top
        history.push_back(f); 
    
        //check history size
        if(history.size() > MAX_UNDO)
        {
            //remove one element at the bottom end
            history.pop_front();
        }
    }
    
    bool undo()
    {
        //history must hold at least one element 
        //other than the current status copy
        if(history.size() > 1)
        {
            //the top element of the queue always holds a copy of the 
            //current board status: remove it first
            history.pop_back(); 
    
            //now the top element is the previous status copy
            snapshot f = history.back();
    
            //copy it back to g
            std::copy(f.begin(), f.end(), &g[0][0]);
    
            //undo operation succedeed
            return true;
        }
    
        //undo operation failed
        return false;
    }
    

    【讨论】:

    • 我使用stack&lt;vector&lt;vector&lt;int&gt; &gt; &gt; 实现了它,如果我正在考虑撤消操作直到MAX_UNDO_LIMIT,您的方法很有用,有什么方法可以在不存储完整板信息的情况下重新生成以前的状态?
    • 正如它在 Effective C++ 中所说的,最好使用 const 和 inline 而不是 #define
    • 啊啊啊...谢谢。当您在这里时,请注意您的代码,因为它无法编译(std::stack::pop 无效)并且逻辑明显被破坏(撤消时,板状态不会改变)。但是,嘿,没有#define 的...
    • 你不喜欢批评,是吗 :p -- 不过我看不出这里有什么值得 DV 的。附加说明:如果 OP 切换到std::array,则推送和弹出将是history.push_back(g)g = history.back(),这样更舒服。
    • @p-a-o-l-o 我刚刚分享了 Scott Meyer 的一个很好的做法,至少说明了为什么我不赞成而不是反对,并且没有提到我反对的原因。感谢您对 pop() 的警告
    猜你喜欢
    • 2020-02-12
    • 1970-01-01
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 2015-02-10
    相关资源
    最近更新 更多