Skip to content

Instantly share code, notes, and snippets.

@Keloran
Created April 23, 2015 11:07
Show Gist options
  • Save Keloran/f172042d1ea87bf07c7d to your computer and use it in GitHub Desktop.
Save Keloran/f172042d1ea87bf07c7d to your computer and use it in GitHub Desktop.
#include "./Markov.hpp"
namespace NordicArts {
namespace GameNS {
Markov::Markov() {
init();
}
Markov::Markov(NordicOS::Logger *pLogger) : m_pLogger(pLogger) {
m_bDebug = true;
init();
}
void Markov::init() {
// Set the locale
m_pLocale = boost::locale::generator().generate("en_US.UTF-8");
// read the file
fillNameList();
// generate the chance maps
generateFirstLetterMap();
generateLastLetterMap();
generateLetterToLetterMap();
}
void Markov::setVariance(float fVariance) {
m_fVariance = fVariance;
}
std::string Markov::generateWord() {
std::string word = "";
// Seed
NordicOS::Time::Time oTime;
NordicOS::Time::Time *pTime = &oTime;
srand(pTime->getNanoSeconds());
// generate first letter
while (true) {
int randLetter = (rand() % 27);
char cLetter = m_cAlphabet[randLetter];
std::string firstLetter = NordicOS::getString(cLetter);
double randChance = ((double)rand() / RAND_MAX);
double randLetterValue = m_mFirstLetterChance[firstLetter];
double randMath = ((m_mFirstLetterChance[firstLetter] * 2) + .05);
if (randChance < randMath) {
word.append(firstLetter);
break;
}
}
// Seed
srand(pTime->getNanoSeconds());
// generate word
while (true) {
int randLetter = (rand() % 27);
char cLetter = m_cAlphabet[randLetter];
std::string nextLetter = NordicOS::getString(cLetter);
std::string lastLetter = NordicOS::getString(word.back());
double nextLetterChance = ((m_mLetterToLetterChance[lastLetter][nextLetter] * 2) - m_fVariance);
double randChance = ((double)rand() / RAND_MAX);
if (randChance < nextLetterChance) {
word.append(nextLetter);
// check if word should end
lastLetter = NordicOS::getString(word.back());
double extraChance = m_mLastLetterChance[lastLetter];
double moreRand = ((double)rand() / RAND_MAX);
if ((word.size() >= 4) && (moreRand < ((extraChance * 1.5) + .05))) {
break;
} else if ((word.size() > 8) && (moreRand < .3)) {
break;
}
}
}
word = boost::locale::to_title(word, m_pLocale);
if (m_bDebug) {
std::string cString = "Word: ";
cString.append(word);
m_pLogger->log(cString);
}
return word;
}
void Markov::fillNameList() {
std::vector<std::string> names;
std::ifstream inFile("./GameFiles/Names/names-list");
std::string cLine;
while (std::getline(inFile, cLine)) {
cLine = boost::locale::to_lower(cLine, m_pLocale);
names.push_back(cLine);
}
// Set the names
m_vNames = names;
}
void Markov::generateFirstLetterMap() {
std::map<std::string, double> map = getAlphabetMap();
double total = 0;
for (std::string c : m_vNames) {
// create the char
char *name = new char[(c.size() + 1)];
name[c.size()] = 0;
memcpy(name, c.c_str(), c.size());
std::string s = NordicOS::getString(name[0]);
if (map.find(s) != map.end()) {
double mapValue = map[s];
mapValue += 1;
map[s] = mapValue;
total++;
}
}
// find the percentage
for (int i = 0; i < m_cAlphabet[i] != '\0'; i++) {
// turn the character into a string
std::string s = NordicOS::getString(m_cAlphabet[i]);
// set value
map[s] = (map[s] / total);
}
m_mFirstLetterChance = map;
}
void Markov::generateLastLetterMap() {
std::map<std::string, double> map = getAlphabetMap();
double total = 0;
for (std::string c : m_vNames) {
// create the char
char *name = new char[(c.size() + 1)];
name[c.size()] = 0;
memcpy(name, c.c_str(), c.size());
// turn the last letter into a string
std::string s = NordicOS::getString(name[(c.size() - 1)]);
if (map.find(s) != map.end()) {
double mapValue = map[s];
mapValue += 1;
map[s] = mapValue;
total++;
}
}
for (int i = 0; i < m_cAlphabet[i] != '\0'; i++) {
// turn the character into a string
std::string s = NordicOS::getString(m_cAlphabet[i]);
// set value
map[s] = (map[s] / total);
}
m_mLastLetterChance = map;
}
void Markov::generateLetterToLetterMap() {
std::map<std::string, std::map<std::string, double> > map;
// create the map
for (int i = 0; i < m_cAlphabet[i] != '\0'; i++) {
std::string s = NordicOS::getString(m_cAlphabet[i]);
map[s] = getAlphabetMap();
}
// count the amount of times 2 letter appear next to each other
for (std::string c : m_vNames) {
char *name = new char[(c.size() + 1)];
name[c.size()] = 0;
memcpy(name, c.c_str(), c.size());
for (int i = 0; i < name[i] != '\0'; i++) {
std::string firstChar = NordicOS::getString(name[i]);
std::string secondChar = NordicOS::getString(name[(i + 1)]);
if (map.find(firstChar) != map.end()) {
if (map[firstChar].find(secondChar) != map[firstChar].end()) {
double mapValue = map[firstChar][secondChar];
mapValue += 1;
map[firstChar][secondChar] = mapValue;
}
}
}
}
for (int i = 0; i < m_cAlphabet[i] != '\0'; i++) {
std::string firstChar = NordicOS::getString(m_cAlphabet[i]);
double total = 0;
if (map.find(firstChar) != map.end()) {
for (std::map<std::string, double>::iterator i = map[firstChar].begin(); i != map[firstChar].end(); ++i) {
std::string secondChar = i->first;
if (map[firstChar].find(secondChar) != map[firstChar].end()) {
total += map[firstChar][secondChar];
}
}
}
for (int j = 0; j < m_cAlphabet[j] != '\0'; j++) {
std::string secondChar = NordicOS::getString(m_cAlphabet[j]);
double mapValue = (map[firstChar][secondChar] / total);
map[firstChar][secondChar] = mapValue;
}
}
m_mLetterToLetterChance = map;
}
std::map<std::string, double> Markov::getAlphabetMap() {
std::map<std::string, double> map;
double d = 0;
for (int i = 0; i < m_cAlphabet[i] != '\0'; i++) {
std::string s = NordicOS::getString(m_cAlphabet[i]);
map[s] = d;
}
return map;
}
Markov::~Markov() {
m_pLogger = nullptr;
}
};
};
#ifndef NordicArts_Game_Markov_H
#define NordicArts_Game_Markov_H
#include <boost/locale.hpp>
#include "../Includes.hpp"
#include <NordicOS/OS.hpp>
#include <NordicOS/Logger/Logger.hpp>
#include <NordicOS/Time/Time.hpp>
namespace NordicArts {
namespace GameNS {
class Markov {
// Variables
public:
protected:
private:
std::map<std::string, double> m_mFirstLetterChance;
std::map<std::string, double> m_mLastLetterChance;
std::map<std::string, std::map<std::string, double> > m_mLetterToLetterChance;
std::vector<std::string> m_vNames;
char m_cAlphabet[28] = "abcdefghijklmnopqrstuvqwxyz";
float m_fVariance = 0.0f;
NordicOS::Logger *m_pLogger = nullptr;
bool m_bDebug;
// Methods
public:
Markov();
Markov(NordicOS::Logger *pLogger);
virtual ~Markov();
std::string generateWord();
void setVariance(float fVariance);
protected:
private:
void init();
void fillNameList();
void generateFirstLetterMap();
void generateLastLetterMap();
void generateLetterToLetterMap();
std::map<std::string, double> getAlphabetMap();
std::locale m_pLocale;
};
};
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment