I am attempting to make an AI similar to NEAT using C++. However, I have run into a problem with getting the population to work correctly. When I use an array of custom objects, some of the data stored in each of the objects' properties is being corrupted. The data inside each of the connections in connections is set to 0xDDDDDDDD
after the net is assigned. When I test the given properties inside the constructor it seems fine but when it is assigned within the population array (in this case t
) all of the data is set to 0xDDDDDDDD
similarly to if it were deleted.
// neat network.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <cmath>
class node
{
public:
int id;
double value;
node()
{
id = 0;
value = 0;
}
node(int n)
{
id = n;
value = 0;
}
void apply(double v)
{
value = v;
}
node copy()
{
return node(id);
}
};
class connection
{
public:
double weight;
int in;
int out;
connection(int i, int o, double w=0)
{
in = i;
out = o;
weight = w;
int r = rand();
weight = ((double)(r % 2000) - 1000.0) / 1000.0;
srand(r);
}
connection()
{
in = 0;
out = 0;
weight = 0;
}
void mutate()
{
weight += (double)((rand() % 50 - 2) / 1000);
}
connection copy()
{
connection ret = connection(in, out);
ret.weight = weight;
return ret;
}
};
double sigmoid(double n)
{
return 1 / (exp(-n) + 1);
}
class net
{
public:
double* position;
int quant;
node* nodes;
int* inpernode;
connection* connections;
int connlen;
int inn;
int ut;
net(int ins, int outs, int cn=0)
{
inn = ins;
ut = outs;
quant = ins+outs;
nodes = new node[quant];
position = new double[quant];
connections = new connection[ins*outs];
inpernode = new int[quant];
for (int i = 0; i < quant; i++)
{
nodes[i] = node(i);
if (i < ins)
{
position[i] = 0;
}
else
{
position[i] = 1;
}
inpernode[i] = 0;
}
int c = 0;
connlen = ins * outs;
for (int i = 0; i < ins; i++)
{
for (int j = ins; j < quant; j++)
{
connections[c] = connection(i, j);
//std::cout << connections[c].weight << " ";
inpernode[j]++;
c++;
}
}
//std::cout << connections[0].in << std::endl;
}
net()
{
connections = new connection();
connlen = 0;
inn = 0;
inpernode = new int();
quant = 0;
nodes = new node();
position = new double();
ut = 0;
}
~net()
{
delete[] position;
delete[] nodes;
delete[] connections;
delete[] inpernode;
}
double* apply(double* inputs)
{
bool* finished = new bool[quant];
//std::cout << connections[0].in;
bool* cfinished = new bool[connlen];
int* ndone = new int[quant];
bool alldone=false;
for (int i = 0; i < connlen; i++)
{
cfinished[i] = false;
}
for (int i = 0; i < quant; i++)
{
finished[i] = i<inn;
ndone[i] = 0;
nodes[i].value = 0;
if (i < inn) {
nodes[i].value = inputs[i];
}
}
while (!alldone)
{
alldone = true;
for (int i = 0; i < connlen; i++)
{
//std::cout << quant;
if (finished[connections[i].in] && !cfinished[i])
{
alldone = false;
nodes[connections[i].out].value += connections[i].weight * sigmoid(nodes[connections[i].in].value);
cfinished[i] = true;
ndone[connections[i].out]++;
if (ndone[connections[i].out] == inpernode[connections[i].out])
{
finished[connections[i].out] = true;
}
}
}
}
double* outs = new double[ut];
for (int i = inn; i < inn + ut; i++)
{
outs[i - inn] = sigmoid(nodes[i].value);
}
return outs;
}
net copy()
{
net ret = net(inn, ut);
ret.quant = quant;
ret.connlen = connlen;
for (int i = 0; i < quant; i++)
{
ret.position[i] = position[i];
ret.nodes[i] = nodes[i].copy();
ret.inpernode[i] = inpernode[i];
}
for (int i = 0; i < connlen; i++)
{
ret.connections[i] = connections[i].copy();
}
return ret;
}
net mutate()
{
net ret = copy();
for (int i = 0; i < quant; i++)
{
if (rand() % 20 == 19)
{
connections[i].mutate();
}
if (rand() % 333 == 332)
{
nodes[quant] = node(quant);
int temp = connections[i].out;
connections[i].out = quant;
connections[connlen] = connection(quant, temp);
quant++;
connlen++;
}
}
if (rand() % 33 == 32)
{
bool done = false;
int tries = 200;
while (!done)
{
tries--;
if (tries < 0)
done = true;
int inc = rand() % quant;
if (position[inc] == 1)
continue;
int utc = rand() % quant;
if (position[inc] > position[utc])
continue;
bool found = false;
for (int i = 0; i < connlen; i++)
{
if (connections[i].in == inc && connections[i].out == utc)
found = true;
}
if (!found)
{
connections[connlen] = connection(inc, utc);
connlen++;
done = true;
}
}
}
return ret;
}
};
int main()
{
srand(2002);
/*net test = net(2, 1);
net test2 = net(2, 1);
std::cout << test.connections[0].weight << " " << test.connections[1].weight << std::endl;
std::cout << test2.connections[0].weight << " " << test2.connections[1].weight << std::endl;
double ins[] = { 0,0 };
double* cp = test.apply(ins);
std::cout << cp[0]<<" ";
cp = test2.apply(ins);
std::cout << cp[0];*/
net t[1];
t[0] = net(2, 1);
std::cout << t[0].inn << " " << t[0].ut << std::endl;
std::cout << t[0].connections[0].in << " " << t[0].connections[0].weight << std::endl;
/*net pop[100];
for (int i = 0; i < 100; i++)
{
pop[i] = net(2, 1);
std::cout << pop[i].connections[0].in << " " << pop[i].connections[1].in << " " << std::endl;
}
int* scores = new int[100];
for (int gen = 0; gen < 100; gen++)
{
for (int i = 0; i < 100; i++)
{
scores[i] = 0;
double inp[] = { 0, 0 };
double* t = pop[i].apply(inp);
if (t[0] < .1)
scores[i]++;
inp[1] = 1;
t = pop[i].apply(inp);
if (t[0] > .9)
scores[i]++;
inp[0] = 1;
inp[1] = 0;
t = pop[i].apply(inp);
if (t[0] > .9)
scores[i]++;
inp[1] = 1;
t = pop[i].apply(inp);
if (t[0] < .1)
scores[i]++;
if (scores[i] == 4)
{
std::cout << "Solved" << gen;
return 0;
}
scores[i] -= pop[i].connlen + pop[i].quant;
}
int sum = 0;
for (int i = 0; i < 100; i++)
sum += scores[i];
double avg = (double)(sum / 100);
net newpop[100];
int nplen = 0;
for (int i = 0; i < 100; i++)
{
if (scores[i] > avg)
{
newpop[nplen++] = pop[i];
}
}
for (int i = 0; i < nplen; i++)
{
pop[i] = newpop[i];
}
for (int i = nplen; i < 100; i++)
{
pop[i] = pop[i % nplen].mutate();
}
}*/
return 0;
}
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu
// Tips for Getting Started:
// 1. Use the Solution Explorer window to add/manage files
// 2. Use the Team Explorer window to connect to source control
// 3. Use the Output window to see build output and other messages
// 4. Use the Error List window to view errors
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file