Commit df6558fc authored by twanvl's avatar twanvl

random pack generation works

parent 16b99249
...@@ -753,6 +753,7 @@ error: ...@@ -753,6 +753,7 @@ error:
It is recommended that you upgrade to the latest version. It is recommended that you upgrade to the latest version.
Visit http:://magicseteditor.sourceforge.net/ Visit http:://magicseteditor.sourceforge.net/
word list type not found: The word list type "%s" was not found (from a <word-list> tag) word list type not found: The word list type "%s" was not found (from a <word-list> tag)
pack item not found: The pack item "%s" was not found (from a pack type)
# Update checking # Update checking
checking updates failed: Checking updates failed. checking updates failed: Checking updates failed.
......
...@@ -1836,16 +1836,16 @@ auto replace: ...@@ -1836,16 +1836,16 @@ auto replace:
############################################################## Card packs ############################################################## Card packs
pack item: pack item:
name: Common name: common
filter: card.rarity == "common" filter: card.rarity == "common"
pack item: pack item:
name: Uncommon name: uncommon
filter: card.rarity == "uncommon" filter: card.rarity == "uncommon"
pack item: pack item:
name: Rare name: rare
filter: card.rarity == "rare" filter: card.rarity == "rare"
pack item: pack item:
name: Basic Land name: basic land
filter: card.type == "Plains" filter: card.type == "Plains"
filter: card.type == "Island" filter: card.type == "Island"
filter: card.type == "Swamp" filter: card.type == "Swamp"
...@@ -1855,46 +1855,46 @@ pack item: ...@@ -1855,46 +1855,46 @@ pack item:
#type: cyclic #type: cyclic
pack type: pack type:
name: Tournament pack name: tournament pack
item: item:
name: Rare name: rare
amount: 3 amount: 3
item: item:
name: Uncommon name: uncommon
amount: 9 amount: 9
item: item:
name: Common name: common
amount: 33 amount: 33
item: item:
name: Basic Land name: basic land
amount: 30 amount: 30
pack type: pack type:
name: Booster pack name: booster pack
item: item:
name: Rare name: rare
amount: 1 amount: 1
item: item:
name: Uncommon name: uncommon
amount: 3 amount: 3
item: item:
name: Common name: common
amount: 11 amount: 11
pack type: pack type:
name: Additional common name: additional common
item: item:
name: Common name: common
pack type: pack type:
name: Additional uncommon name: additional uncommon
item: item:
name: Uncommon name: uncommon
pack type: pack type:
name: Additional rare name: additional rare
item: item:
name: Rare name: rare
pack type: pack type:
name: Additional special name: additional special
item: item:
name: Special name: special
......
...@@ -26,7 +26,7 @@ Since the result is random, calling the function twice will give a different ans ...@@ -26,7 +26,7 @@ Since the result is random, calling the function twice will give a different ans
> random_select([1,2,3,4], count:3) == [2,3,1] > 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) == [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) == [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: false) == [1,3,4]
--See also-- --See also--
| [[fun:random_shuffle]] Randomly shuffle a list. | [[fun:random_shuffle]] Randomly shuffle a list.
...@@ -8,6 +8,13 @@ ...@@ -8,6 +8,13 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <data/pack.hpp> #include <data/pack.hpp>
#include <data/set.hpp>
#include <data/game.hpp>
#include <data/card.hpp>
DECLARE_TYPEOF_COLLECTION(PackItemRefP);
DECLARE_TYPEOF_COLLECTION(PackItemP);
DECLARE_TYPEOF_COLLECTION(CardP);
// ----------------------------------------------------------------------------- : PackType // ----------------------------------------------------------------------------- : PackType
...@@ -21,27 +28,84 @@ IMPLEMENT_REFLECTION(PackType) { ...@@ -21,27 +28,84 @@ IMPLEMENT_REFLECTION(PackType) {
REFLECT(items); REFLECT(items);
} }
void PackType::generate(Set& set, vector<CardP>& out) const { bool PackType::update(Context& ctx) {
//%FOR_EACH(card_type, card_types) { bool change = enabled.update(ctx);
//% card_type->generate(set,out); FOR_EACH(item, items) {
//%} change |= item->update(ctx);
}
return change;
}
void PackType::generate(PackItemCache& packs, boost::mt19937& gen, vector<CardP>& 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::PackItemRef() PackItemRef::PackItemRef()
: amount(1) : amount(1)
, type(PACK_REF_REPLACE)
{} {}
IMPLEMENT_REFLECTION(PackItemRef) { IMPLEMENT_REFLECTION(PackItemRef) {
REFLECT(name); REFLECT(name);
REFLECT(amount); REFLECT(amount);
REFLECT(type);
} }
bool PackItemRef::update(Context& ctx) { bool PackItemRef::update(Context& ctx) {
return amount.update(ctx); return amount.update(ctx);
} }
/// Random generator with random numbers in a range
template <typename Gen>
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<CardP>& out) const {
vector<CardP>& 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<boost::mt19937> 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 // ----------------------------------------------------------------------------- : PackItem
IMPLEMENT_REFLECTION(PackItem) { IMPLEMENT_REFLECTION(PackItem) {
...@@ -50,9 +114,37 @@ IMPLEMENT_REFLECTION(PackItem) { ...@@ -50,9 +114,37 @@ IMPLEMENT_REFLECTION(PackItem) {
} }
void PackItem::generate(Set& set, vector<CardP>& out) const { void PackItem::generate(Set& set, vector<CardP>& out) const {
//%Context& ctx = set.getContext(); FOR_EACH(card, set.cards) {
//%amount.update(ctx); Context& ctx = set.getContext(card);
//%FOR_EACH(card_type, card_types) { bool keep = *filter.invoke(ctx);
//% card_type->generate(set,out); if (keep) {
//%} out.push_back(card);
}
}
}
// ----------------------------------------------------------------------------- : PackItemCache
PackItemCache::PackItemCache(Set& set)
: set(set)
{}
vector<CardP>& PackItemCache::cardsFor(const String& name) {
// lookup name
map<String,Cards>::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<CardP>);
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));
}
} }
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/reflect.hpp> #include <util/reflect.hpp>
#include <script/scriptable.hpp> #include <script/scriptable.hpp>
#include <boost/random/mersenne_twister.hpp>
DECLARE_POINTER_TYPE(PackItemRef); DECLARE_POINTER_TYPE(PackItemRef);
DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(Card);
class Set; class Set;
class PackItemCache;
// ----------------------------------------------------------------------------- : PackType // ----------------------------------------------------------------------------- : PackType
...@@ -28,8 +30,11 @@ class PackType : public IntrusivePtrBase<PackType> { ...@@ -28,8 +30,11 @@ class PackType : public IntrusivePtrBase<PackType> {
Scriptable<bool> enabled; ///< Is this pack enabled? Scriptable<bool> enabled; ///< Is this pack enabled?
vector<PackItemRefP> items; ///< Cards in this pack vector<PackItemRefP> items; ///< Cards in this pack
/// Update scripts, returns true if there is a change
bool update(Context& ctx);
/// Generate a random pack of cards, add them to out /// Generate a random pack of cards, add them to out
void generate(Set& set, vector<CardP>& out) const; void generate(PackItemCache& packs, boost::mt19937& gen, vector<CardP>& out) const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
...@@ -37,18 +42,25 @@ class PackType : public IntrusivePtrBase<PackType> { ...@@ -37,18 +42,25 @@ class PackType : public IntrusivePtrBase<PackType> {
// ----------------------------------------------------------------------------- : PackItemRef // ----------------------------------------------------------------------------- : PackItemRef
enum PackRefType
{ PACK_REF_REPLACE
, PACK_REF_NO_REPLACE
, PACK_REF_CYCLIC
};
class PackItemRef : public IntrusivePtrBase<PackItemRef> { class PackItemRef : public IntrusivePtrBase<PackItemRef> {
public: public:
PackItemRef(); PackItemRef();
String name; ///< Name of this type of cards String name; ///< Name of this type of cards
Scriptable<int> amount; ///< Number of cards of this type Scriptable<int> amount; ///< Number of cards of this type
PackRefType type;
/// Update scripts, returns true if there is a change /// Update scripts, returns true if there is a change
bool update(Context& ctx); bool update(Context& ctx);
/// Generate random cards, add them to out /// Generate random cards, add them to out
void generate(Set& set, vector<CardP>& out) const; void generate(PackItemCache& packs, boost::mt19937& gen, vector<CardP>& out) const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
...@@ -62,12 +74,28 @@ class PackItem : public IntrusivePtrBase<PackItem> { ...@@ -62,12 +74,28 @@ class PackItem : public IntrusivePtrBase<PackItem> {
String name; ///< Name of this type of cards String name; ///< Name of this type of cards
OptionalScript filter; ///< Filter to select this type of cards OptionalScript filter; ///< Filter to select this type of cards
/// Generate random cards, add them to out /// Select *all* cards matching the filter
void generate(Set& set, vector<CardP>& out) const; void generate(Set& set, vector<CardP>& out) const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
// ----------------------------------------------------------------------------- : PackItemCache
class PackItemCache {
public:
PackItemCache(Set& set);
/// The cards for a given PackItem
vector<CardP>& cardsFor(const String& name);
private:
Set& set;
/// Cards for each PackItem
typedef shared_ptr<vector<CardP> > Cards;
map<String,Cards> item_cards;
};
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -32,7 +32,9 @@ class RandomCardList : public CardListBase { ...@@ -32,7 +32,9 @@ class RandomCardList : public CardListBase {
/// Reset the list /// Reset the list
void reset(); void reset();
/// Add a pack of cards /// Add a pack of cards
void add(PackType& pack); void add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack);
using CardListBase::rebuild;
protected: protected:
virtual void getItems(vector<VoidP>& out) const; virtual void getItems(vector<VoidP>& out) const;
...@@ -49,8 +51,8 @@ RandomCardList::RandomCardList(Window* parent, int id, long style) ...@@ -49,8 +51,8 @@ RandomCardList::RandomCardList(Window* parent, int id, long style)
void RandomCardList::reset() { void RandomCardList::reset() {
cards.clear(); cards.clear();
} }
void RandomCardList::add(PackType& pack) { void RandomCardList::add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack) {
pack.generate(*set,cards); pack.generate(packs,gen,cards);
} }
void RandomCardList::onChangeSet() { void RandomCardList::onChangeSet() {
...@@ -73,7 +75,7 @@ RandomPackPanel::RandomPackPanel(Window* parent, int id) ...@@ -73,7 +75,7 @@ RandomPackPanel::RandomPackPanel(Window* parent, int id)
{ {
// init controls // init controls
preview = new CardViewer(this, wxID_ANY); preview = new CardViewer(this, wxID_ANY);
card_list = new FilteredCardList(this, wxID_ANY); card_list = new RandomCardList(this, wxID_ANY);
generate_button = new wxButton(this, ID_GENERATE_PACK, _BUTTON_("generate pack")); generate_button = new wxButton(this, ID_GENERATE_PACK, _BUTTON_("generate pack"));
seed_random = new wxRadioButton(this, ID_SEED_RANDOM, _BUTTON_("random seed")); seed_random = new wxRadioButton(this, ID_SEED_RANDOM, _BUTTON_("random seed"));
seed_fixed = new wxRadioButton(this, ID_SEED_FIXED, _BUTTON_("fixed seed")); seed_fixed = new wxRadioButton(this, ID_SEED_FIXED, _BUTTON_("fixed seed"));
...@@ -135,7 +137,7 @@ void RandomPackPanel::onChangeSet() { ...@@ -135,7 +137,7 @@ void RandomPackPanel::onChangeSet() {
FOR_EACH(pack, set->game->pack_types) { FOR_EACH(pack, set->game->pack_types) {
PackItem i; PackItem i;
i.pack = pack; i.pack = pack;
i.label = new wxStaticText(this, wxID_ANY, pack->name); i.label = new wxStaticText(this, wxID_ANY, capitalize_sentence(pack->name));
i.value = new wxSpinCtrl(this, ID_PACK_AMOUNT, _("0"), wxDefaultPosition, wxSize(50,-1)); i.value = new wxSpinCtrl(this, ID_PACK_AMOUNT, _("0"), wxDefaultPosition, wxSize(50,-1));
packsSizer->Add(i.label, 0, wxALIGN_CENTER_VERTICAL); packsSizer->Add(i.label, 0, wxALIGN_CENTER_VERTICAL);
packsSizer->Add(i.value, 0, wxEXPAND | wxALIGN_CENTER); packsSizer->Add(i.value, 0, wxEXPAND | wxALIGN_CENTER);
...@@ -227,8 +229,23 @@ void RandomPackPanel::setSeed(int seed) { ...@@ -227,8 +229,23 @@ void RandomPackPanel::setSeed(int seed) {
} }
void RandomPackPanel::generate() { void RandomPackPanel::generate() {
boost::mt19937 random((unsigned)getSeed()); boost::mt19937 gen((unsigned)getSeed());
//set->game->pack_types[0].generate() PackItemCache pack_cache(*set);
// add packs to card list
card_list->reset();
FOR_EACH(item,packs) {
int copies = item.value->GetValue();
for (int i = 0 ; i < copies ; ++i) {
card_list->add(pack_cache, gen, *item.pack);
}
}
card_list->rebuild();
}
// ----------------------------------------------------------------------------- : Selection
void RandomPackPanel::selectCard(const CardP& card) {
preview->setCard(card);
} }
// ----------------------------------------------------------------------------- : Clipboard // ----------------------------------------------------------------------------- : Clipboard
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <wx/spinctrl.h> #include <wx/spinctrl.h>
class CardViewer; class CardViewer;
class FilteredCardList; class RandomCardList;
DECLARE_POINTER_TYPE(PackType); DECLARE_POINTER_TYPE(PackType);
// ----------------------------------------------------------------------------- : RandomPackPanel // ----------------------------------------------------------------------------- : RandomPackPanel
...@@ -34,6 +34,9 @@ class RandomPackPanel : public SetWindowPanel { ...@@ -34,6 +34,9 @@ class RandomPackPanel : public SetWindowPanel {
virtual void onUpdateUI(wxUpdateUIEvent&); virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id); virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual void selectCard(const CardP& card);
// --------------------------------------------------- : Clipboard // --------------------------------------------------- : Clipboard
virtual bool canCopy() const; virtual bool canCopy() const;
...@@ -41,7 +44,7 @@ class RandomPackPanel : public SetWindowPanel { ...@@ -41,7 +44,7 @@ class RandomPackPanel : public SetWindowPanel {
private: private:
CardViewer* preview; ///< Card preview CardViewer* preview; ///< Card preview
FilteredCardList* card_list; ///< The list of cards RandomCardList* card_list; ///< The list of cards
wxTextCtrl* seed; ///< Seed value wxTextCtrl* seed; ///< Seed value
wxFlexGridSizer* packsSizer; wxFlexGridSizer* packsSizer;
wxFlexGridSizer* totalsSizer; wxFlexGridSizer* totalsSizer;
......
# This file contains the keys expected to be in MSE locales # This file contains the keys expected to be in MSE locales
# It was automatically generated by tools/locale/locale.pl # It was automatically generated by tools/locale/locale.pl
# Generated on Sun Aug 3 21:57:37 2008 # Generated on Mon Aug 4 03:28:32 2008
action: action:
add control point: 0 add control point: 0
...@@ -116,6 +116,7 @@ error: ...@@ -116,6 +116,7 @@ error:
no game specified: 1 no game specified: 1
no stylesheet specified for the set: 0 no stylesheet specified for the set: 0
no updates: 0 no updates: 0
pack item not found: 1
package not found: 1 package not found: 1
package out of date: 3 package out of date: 3
package too new: 4 package too new: 4
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment