New descriptive text popup feature for deck selection
http://wololo.net/forum/viewtopic.php?f=13&t=2423
This commit is contained in:
+466
-242
@@ -1,242 +1,466 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckStats.h"
|
||||
#include "Player.h"
|
||||
#include "GameObserver.h"
|
||||
|
||||
DeckStats * DeckStats::mInstance = NULL;
|
||||
|
||||
int DeckStat::percentVictories()
|
||||
{
|
||||
if (nbgames == 0)
|
||||
return 50;
|
||||
return (100 * victories / nbgames);
|
||||
}
|
||||
|
||||
DeckStats * DeckStats::GetInstance()
|
||||
{
|
||||
if (!mInstance)
|
||||
{
|
||||
mInstance = NEW DeckStats();
|
||||
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void DeckStats::cleanStats()
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
|
||||
stats.clear();
|
||||
}
|
||||
|
||||
DeckStats::~DeckStats()
|
||||
{
|
||||
cleanStats();
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it->second->percentVictories());
|
||||
}
|
||||
}
|
||||
|
||||
DeckStat* DeckStats::getDeckStat(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int DeckStats::nbGames()
|
||||
{
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
}
|
||||
return nbgames;
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories()
|
||||
{
|
||||
int victories = 0;
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
victories += d->victories;
|
||||
}
|
||||
if (nbgames)
|
||||
{
|
||||
return (victories * 100) / nbgames;
|
||||
}
|
||||
return 50;
|
||||
}
|
||||
|
||||
void DeckStats::load(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
load(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::load(const char * filename)
|
||||
{
|
||||
cleanStats();
|
||||
std::ifstream file(filename);
|
||||
std::string s;
|
||||
|
||||
if (file)
|
||||
{
|
||||
while (std::getline(file, s))
|
||||
{
|
||||
string deckfile = s;
|
||||
std::getline(file, s);
|
||||
int games = atoi(s.c_str());
|
||||
std::getline(file, s);
|
||||
int victories = atoi(s.c_str());
|
||||
map<string, DeckStat *>::iterator it = stats.find(deckfile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[deckfile] = NEW DeckStat(games, victories);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::save(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
save(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::save(const char * filename)
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
char writer[512];
|
||||
if (file)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
sprintf(writer, "%s\n", it->first.c_str());
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->nbgames);
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->victories);
|
||||
file << writer;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game)
|
||||
{
|
||||
int victory = 1;
|
||||
if (!game->gameOver)
|
||||
{
|
||||
if (player->life == opponent->life)
|
||||
return;
|
||||
if (player->life < opponent->life)
|
||||
victory = 0;
|
||||
}
|
||||
else if (game->gameOver == player)
|
||||
{
|
||||
victory = 0;
|
||||
}
|
||||
load(player);
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponent->deckFileSmall);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[opponent->deckFileSmall] = NEW DeckStat(1, victory);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->victories += victory;
|
||||
it->second->nbgames += 1;
|
||||
}
|
||||
save(player);
|
||||
}
|
||||
|
||||
StatsWrapper::StatsWrapper(int deckId)
|
||||
{
|
||||
// Load deck statistics
|
||||
char buffer[512];
|
||||
DeckStats * stats = DeckStats::GetInstance();
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
|
||||
sprintf(buffer, "stats/player_deck%i.txt", deckId);
|
||||
string deckstats = options.profileFile(buffer);
|
||||
|
||||
if (fileExists(deckstats.c_str()))
|
||||
{
|
||||
stats->load(deckstats.c_str());
|
||||
percentVictories = stats->percentVictories();
|
||||
gamesPlayed = stats->nbGames();
|
||||
|
||||
// Detailed deck statistics against AI
|
||||
int found = 1;
|
||||
int nbDecks = 0;
|
||||
while (found)
|
||||
{
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
char smallDeckName[512];
|
||||
sprintf(buffer, "%s/deck%i.txt", RESPATH"/ai/baka", nbDecks + 1);
|
||||
if (fileExists(buffer))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(buffer, NULL, 1);
|
||||
found = 1;
|
||||
nbDecks++;
|
||||
|
||||
sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks);
|
||||
DeckStat* deckStat = stats->getDeckStat(string(smallDeckName));
|
||||
|
||||
if ((deckStat != NULL) && (deckStat->nbgames > 0))
|
||||
{
|
||||
int percentVictories = stats->percentVictories(string(smallDeckName));
|
||||
aiDeckNames.push_back(string(mtgd->meta_name));
|
||||
aiDeckStats.push_back(deckStat);
|
||||
}
|
||||
|
||||
delete mtgd;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gamesPlayed = 0;
|
||||
percentVictories = 0;
|
||||
}
|
||||
}
|
||||
|
||||
StatsWrapper::~StatsWrapper()
|
||||
{
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
}
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DeckStats.h"
|
||||
#include "Player.h"
|
||||
#include "GameObserver.h"
|
||||
#include "MTGDeck.h"
|
||||
#include "ManaCostHybrid.h"
|
||||
|
||||
DeckStats * DeckStats::mInstance = NULL;
|
||||
|
||||
DeckStat::DeckStat(int _nbgames, int _victories) : nbgames(_nbgames), victories(_victories)
|
||||
{
|
||||
}
|
||||
|
||||
int DeckStat::percentVictories()
|
||||
{
|
||||
if (nbgames == 0) return 50;
|
||||
return (100 * victories / nbgames);
|
||||
}
|
||||
|
||||
DeckStats * DeckStats::GetInstance()
|
||||
{
|
||||
if (!mInstance)
|
||||
{
|
||||
mInstance = NEW DeckStats();
|
||||
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void DeckStats::cleanStats()
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
SAFE_DELETE(it->second);
|
||||
}
|
||||
|
||||
stats.clear();
|
||||
}
|
||||
|
||||
DeckStats::~DeckStats()
|
||||
{
|
||||
cleanStats();
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it->second->percentVictories());
|
||||
}
|
||||
}
|
||||
|
||||
DeckStat* DeckStats::getDeckStat(string opponentsFile)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponentsFile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int DeckStats::nbGames()
|
||||
{
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
}
|
||||
return nbgames;
|
||||
}
|
||||
|
||||
int DeckStats::percentVictories()
|
||||
{
|
||||
int victories = 0;
|
||||
int nbgames = 0;
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
DeckStat * d = it->second;
|
||||
nbgames += d->nbgames;
|
||||
victories += d->victories;
|
||||
}
|
||||
if (nbgames)
|
||||
{
|
||||
return (victories * 100) / nbgames;
|
||||
}
|
||||
return 50;
|
||||
}
|
||||
|
||||
void DeckStats::load(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
load(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::load(const char * filename)
|
||||
{
|
||||
cleanStats();
|
||||
std::ifstream file(filename);
|
||||
std::string s;
|
||||
|
||||
if (file)
|
||||
{
|
||||
while (std::getline(file, s))
|
||||
{
|
||||
string deckfile = s;
|
||||
std::getline(file, s);
|
||||
int games = atoi(s.c_str());
|
||||
std::getline(file, s);
|
||||
int victories = atoi(s.c_str());
|
||||
map<string, DeckStat *>::iterator it = stats.find(deckfile);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[deckfile] = NEW DeckStat(games, victories);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::save(Player * player)
|
||||
{
|
||||
char filename[512];
|
||||
sprintf(filename, "stats/%s.txt", player->deckFileSmall.c_str());
|
||||
save(options.profileFile(filename).c_str());
|
||||
}
|
||||
|
||||
void DeckStats::save(const char * filename)
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
char writer[512];
|
||||
if (file)
|
||||
{
|
||||
map<string, DeckStat *>::iterator it;
|
||||
for (it = stats.begin(); it != stats.end(); it++)
|
||||
{
|
||||
sprintf(writer, "%s\n", it->first.c_str());
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->nbgames);
|
||||
file << writer;
|
||||
sprintf(writer, "%i\n", it->second->victories);
|
||||
file << writer;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game)
|
||||
{
|
||||
int victory = 1;
|
||||
if (!game->gameOver)
|
||||
{
|
||||
if (player->life == opponent->life) return;
|
||||
if (player->life < opponent->life) victory = 0;
|
||||
}
|
||||
else if (game->gameOver == player)
|
||||
{
|
||||
victory = 0;
|
||||
}
|
||||
load(player);
|
||||
map<string, DeckStat *>::iterator it = stats.find(opponent->deckFileSmall);
|
||||
if (it == stats.end())
|
||||
{
|
||||
stats[opponent->deckFileSmall] = NEW DeckStat(1, victory);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->victories += victory;
|
||||
it->second->nbgames += 1;
|
||||
}
|
||||
save(player);
|
||||
}
|
||||
StatsWrapper::StatsWrapper(int deckId)
|
||||
{
|
||||
mDeckId = deckId;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "stats/player_deck%i.txt", deckId);
|
||||
string deckstats = options.profileFile(buffer);
|
||||
initStatistics(deckstats);
|
||||
}
|
||||
|
||||
StatsWrapper::StatsWrapper(string deckstats)
|
||||
{
|
||||
initStatistics(deckstats);
|
||||
}
|
||||
|
||||
void StatsWrapper::initStatistics(string deckstats)
|
||||
{
|
||||
// Load deck statistics
|
||||
DeckStats * stats = DeckStats::GetInstance();
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
|
||||
if (fileExists(deckstats.c_str()))
|
||||
{
|
||||
stats->load(deckstats.c_str());
|
||||
percentVictories = stats->percentVictories();
|
||||
gamesPlayed = stats->nbGames();
|
||||
|
||||
// Detailed deck statistics against AI
|
||||
int found = 1;
|
||||
int nbDecks = 0;
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
char smallDeckName[512];
|
||||
sprintf(buffer, "%s/deck%i.txt", RESPATH"/ai/baka", nbDecks + 1);
|
||||
if (fileExists(buffer))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(buffer, NULL, 1);
|
||||
found = 1;
|
||||
nbDecks++;
|
||||
|
||||
sprintf(smallDeckName, "%s_deck%i", "ai_baka", nbDecks);
|
||||
DeckStat* deckStat = stats->getDeckStat(string(smallDeckName));
|
||||
|
||||
if ((deckStat != NULL) && (deckStat->nbgames > 0))
|
||||
{
|
||||
int percentVictories = stats->percentVictories(string(smallDeckName));
|
||||
aiDeckNames.push_back(string(mtgd->meta_name));
|
||||
aiDeckStats.push_back(deckStat);
|
||||
}
|
||||
|
||||
delete mtgd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gamesPlayed = 0;
|
||||
percentVictories = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StatsWrapper::updateStats(string filename, MTGAllCards *collection)
|
||||
{
|
||||
if (fileExists(filename.c_str()))
|
||||
{
|
||||
MTGDeck * mtgd = NEW MTGDeck(filename.c_str(), collection);
|
||||
DeckDataWrapper *deckDataWrapper = NEW DeckDataWrapper(mtgd);
|
||||
updateStats(deckDataWrapper);
|
||||
SAFE_DELETE( mtgd );
|
||||
SAFE_DELETE( deckDataWrapper );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StatsWrapper::updateStats(DeckDataWrapper *myDeck)
|
||||
{
|
||||
if (!this->needUpdate || !myDeck) return;
|
||||
this->needUpdate = false;
|
||||
this->cardCount = myDeck->getCount(WSrcDeck::UNFILTERED_COPIES);
|
||||
this->countLands = myDeck->getCount(Constants::MTG_COLOR_LAND);
|
||||
this->totalPrice = myDeck->totalPrice();
|
||||
|
||||
this->countManaProducers = 0;
|
||||
// Mana cost
|
||||
int currentCount, convertedCost;
|
||||
ManaCost * currentCost;
|
||||
this->totalManaCost = 0;
|
||||
this->totalCreatureCost = 0;
|
||||
this->totalSpellCost = 0;
|
||||
MTGCard * current = myDeck->getCard();
|
||||
|
||||
// Clearing arrays
|
||||
for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++)
|
||||
{
|
||||
this->countCardsPerCost[i] = 0;
|
||||
this->countCreaturesPerCost[i] = 0;
|
||||
this->countSpellsPerCost[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= Constants::MTG_NB_COLORS; i++)
|
||||
{
|
||||
this->totalCostPerColor[i] = 0;
|
||||
this->countLandsPerColor[i] = 0;
|
||||
this->countBasicLandsPerColor[i] = 0;
|
||||
this->countNonLandProducersPerColor[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= Constants::STATS_MAX_MANA_COST; i++)
|
||||
{
|
||||
for (int k = 0; k <= Constants::MTG_NB_COLORS; k++)
|
||||
{
|
||||
this->countCardsPerCostAndColor[i][k] = 0;
|
||||
this->countCreaturesPerCostAndColor[i][k] = 0;
|
||||
this->countSpellsPerCostAndColor[i][k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int ic = 0; ic < myDeck->Size(true); ic++)
|
||||
{
|
||||
current = myDeck->getCard(ic, true);
|
||||
currentCost = current->data->getManaCost();
|
||||
convertedCost = currentCost->getConvertedCost();
|
||||
currentCount = myDeck->count(current);
|
||||
|
||||
// Add to the cards per cost counters
|
||||
this->totalManaCost += convertedCost * currentCount;
|
||||
if (convertedCost > Constants::STATS_MAX_MANA_COST)
|
||||
{
|
||||
convertedCost = Constants::STATS_MAX_MANA_COST;
|
||||
}
|
||||
this->countCardsPerCost[convertedCost] += currentCount;
|
||||
if (current->data->isCreature())
|
||||
{
|
||||
this->countCreaturesPerCost[convertedCost] += currentCount;
|
||||
this->totalCreatureCost += convertedCost * currentCount;
|
||||
}
|
||||
else if (current->data->isSpell())
|
||||
{
|
||||
this->countSpellsPerCost[convertedCost] += currentCount;
|
||||
this->totalSpellCost += convertedCost * currentCount;
|
||||
}
|
||||
|
||||
// Lets look for mana producing abilities
|
||||
|
||||
vector<string> abilitiesVector;
|
||||
string thisstring = current->data->magicText;
|
||||
abilitiesVector = split(thisstring, '\n');
|
||||
|
||||
for (int v = 0; v < (int) abilitiesVector.size(); v++)
|
||||
{
|
||||
string s = abilitiesVector[v];
|
||||
size_t t = s.find("add");
|
||||
if (t != string::npos)
|
||||
{
|
||||
s = s.substr(t + 3);
|
||||
ManaCost * mc = ManaCost::parseManaCost(s);
|
||||
for (int j = 0; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
if (mc->hasColor(j))
|
||||
{
|
||||
if (current->data->isLand())
|
||||
{
|
||||
if (current->data->hasType("Basic"))
|
||||
{
|
||||
this->countBasicLandsPerColor[j] += currentCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->countLandsPerColor[j] += currentCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->countNonLandProducersPerColor[j] += currentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
SAFE_DELETE(mc);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the per color counters
|
||||
// a. regular costs
|
||||
for (int j = 0; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
this->totalCostPerColor[j] += currentCost->getCost(j) * currentCount;
|
||||
if (current->data->hasColor(j))
|
||||
{
|
||||
// Add to the per cost and color counter
|
||||
this->countCardsPerCostAndColor[convertedCost][j] += currentCount;
|
||||
if (current->data->isCreature())
|
||||
{
|
||||
this->countCreaturesPerCostAndColor[convertedCost][j] += currentCount;
|
||||
}
|
||||
else if (current->data->isSpell())
|
||||
{
|
||||
this->countSpellsPerCostAndColor[convertedCost][j] += currentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// b. Hybrid costs
|
||||
ManaCostHybrid * hybridCost;
|
||||
int i;
|
||||
i = 0;
|
||||
|
||||
while ((hybridCost = currentCost->getHybridCost(i++)) != NULL)
|
||||
{
|
||||
this->totalCostPerColor[hybridCost->color1] += hybridCost->value1 * currentCount;
|
||||
this->totalCostPerColor[hybridCost->color2] += hybridCost->value2 * currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
this->totalColoredSymbols = 0;
|
||||
for (int j = 1; j < Constants::MTG_NB_COLORS; j++)
|
||||
{
|
||||
this->totalColoredSymbols += this->totalCostPerColor[j];
|
||||
}
|
||||
|
||||
this->countCardsPerCost[0] -= this->countLands;
|
||||
|
||||
// Counts by type
|
||||
this->countCreatures = countCardsByType("Creature", myDeck);
|
||||
this->countInstants = countCardsByType("Instant", myDeck);
|
||||
this->countEnchantments = countCardsByType("Enchantment", myDeck);
|
||||
this->countSorceries = countCardsByType("Sorcery", myDeck);
|
||||
this->countSpells = this->countInstants + this->countEnchantments + this->countSorceries;
|
||||
//this->countArtifacts = countCardsByType("Artifact", myDeck);
|
||||
|
||||
// Average mana costs
|
||||
this->avgManaCost = ((this->cardCount - this->countLands) <= 0) ? 0 : (float) this->totalManaCost / (this->cardCount
|
||||
- this->countLands);
|
||||
this->avgCreatureCost = (this->countCreatures <= 0) ? 0 : (float) this->totalCreatureCost / this->countCreatures;
|
||||
this->avgSpellCost = (this->countSpells <= 0) ? 0 : (float) this->totalSpellCost / this->countSpells;
|
||||
|
||||
// Probabilities
|
||||
// TODO: this could be optimized by reusing results
|
||||
for (int i = 0; i < Constants::STATS_FOR_TURNS; i++)
|
||||
{
|
||||
this->noLandsProbInTurn[i] = noLuck(this->cardCount, this->countLands, 7 + i) * 100;
|
||||
this->noCreaturesProbInTurn[i] = noLuck(this->cardCount, this->countCreatures, 7 + i) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
// This should probably be cached in DeckDataWrapper
|
||||
// or at least be calculated for all common types in one go
|
||||
int StatsWrapper::countCardsByType(const char * _type, DeckDataWrapper * myDeck)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < myDeck->Size(true); i++)
|
||||
{
|
||||
MTGCard * current = myDeck->getCard(i, true);
|
||||
if (current->data->hasType(_type))
|
||||
{
|
||||
result += myDeck->count(current);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// n cards total, a of them are of desired type (A), x drawn
|
||||
// returns probability of no A's
|
||||
float StatsWrapper::noLuck(int n, int a, int x)
|
||||
{
|
||||
if ((a >= n) || (a == 0)) return 1;
|
||||
if ((n == 0) || (x == 0) || (x > n) || (n - a < x)) return 0;
|
||||
|
||||
a = n - a;
|
||||
float result = 1;
|
||||
|
||||
for (int i = 0; i < x; i++)
|
||||
result *= (float) (a - i) / (n - i);
|
||||
return result;
|
||||
}
|
||||
|
||||
StatsWrapper::~StatsWrapper()
|
||||
{
|
||||
aiDeckNames.clear();
|
||||
aiDeckStats.clear();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user