#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
extern "C"
{
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
}
inline unsigned randint(unsigned x)
{
//return (unsigned)floor((double)rand() * (double)x / (double)RAND_MAX);
return rand() % x;
}
inline bool magik(unsigned x)
{
return randint(100) < x;
}
class SentientWeapon
{
public:
static const unsigned NEW_GROUP_CHANCE = 40;
unsigned pval, pval2, to_h, to_d, totalPoints;
std::vector<std::string> realms;
SentientWeapon(void)
: pval(1)
, pval2(0)
, totalPoints(0)
, to_h(0)
, to_d(0)
{
if(not allRealmsInitialized)
initRealms();
};
void gainRealm(void)
{
unsigned tries = 1000;
while(tries-- > 0)
{
unsigned rv = randint(allRealms.size());
std::string realm = allRealms[rv];
std::vector<std::string>::iterator result =
find(realms.begin(), realms.end(), realm);
if((result == realms.end()) and
(realmPrices[realm] <= pval2))
{
pval2 -= realmPrices[realm];
realms.push_back(realm);
return;
}
}
};
void gainPower(void)
{
// Unimplemented
};
void gainLevel(void)
{
unsigned die = randint(100);
if(die < 33)
{
to_h += randint(2);
to_d += 1;
}
else if(die < 66)
{
to_h += 1;
pval2 += 1;
totalPoints += 1;
if(magik(NEW_GROUP_CHANCE))
gainRealm();
}
else
{
if(realms.size() == 0)
gainRealm();
gainPower();
if(pval == 0)
{
pval = 1;
}
else
{
while(magik(20 - pval * 2) and (pval < 5))
pval += 1;
}
}
};
static std::map<std::string, unsigned> realmPrices;
static std::vector<std::string> allRealms;
static bool allRealmsInitialized;
static void initRealms(void)
{
realmPrices["Fire"] = 1;
realmPrices["Cold"] = 1;
realmPrices["Lightning"] = 1;
realmPrices["Poison"] = 2;
realmPrices["Acid"] = 3;
realmPrices["Air"] = 5;
realmPrices["Earth"] = 5;
realmPrices["Mind"] = 7;
realmPrices["Shield"] = 7;
realmPrices["Chaos"] = 7;
realmPrices["Magic"] = 10;
realmPrices["Antimagic"] = 10;
for(std::map<std::string, unsigned>::iterator i = realmPrices.begin();
i != realmPrices.end(); ++i)
{
allRealms.push_back((*i).first);
}
};
};
bool SentientWeapon::allRealmsInitialized = false;
std::map<std::string, unsigned> SentientWeapon::realmPrices;
std::vector<std::string> SentientWeapon::allRealms;
int main(int, char **)
{
srand(time(0));
std::vector<SentientWeapon> weaponList;
for(int i = 0; i < 10000; ++i)
{
SentientWeapon weapon;
for(int j = 1; j < 50; ++j)
weapon.gainLevel();
weaponList.push_back(weapon);
}
std::map<std::string, unsigned> realmCount;
for(std::vector<std::string>::iterator i = SentientWeapon::allRealms.begin();
i != SentientWeapon::allRealms.end(); ++i)
{
realmCount[*i] = 0;
}
std::map<unsigned, unsigned> pvalCount;
for(unsigned i = 1; i <= 5; ++i)
{
pvalCount[i] = 0;
}
for(std::vector<SentientWeapon>::iterator i = weaponList.begin();
i != weaponList.end(); ++i)
{
SentientWeapon &weapon = *i;
pvalCount[weapon.pval] = pvalCount[weapon.pval] + 1;
for(std::vector<std::string>::iterator i = weapon.realms.begin();
i != weapon.realms.end(); ++i)
{
realmCount[*i] = realmCount[*i] + 1;
}
}
for(std::map<std::string, unsigned>::iterator i = realmCount.begin();
i != realmCount.end(); ++i)
{
char percentString[10];
snprintf(percentString, 10, "%.3f%%", 100.0 * (*i).second / weaponList.size());
std::cout << (*i).first << ": " << percentString << std::endl;
}
for(unsigned i = 1; i <= 5; ++i)
{
char percentString[10];
snprintf(percentString, 10, "%.3f%%", 100.0 * pvalCount[i] / weaponList.size());
std::cout << i << ": " << percentString << std::endl;
}
return 0;
}
Chatter
KhymChanur: About this code snippet:
if(pval == 0) pval = 1;
while(magik(20 - pval * 2) and (pval < 5))
pval += 1;
If my understanding of the spoiler is correct, if the 34% chance "gain a power and attempt to raise pval" happens, then it will only attempt to increase the pval once, rather than keep on increasing the pval until an attempt fails:
- Set the pval to +1, if it is zero, or possibly (12-18% chance) gain one pval up to an absolute max of +5,
However, I can't find the pval increasing code in the 2.x files, so maybe your version is right.
NeilStevens: I didn't reference any spoilers when writing this. I used your perl code to look up the realms and their prices, and I used object1.c for the implementation. The actual snippet is:
if (!o_ptr->pval) o_ptr->pval = 1;
else
{
while (magik(20 - (o_ptr->pval * 2))) o_ptr->pval++;
if (o_ptr->pval > 5) o_ptr->pval = 5;
}
Oops... I messed up... I missed the "else" there. My code gives an extra chance at extra gains that it shouldn't, as in the case when pval == 0 it should go to 1 and quit, while I set it to one then send it into the loop. Grr, that's really poor C style, the way that if/else is structured, so I say it's not my fault!
I'm sure by the time we're all done with tome 3, this won't happen again, right?
KhymChanur: Ah, right, I was grepping for TR4_LEVELS, so I missed that code. However, the pval code still isn't quite right, because object_prep() ensures that the pval for sentient weapons always starts at 1, so there's no need to check is the pval is 0.
NeilStevens: Nice, so the error would have no effect if I went in and finished the implementation. That's two of those mistakes I made.
Fixing it anyway though.
NeilStevens: Updated with more pval stuff.
By the way, STL is *slow*. I wrote this in C++ instead of Ruby in the hopes of getting something fast. My mistake.
ToME Wiki