See Randomizing and mutating algo class - style
I'm looking for a review of the functionality of this code, answers to the above question which also describes the code use focus on style instead.
Below is the updated code since the style feedback.
algo
is an algorithm that is dynamic. algo
instances can be created, asked to become random, mutated and also run. They can be set to remember changes they make to themselves between runs or not. They also output values, these could be used for anything from value sequences such as mathematical number sequences to controls for a bot in a game. It's straightforward to specify limits on memory or computation steps for each as well and needless to say are entirely sandboxed.
By sandboxed I mean that they only compute and produce output as described, they cannot for example use local or global variables, print to the console, #include
or write to files.
algo
s can be used where algorithms need to be portable and must be only able to calculate/compute. There is no distinction between data and instructions in an algo
.
A use is as values for directed search for algorithms such as with evolutionary algorithms, MCTS or others.
Another is in a data file that includes algorithms, like an image that includes its own way to decompress itself, that can therefore be constructed using the specific image that is to be decompressed.
They are deliberately general, being a component that could be used in many contexts and conceptually simple, as a number is.
// by Alan Tennant
// Nov 2012
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib> // for rand and abs
#include <ctime>
class algo
{
public:
std::vector<unsigned short> code;
std::vector<unsigned int> output;
bool debug_info;
algo()
{
reset1(false);
instructions_p = 11;
debug_info = true;
}
void random(unsigned int size)
{
code.clear();
output.clear();
for(unsigned int n = 0; n < size; n++)
code.push_back(rand() % instructions_p);
reset1(true);
}
void run(
unsigned long most_run_time,
unsigned int largest_program,
unsigned int largest_output_size,
bool reset)
{
if (reset && !is_reset_p)
{
reset1(true);
output.clear();
code2 = code;
code_pos = 0;
}
is_reset_p = false;
size_t code_size = code2.size();
if (debug_info && !can_resume_p)
std::cout<<"can't resume, reset first"<<std::endl;
if(code_size == 0 || most_run_time == 0)
{
out_of_time_p = true;
out_of_space_p = false;
run_time_p = most_run_time;
}
else if (can_resume_p)
{
unsigned short instruction;
bool cont = true;
if(debug_info) {
std::cout<<"size: "<<code_size<<std::endl<<std::endl;}
while(cont)
{
instruction = code2[code_pos] % instructions_p;
if(debug_info) {std::cout<<code_pos<<", ";}
code_pos = (code_pos + 1) % code_size;
switch(instruction)
{
case 0:
if(debug_info) {std::cout<<"end";}
cont = false;
can_resume_p = false;
break;
case 1:
if(debug_info) {
std::cout<<"goto p1";}
code_pos = code2[(code_pos + 1) % code_size];
break;
case 2:
if(debug_info) {
std::cout<<"if value at p1 % 2 = 0 then goto p2";}
if(code2[code2[code_pos] % code_size] % 2 == 0) {
code_pos = code2[(code_pos + 1) % code_size];}
else {
code_pos += 2;}
break;
case 3:
if(debug_info) {std::cout<<"value at p1 = value at p2";}
code2[code2[code_pos] % code_size] =
code2[code2[(code_pos + 1) % code_size] % code_size];
code_pos += 2;
break;
case 4:
if(debug_info) {
std::cout<<"value at p1 = value at p2 + value at p3";}
code2[code2[code_pos] % code_size] = (
code2[code2[(code_pos + 1) % code_size] % code_size] +
code2[code2[(code_pos + 2) % code_size] % code_size]
) % USHRT_MAX;
code_pos += 3;
break;
case 5:
{
if(debug_info)
{std::cout<<"value at p1 = value at p2 - value at p3";}
long v1 =
(long)code2[code2[(code_pos + 1) % code_size] % code_size] -
code2[code2[(code_pos + 2) % code_size] % code_size];
code2[code2[code_pos] % code_size] = abs(v1) % USHRT_MAX;
code_pos += 3;
}
break;
case 6:
{
if(debug_info) {std::cout<<"toggle value at p1";}
size_t v1 = code2[code_pos] % code_size;
unsigned short v2 = code2[v1];
if(v2 == 0) {code2[v1] = 1;}
else {code2[v1] = 0;}
code_pos++;
}
break;
case 7:
if(debug_info) {
std::cout<<"output value at p1";}
output.push_back(code2[code2[code_pos] % code_size]);
code_pos++;
break;
case 8:
if(debug_info) {std::cout<<"increase size";}
code2.push_back(0);
break;
case 9:
{
if(debug_info) {std::cout<<"increment value at p1";}
size_t v1 = code2[code_pos] % code_size;
code2[v1] = (code2[v1] + 1) % USHRT_MAX;
code_pos++;
}
break;
case 10:
{
if(debug_info) {std::cout<<"decrement value at p1";}
size_t v1 = code2[code_pos] % code_size;
code2[v1] = abs((code2[v1] - 1) % USHRT_MAX);
code_pos++;
}
break;
}
if(debug_info) {std::cout<<std::endl;}
run_time_p++;
code_size = code2.size();
code_pos = code_pos % code_size;
if(run_time_p == most_run_time) {
cont = false; out_of_time_p = true;}
if(code_size > largest_program)
{
cont = false;
can_resume_p = false;
out_of_space_p = true;
if (debug_info)
std::cout<<"became too large"<<std::endl;
}
if(output.size() > largest_output_size)
{
cont = false;
can_resume_p = false;
output.pop_back();
if (debug_info)
std::cout<<"too much output"<<std::endl;
}
}
if (debug_info)
{
std::cout<<std::endl<<"size: "<<code_size<<std::endl<<
std::endl<<"output: "<<std::endl;
size_t output_size = output.size();
for (size_t t = 0; t < output_size; t++)
std::cout<<output[t]<<std::endl;
}
}
}
void mutate(unsigned int largest_program)
{
output.clear();
size_t size;
// special mutations
while(rand() % 4 != 0) // 3/4 chance
{
size = code.size();
if(rand() % 2 == 0) // 1/2 chance
{
// a bit of code is added to the end (would prefer inserted anywhere)
if(size < largest_program)
code.push_back(rand() % instructions_p);
}
else
{
// a bit of code is removed from the end (would prefer removed from anywhere)
if(size != 0)
code.pop_back();
}
// a section of code is moved, not yet implemented.
}
// mutate bits of the code
size = code.size();
if (size > 0)
{
unsigned int most_mutation =
static_cast<unsigned int>(size * 0.1); // static_cast to support GCC
if(most_mutation < 9)
most_mutation = 8;
unsigned int mutation = rand() % most_mutation;
for(unsigned int n = 0; n < mutation; n++)
code[rand() % size] = rand() % instructions_p;
}
reset1(true);
}
#pragma region
unsigned long run_time()
{
return run_time_p;
}
bool out_of_time()
{
return out_of_time_p;
}
bool out_of_space()
{
return out_of_space_p;
}
bool can_resume()
{
return can_resume_p;
}
bool is_reset()
{
return is_reset_p;
}
private:
bool can_resume_p, is_reset_p,
out_of_time_p, out_of_space_p;
unsigned int code_pos;
unsigned short instructions_p;
unsigned long run_time_p;
std::vector<unsigned short> code2;
void reset1(bool say)
{
out_of_time_p = false;
out_of_space_p = false;
run_time_p = 0;
code2 = code;
code_pos = 0;
can_resume_p = true;
is_reset_p = true;
if (say && debug_info)
std::cout<<"reset"<<std::endl;
}
#pragma endregion
};
int main()
{
srand((unsigned int)time(NULL));
algo a = algo();
a.random(50);
std::cout<<std::endl<<std::endl;
a.run(10, 100, 10, false);
std::cout<<std::endl<<std::endl;
a.run(10, 100, 10, false);
return 0;
}
#pragma region
is still there, you stil useUSHRT_MAX
...). – Morwenn Mar 26 '14 at 12:47