Commit df6558fc authored by twanvl's avatar twanvl

random pack generation works

parent 16b99249
......@@ -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 <word-list> tag)
pack item not found: The pack item "%s" was not found (from a pack type)
# Update checking
checking updates failed: Checking updates failed.
......
......@@ -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
......
......@@ -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.
......@@ -8,6 +8,13 @@
#include <util/prec.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
......@@ -21,27 +28,84 @@ IMPLEMENT_REFLECTION(PackType) {
REFLECT(items);
}
void PackType::generate(Set& set, vector<CardP>& 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<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()
: 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 <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
IMPLEMENT_REFLECTION(PackItem) {
......@@ -50,9 +114,37 @@ IMPLEMENT_REFLECTION(PackItem) {
}
void PackItem::generate(Set& set, vector<CardP>& 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<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 @@
#include <util/prec.hpp>
#include <util/reflect.hpp>
#include <script/scriptable.hpp>
#include <boost/random/mersenne_twister.hpp>
DECLARE_POINTER_TYPE(PackItemRef);
DECLARE_POINTER_TYPE(Card);
class Set;
class PackItemCache;
// ----------------------------------------------------------------------------- : PackType
......@@ -28,8 +30,11 @@ class PackType : public IntrusivePtrBase<PackType> {
Scriptable<bool> enabled; ///< Is this pack enabled?
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
void generate(Set& set, vector<CardP>& out) const;
void generate(PackItemCache& packs, boost::mt19937& gen, vector<CardP>& out) const;
private:
DECLARE_REFLECTION();
......@@ -37,18 +42,25 @@ class PackType : public IntrusivePtrBase<PackType> {
// ----------------------------------------------------------------------------- : PackItemRef
enum PackRefType
{ PACK_REF_REPLACE
, PACK_REF_NO_REPLACE
, PACK_REF_CYCLIC
};
class PackItemRef : public IntrusivePtrBase<PackItemRef> {
public:
PackItemRef();
String name; ///< Name of this type of cards
Scriptable<int> amount; ///< Number of cards of this type
PackRefType type;
/// Update scripts, returns true if there is a change
bool update(Context& ctx);
/// 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:
DECLARE_REFLECTION();
......@@ -59,15 +71,31 @@ class PackItemRef : public IntrusivePtrBase<PackItemRef> {
/// A card type description for playtesting
class PackItem : public IntrusivePtrBase<PackItem> {
public:
String name; ///< Name of this type of cards
OptionalScript filter; ///< Filter to select this type of cards
String name; ///< Name of 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;
private:
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
#endif
......@@ -32,7 +32,9 @@ class RandomCardList : public CardListBase {
/// Reset the list
void reset();
/// Add a pack of cards
void add(PackType& pack);
void add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack);
using CardListBase::rebuild;
protected:
virtual void getItems(vector<VoidP>& out) const;
......@@ -49,8 +51,8 @@ RandomCardList::RandomCardList(Window* parent, int id, long style)
void RandomCardList::reset() {
cards.clear();
}
void RandomCardList::add(PackType& pack) {
pack.generate(*set,cards);
void RandomCardList::add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack) {
pack.generate(packs,gen,cards);
}
void RandomCardList::onChangeSet() {
......@@ -73,7 +75,7 @@ RandomPackPanel::RandomPackPanel(Window* parent, int id)
{
// init controls
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"));
seed_random = new wxRadioButton(this, ID_SEED_RANDOM, _BUTTON_("random seed"));
seed_fixed = new wxRadioButton(this, ID_SEED_FIXED, _BUTTON_("fixed seed"));
......@@ -135,7 +137,7 @@ void RandomPackPanel::onChangeSet() {
FOR_EACH(pack, set->game->pack_types) {
PackItem i;
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));
packsSizer->Add(i.label, 0, wxALIGN_CENTER_VERTICAL);
packsSizer->Add(i.value, 0, wxEXPAND | wxALIGN_CENTER);
......@@ -227,8 +229,23 @@ void RandomPackPanel::setSeed(int seed) {
}
void RandomPackPanel::generate() {
boost::mt19937 random((unsigned)getSeed());
//set->game->pack_types[0].generate()
boost::mt19937 gen((unsigned)getSeed());
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
......
......@@ -14,7 +14,7 @@
#include <wx/spinctrl.h>
class CardViewer;
class FilteredCardList;
class RandomCardList;
DECLARE_POINTER_TYPE(PackType);
// ----------------------------------------------------------------------------- : RandomPackPanel
......@@ -34,6 +34,9 @@ class RandomPackPanel : public SetWindowPanel {
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual void selectCard(const CardP& card);
// --------------------------------------------------- : Clipboard
virtual bool canCopy() const;
......@@ -41,7 +44,7 @@ class RandomPackPanel : public SetWindowPanel {
private:
CardViewer* preview; ///< Card preview
FilteredCardList* card_list; ///< The list of cards
RandomCardList* card_list; ///< The list of cards
wxTextCtrl* seed; ///< Seed value
wxFlexGridSizer* packsSizer;
wxFlexGridSizer* totalsSizer;
......
# This file contains the keys expected to be in MSE locales
# 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:
add control point: 0
......@@ -116,6 +116,7 @@ error:
no game specified: 1
no stylesheet specified for the set: 0
no updates: 0
pack item not found: 1
package not found: 1
package out of date: 3
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