#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <memory>
#include <cstdlib>
#include <cstring>
#include <ctime>
void panic(const char *s)
{
std::cerr << "\nFatal: " << s << '\n';
exit(0);
}
class table {
struct entry {
int total;
std::map<char, int> probabilities;
};
int order;
std::map<std::string, entry> tab;
std::vector<char> buf;
void clearbuf();
void advancebuf(char c);
public:
table(const char *fn, int order);
void maketext();
void square();
void invert();
};
void table::clearbuf()
{
memset(&buf[0], 0, order);
}
void table::advancebuf(char c)
{
memmove(&buf[0], &buf[1], order - 1);
buf[order - 1] = c;
}
table::table(const char *fn, int order_)
: order(order_)
, buf(order_)
{
clearbuf();
std::ifstream in(fn);
if (in.fail())
panic("Error opening file\n");
while (!in.eof()) {
char c = in.get();
if (in.fail() && !in.eof())
panic("Error reading file\n");
if (in.eof())
c = 0;
entry &e = tab[std::string(&buf[0], order)];
e.total++;
e.probabilities[c]++;
advancebuf(c);
}
}
void table::maketext()
{
clearbuf();
for (;;) {
std::map<std::string, entry>::const_iterator it =
tab.find(std::string(&buf[0], order));
if (it == tab.end())
panic("Dead end!");
const entry &e = it->second;
int r = rand() % e.total;
std::map<char, int>::const_iterator it2 =
e.probabilities.begin();
while (r > 0 && it2 != e.probabilities.end()) {
r -= it2->second;
if (r < 0)
break;
++it2;
}
if (it2 == e.probabilities.end())
panic("No entry!?");
char c = it2->first;
if (!c)
return;
std::cout << c;
advancebuf(c);
}
}
void table::square()
{
for (std::map<std::string, entry>::iterator it = tab.begin();
it != tab.end(); ++it) {
entry &e = it->second;
int total = 0;
for (std::map<char, int>::iterator it2 = e.probabilities.begin();
it2 != e.probabilities.end(); ++it2) {
it2->second *= it2->second;
total += it2->second;
}
e.total = total;
}
}
void table::invert()
{
for (std::map<std::string, entry>::iterator it = tab.begin();
it != tab.end(); ++it) {
entry &e = it->second;
int min = 100000, max = 0;
for (std::map<char, int>::const_iterator it2 = e.probabilities.begin();
it2 != e.probabilities.end(); ++it2) {
int p = it2->second;
if(p < min)
min = p;
if(p > max)
max = p;
}
int total = 0;
for (std::map<char, int>::iterator it2 = e.probabilities.begin();
it2 != e.probabilities.end(); ++it2) {
it2->second = max + min - it2->second;
total += it2->second;
}
e.total = total;
}
}
int main(int argc, const char **argv)
{
if (argc != 4) {
std::cerr << "Usage: " << argv[0] << " filename order(1..10) modifier(none,square,invert)\n";
return 1;
}
const char *fn = argv[1];
int order = atoi(argv[2]);
if (order < 1 || order > 10) {
panic("Order must be in range [1..10]");
}
char modifier = argv[3][0];
if (modifier != 'n' && modifier != 's' && modifier != 'i') {
panic("Modifier must be one of n, s or i");
}
srand(time(NULL));
table tab(fn, order);
if (modifier == 's') {
tab.square();
}
if (modifier == 'i') {
tab.invert();
}
tab.maketext();
return 0;
}
|