I was inspired to write a small C++11 program that would generate so-called Conway numbers, or 'look and say' numbers. Essentially, given the nth term, e.g. 11112, the next is simply the pronunciation of the former term; in our case 4112, because there were 4 1's and only one 2. Another example: '13' to '1113'.
The following is the source code of the program in its entirety for completeness (omit stdafx.h include if not compiling with MS Visual Studio):
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
using namespace std;
void print_usage(){
cout << endl << "Conway Number Generator";
cout << endl << "Arguments: initializer followed by nth term to be printed" << endl;
}
string say(string s){
// Returns string said phonetically
// e.g. '111' becomes '31'
unsigned int sz = s.size();
if (sz == 1){
s.insert(0, "1");
}
else{
s.insert(0, to_string(sz));
s.erase(2, sz-1);
}
return s;
}
string get_next(string x){
// Returns next term in Conway sequence
unsigned prev_point = 0;
vector<string> grp;
string tmp;
tmp.resize(x.size());
// Organize sequence in group of identical consecutive characters
for (unsigned int i = 0; i < x.size(); ++i){
if (i != x.size() - 1){
if (x.at(i) != x.at(i + 1)){
tmp.assign(x, prev_point, i - prev_point);
grp.push_back(tmp);
prev_point = i + 1;
tmp.clear();
}
}
else if (i != 0){
if (x.at(i) != x.at(i - 1)){
tmp = x.at(i);
grp.push_back(tmp);
tmp.clear();
}
}
}
// Phonetically say each group
// Could use a lambda: transform(begin(grp), end(grp), begin(said_grp)[=](string s){return say(s);});
// if I create a new vector<string> said_grp to copy in
// That didn't help the runtime error
for (auto& i : grp)
i = say(i);
// Join each vector<string> entry into a single string
string next_seq;
next_seq = accumulate(begin(grp), end(grp), string(""));
return next_seq;
}
string conway(string init, int n){
// Print out nth Conway term
// starting sequence at init
for (int i = 1; i <= n; ++i)
init = get_next(init);
return init;
}
int main(int argc, const char* argv[]){
if (argc < 3){
print_usage();
return 0;
}
cout << endl << "Conway number: " << conway(argv[1], stoi(argv[2])) << endl;
return 0;
}
The general approach:
- Accept two arguments: the first term of the Conway sequence, and an integer
n
choose to compute the nth term of that sequence. - The function
conway(...)
loops through applyingget_next()
to the initial stringn
times. - The function
say()
'pronounces' the numbers. get_next()
functions by splitting the entire number into consecutive identical numbers; each is then transformed bysay()
.
The issue I'm having is an error, std::out_of_range
, from the return statement of my say()
function. However, I can recall testing say()
alone with various inputs, and it never caused an exception. I must be using it incorrectly somehow. As I note in the code comments, I tried using the STL transform instead of a for
loop with a lambda before, same error.
Note: to those interested in the Conway sequence, see the original paper by Conway. They admit some interesting properties, and it appears they give rise to a constant known as Conway's constant which was shown to be algebraic.