From 04a040dc29a87df5a47745275f0fb16c71570c44 Mon Sep 17 00:00:00 2001 From: twanvl Date: Mon, 4 Aug 2008 01:38:46 +0000 Subject: [PATCH] random pack generation works git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1045 0fc631ac-6414-0410-93d0-97cfa31319b6 --- data/en.mse-locale/locale | 1 + data/magic.mse-game/game | 42 ++++----- doc/function/random_select.txt | 4 +- src/data/pack.cpp | 110 +++++++++++++++++++++-- src/data/pack.hpp | 38 ++++++-- src/gui/set/random_pack_panel.cpp | 31 +++++-- src/gui/set/random_pack_panel.hpp | 7 +- src/resource/common/expected_locale_keys | 3 +- 8 files changed, 189 insertions(+), 47 deletions(-) diff --git a/data/en.mse-locale/locale b/data/en.mse-locale/locale index 90bbec30..e5f54207 100644 --- a/data/en.mse-locale/locale +++ b/data/en.mse-locale/locale @@ -753,6 +753,7 @@ error: It is recommended that you upgrade to the latest version. Visit http:://magicseteditor.sourceforge.net/ word list type not found: The word list type "%s" was not found (from a tag) + pack item not found: The pack item "%s" was not found (from a pack type) # Update checking checking updates failed: Checking updates failed. diff --git a/data/magic.mse-game/game b/data/magic.mse-game/game index de062bec..6edabb58 100644 --- a/data/magic.mse-game/game +++ b/data/magic.mse-game/game @@ -1836,16 +1836,16 @@ auto replace: ############################################################## Card packs pack item: - name: Common + name: common filter: card.rarity == "common" pack item: - name: Uncommon + name: uncommon filter: card.rarity == "uncommon" pack item: - name: Rare + name: rare filter: card.rarity == "rare" pack item: - name: Basic Land + name: basic land filter: card.type == "Plains" filter: card.type == "Island" filter: card.type == "Swamp" @@ -1855,46 +1855,46 @@ pack item: #type: cyclic pack type: - name: Tournament pack + name: tournament pack item: - name: Rare + name: rare amount: 3 item: - name: Uncommon + name: uncommon amount: 9 item: - name: Common + name: common amount: 33 item: - name: Basic Land + name: basic land amount: 30 pack type: - name: Booster pack + name: booster pack item: - name: Rare + name: rare amount: 1 item: - name: Uncommon + name: uncommon amount: 3 item: - name: Common + name: common amount: 11 pack type: - name: Additional common + name: additional common item: - name: Common + name: common pack type: - name: Additional uncommon + name: additional uncommon item: - name: Uncommon + name: uncommon pack type: - name: Additional rare + name: additional rare item: - name: Rare + name: rare pack type: - name: Additional special + name: additional special item: - name: Special + name: special diff --git a/doc/function/random_select.txt b/doc/function/random_select.txt index 2f9a92fb..43362908 100644 --- a/doc/function/random_select.txt +++ b/doc/function/random_select.txt @@ -25,8 +25,8 @@ Since the result is random, calling the function twice will give a different ans > random_select([1,2,3,4]) == 2 > random_select([1,2,3,4], count:3) == [2,3,1] > random_select([1,2,3,4], count:3) == [3,1,4] -> random_select([1,2,3,4], count:3, replace: true) == [2,3,2] -> random_select([1,2,3,4], count:3, replace: true) == [1,3,4] +> random_select([1,2,3,4], count:3, replace: true) == [2,3,2] +> random_select([1,2,3,4], count:3, replace: false) == [1,3,4] --See also-- | [[fun:random_shuffle]] Randomly shuffle a list. diff --git a/src/data/pack.cpp b/src/data/pack.cpp index e20f144b..2fe0f8e1 100644 --- a/src/data/pack.cpp +++ b/src/data/pack.cpp @@ -8,6 +8,13 @@ #include #include +#include +#include +#include + +DECLARE_TYPEOF_COLLECTION(PackItemRefP); +DECLARE_TYPEOF_COLLECTION(PackItemP); +DECLARE_TYPEOF_COLLECTION(CardP); // ----------------------------------------------------------------------------- : PackType @@ -21,27 +28,84 @@ IMPLEMENT_REFLECTION(PackType) { REFLECT(items); } -void PackType::generate(Set& set, vector& out) const { - //%FOR_EACH(card_type, card_types) { - //% card_type->generate(set,out); - //%} +bool PackType::update(Context& ctx) { + bool change = enabled.update(ctx); + FOR_EACH(item, items) { + change |= item->update(ctx); + } + return change; +} + +void PackType::generate(PackItemCache& packs, boost::mt19937& gen, vector& out) const { + FOR_EACH_CONST(item, items) { + item->generate(packs,gen,out); + } +} + +// ----------------------------------------------------------------------------- : PackRefType + +IMPLEMENT_REFLECTION_ENUM(PackRefType) { + VALUE_N("replace", PACK_REF_REPLACE); + VALUE_N("no replace", PACK_REF_NO_REPLACE); + VALUE_N("cyclic", PACK_REF_CYCLIC); } // ----------------------------------------------------------------------------- : PackItemRef PackItemRef::PackItemRef() : amount(1) + , type(PACK_REF_REPLACE) {} IMPLEMENT_REFLECTION(PackItemRef) { REFLECT(name); REFLECT(amount); + REFLECT(type); } bool PackItemRef::update(Context& ctx) { return amount.update(ctx); } +/// Random generator with random numbers in a range +template +struct RandomRange { + RandomRange(Gen& gen) : gen(gen) {} + unsigned operator () (unsigned max) { return gen() % max; } + Gen& gen; +}; + +void PackItemRef::generate(PackItemCache& packs, boost::mt19937& gen, vector& out) const { + vector& cards = packs.cardsFor(name); + // generate 'amount' cards and add them to out + if (cards.empty()) return; + if (type == PACK_REF_REPLACE) { + // amount random numbers + for (int i = 0 ; i < amount ; ++i) { + size_t index = gen() % cards.size(); + out.push_back(cards[index]); + } + } else if (type == PACK_REF_NO_REPLACE) { + // random shuffle + // to prevent us from being too predictable for small sets, periodically reshuffle + RandomRange gen_range(gen); + size_t max_per_batch = (cards.size() + 1) / 2; + int rem = amount; + while (rem > 0) { + random_shuffle(cards.begin(), cards.end(), gen_range); + out.insert(out.end(), cards.begin(), cards.begin() + min((size_t)rem, max_per_batch)); + rem -= (int)max_per_batch; + } + } else if (type == PACK_REF_CYCLIC) { + // multiple copies + size_t copies = amount / cards.size(); + FOR_EACH_CONST(card, cards) { + out.insert(out.end(),copies,card); + } + // TODO: what if amount is not a multiple of the number of cards? + } +} + // ----------------------------------------------------------------------------- : PackItem IMPLEMENT_REFLECTION(PackItem) { @@ -50,9 +114,37 @@ IMPLEMENT_REFLECTION(PackItem) { } void PackItem::generate(Set& set, vector& out) const { - //%Context& ctx = set.getContext(); - //%amount.update(ctx); - //%FOR_EACH(card_type, card_types) { - //% card_type->generate(set,out); - //%} + FOR_EACH(card, set.cards) { + Context& ctx = set.getContext(card); + bool keep = *filter.invoke(ctx); + if (keep) { + out.push_back(card); + } + } +} + +// ----------------------------------------------------------------------------- : PackItemCache + +PackItemCache::PackItemCache(Set& set) + : set(set) +{} + +vector& PackItemCache::cardsFor(const String& name) { + // lookup name + map::iterator it = item_cards.find(name); + if (it != item_cards.end()) { + return *it->second; + } else { + // not used before, generate list and cache + FOR_EACH(item, set.game->pack_items) { + if (item->name == name) { + Cards cards(new vector); + item->generate(set,*cards); + item_cards.insert(make_pair(name,cards)); + return *cards; + } + } + // still not found + throw Error(_ERROR_1_("pack item not found",name)); + } } diff --git a/src/data/pack.hpp b/src/data/pack.hpp index ab24647c..4c63e1f0 100644 --- a/src/data/pack.hpp +++ b/src/data/pack.hpp @@ -12,10 +12,12 @@ #include #include #include