在瓷砖匹配游戏逻辑中使用 STL 算法

Posted

技术标签:

【中文标题】在瓷砖匹配游戏逻辑中使用 STL 算法【英文标题】:Use of STL algorithms in a tile matching game logic 【发布时间】:2018-04-15 23:44:13 【问题描述】:

我制作了一个拼图游戏。它有一个 Board 对象,其中包含卡片对象的向量并将事件委托给它们。 Board 事件处理中包含以下代码:

// Counting logic-driving card states
int cardFaceUpCounter = 0;
std::vector<Card*> faceUpCards(2);

// Checking for logic-driving card states 
for (auto& card : this->boardMatrix)

    if (this->isCardInAnim(&card))
    
        return;
    
    if (this->isCardFaceUp(&card))
    
        ++cardFaceUpCounter;
        faceUpCards[cardFaceUpCounter - 1] = &card;
           

我刚刚在 Pluralsight 上完成了 Kate Gregory 的 Beautiful C++ 学习。 她认为我们应该避免编写循环,并且应该尽可能地使用 STL 算法头。 我发现她的论点和方法非常有说服力,因此我尝试重构我最新的宠物项目以反映她的教义。

上面的示例是我无法看到如何使用 STL 算法来更好地传达意图并保持性能 - 单个循环而不是两个或三个循环,尽管隐藏在算法调用中。

第二个问题是,如果使用 STL 算法无法实现单循环效率,出于可读性的考虑,您是否仍然更喜欢这种方法。

【问题讨论】:

你为什么期待两张而且只有两张正面朝上的牌?你可以把它写成一个容器到另一个容器的标准转换。 我的游戏被设置成任何时候只能出两张牌。事件只能触发一个卡牌回合,因此如果检测到两张卡牌,下一个事件(点击),如果相同则丢弃它们,如果不同则将它们返回。 通常最好使用push_back,以防您的假设错误。此外,它使您的算法更通用。 如果我的假设是错误的,我的游戏逻辑就会中断,如果我的代码中断比逻辑中断,我更容易找到错误。但我会进一步研究你的评论。真诚的感谢。 另外,你认为我的推理有效吗? 【参考方案1】:

这是我的想法的一个例子。

int cardFaceUpCounter = 0;
std::vector<Card*> faceUpCards(2);

if (std::any_of(boardMatrix.begin(), boardMatrix.end(), [&](auto& card) 
    if (isCardFaceUp(&card))
        faceUpCards[cardFaceUpCounter++] = &card;

    return isCardInAnim(&card);    
)) return;

【讨论】:

哇,太好了 :) 我会在早上接受它,当我要深入研究这个问题时。谢谢 :) 为了完整起见,您可以添加 if(any_of()) return;因为动画打破了我的循环。 我认为这回答了我的第一个问题。但是你认为这段代码比我写的更具可读性吗?我知道这是我要求的意见,但有时你不能没有他们:) 我尝试写一些更有表现力的东西,但我最终写了一个 find_all func,一个 std::find_if 在一个保存到向量的循环中。这似乎不值得麻烦。 @AntonioDropulić 既然你想结束外部函数,我可能会自己去一个循环。 我会避免在std::any_of 中使用副作用。【参考方案2】:

使用range-v3,会是这样的:

std::vector<Card*> faceUpCards = this->boardMatrix
    | ranges::view::take_while([this](const auto& card) return !isCardInAnim(&card);)
    | ranges::view::filter([this](const auto& card) return isCardFaceUp(&card); )
    | ranges::view::transform([](auto& e) return &e; );

仅使用 STL,我会执行以下操作:

auto it = std::find_if(boardMatrix.begin(), boardMatrix.end(),
                       [this](const auto& card) return isCardInAnim(&card););
std::vector<Card*> faceUpCards(std::distance(boardMatrix.begin(), it), nullptr);
std::transform(boardMatrix.begin(), it,
               faceUpCards.begin(),
               [](auto& card) return &card;);
faceUpCards.erase(std::remove_if(faceUpCards.begin(), faceUpCards.end(),
                                [this](const auto& card) return !isCardFaceUp(&card); ),
                  faceUpCards.end());

【讨论】:

告诉我如果我读你的代码很好。您希望所有正面朝上的卡片都在 begin 和 card in anim 之间,并且您希望 begin 和 card in anim 之间的所有卡片都向上。还要感谢范围示例,但我目前正在尝试掌握 STL - 新手问题:) 我支持范围 - v3 lib,不确定 stl 示例是否正确。 确实,我错过了关于isCardFaceUp 的两种情况的过滤。固定。

以上是关于在瓷砖匹配游戏逻辑中使用 STL 算法的主要内容,如果未能解决你的问题,请参考以下文章

小白学游戏常用算法一随机迷宫算法

两年游戏经历

详解 C 语言开发五子棋游戏以及游戏中的重要算法与思路

如何在糖果迷之类的游戏中为瓷砖分配颜色

瓷砖块在pygame平台游戏中呈现隐形

游戏引擎架构