模拟一堆卡片的最佳容器

Posted

技术标签:

【中文标题】模拟一堆卡片的最佳容器【英文标题】:Optimal container to simulate a pile of card 【发布时间】:2015-08-10 21:59:35 【问题描述】:

我正在实现一个游戏,我正在寻找一个合适的容器来模拟一堆卡片。

强制条件:

    容器可以随机打乱(需要random iterators,不包括std::list) 容器可以分类 可以弹出第一个元素(从顶部抽一张牌) 可以在末尾插入元素(将卡片丢弃到底部)

到目前为止,我使用的是std::vector<District>,其中District 是代表卡值的enum class

Live demo

#include <vector>
#include <algorithm>

namespace Citadel

    enum class District
    
        UNINITIALIZED,
        FORTRESS,
        MANOR,
        // etc
    ;

    class DistrictDeck
    
    public:
        void Setup(const std::vector<District>& availableDistricts)
        
            // Simplified filling...
            for (const auto district : availableDistricts)
            
                pileOfCards_.push_back(district);
            

            // Once all cards have been pushed, shuffle them
            std::random_shuffle(std::begin(pileOfCards_), std::end(pileOfCards_));
        

        // Pick a district card from top of the stack
        District Draw()
        
            District district = District::UNINITIALIZED;

            if (pileOfCards_.size() > 0)
            
                district = pileOfCards_.front();
                pileOfCards_.erase(std::begin(pileOfCards_));
            

            return district;
        

        // Put a district card below the bottom of the stack
        void Discard(const District district)
        
            pileOfCards_.push_back(district);
        

    private:
        std::vector<District> pileOfCards_;
    ;


int main()


在我的确切情况下,哪个容器可以替换 std::vector

【问题讨论】:

std::vector 很好,但您可能还想看看std::deque 由于卡片是小东西,我只使用固定大小的数组。 C++ 程序员还记得如何使用“原始”数组,不是吗? @LeeDanielCrocker,一些DistrictDeck 实例可以有更多或更少的卡片,我更喜欢坚持使用动态容器。我知道我可以模板类来构建一个定制的数组,但我喜欢保持较低的维护工作量。 使用vector 作为循环缓冲区,即保留起始和结束索引。它比deque 更好,因为在您的情况下,最大卡片数是有界的, 【参考方案1】:

Vector 可以很好地满足您的目的。使用Fisher Yates Shuffle 可以最佳地执行洗牌 (O(n))。

我还应该注意,基于 std::random_shuffle 的复杂性,这看起来已经是您正在使用的。

【讨论】:

【参考方案2】:

首先,保留向量可能是一个不错的选择。

如果您必须经常移除卡片堆开头的元素,并且希望避免向量所需的大量移动,那么您可以选择 deque

deque<int> q; 
default_random_engine rndgen;
q.push_front(11);
q.push_back(12);                     // requirement 4
q.push_front(15);
q.push_front(20); 
cout << q.front() <<endl;            // requirement 3
q.pop_front();                       //    "   "
cout << q.at(2)<<endl;               // + random access
sort(q.begin(), q.end());            // requirement 2
shuffle(q.begin(), q.end(), rndgen); // requirement 1

live demo

值得一提的是:双端队列具有随机迭代器,在恒定时间内在队列的开头或结尾执行插入/访问,虽然插入可能会使迭代器无效,但对元素的指针和引用仍然有效。

【讨论】:

【参考方案3】:

保持矢量怎么样?这似乎是一个合理的选择——你希望在那里保留多少张卡片?连续存储通常更可取,因为这样可以避免大多数内存访问性能问题。

如果您知道要使用的最大卡片数,也可以使用 std::array 或纯数组。

与往常一样,衡量您的表现,看看您是否确实存在性能问题。

【讨论】:

我对 std::vector 的主要担心是关于绘图卡 pileOfCards_.erase(std::begin(pileOfCards_)); 从而转移内存,但我想对于 enum class,这没什么大不了的。 对于少量卡片,复制这些枚举会很快。我猜你也不会每毫秒多次执行这个操作...... 没错,我只是想知道一种更好的方法。

以上是关于模拟一堆卡片的最佳容器的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个向用户显示一堆卡片的集合视图?

1黑白卡片--全国模拟

如何在容器内居中卡片(引导程序)[重复]

如何在弹性容器中居中卡片

使用 jquery droppable,我如何复制 trello 将人物图像拖放到卡片上的行为,它捕捉到卡片的右下角?

Flutter 卡片和容器设计