Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
259 lines
6.4 KiB
C++
259 lines
6.4 KiB
C++
#pragma warning (disable:4786)
|
|
#include "ai nnet.hpp"
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
|
|
Back_Layer::Back_Layer (int nodes,int ninputs,bool first)
|
|
{
|
|
Create (nodes,ninputs,first);
|
|
}
|
|
|
|
void Back_Layer::Create (int nodes,int ninputs,bool first)
|
|
{
|
|
int i,j;
|
|
double temp;
|
|
|
|
next = NULL;
|
|
prev = NULL;
|
|
num_nodes = nodes;
|
|
next = prev = NULL;
|
|
thenodes = (Back_Node *) calloc (sizeof (Back_Node),num_nodes);
|
|
num_inputs = ninputs;
|
|
inputs = (double *) calloc (sizeof (double),num_inputs);
|
|
outputs = (double *) calloc (sizeof (double),num_nodes);
|
|
errors = (double *) calloc (sizeof (double),num_nodes);
|
|
for (i=0;i<num_inputs;i++)
|
|
{ inputs[i] = 0;
|
|
}
|
|
for (i=0;i<num_nodes;i++)
|
|
{
|
|
thenodes[i].weights = (double *) calloc (sizeof (double),num_inputs);
|
|
thenodes[i].deltas = (double *) calloc (sizeof (double),num_inputs);
|
|
for (j=0;j<num_inputs;j++)
|
|
{
|
|
thenodes[i].deltas[j] = 0.0;
|
|
if (!first)
|
|
{
|
|
temp = rand ();
|
|
temp /= ((double) RAND_MAX);
|
|
temp = temp - 0.5;
|
|
thenodes[i].weights[j] = temp;
|
|
}
|
|
else
|
|
{
|
|
thenodes[i].weights[j] = 1.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Back_Layer::~Back_Layer (void)
|
|
{
|
|
Destroy ();
|
|
}
|
|
|
|
void Back_Layer::Destroy (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i<num_nodes;i++)
|
|
{
|
|
free (thenodes[i].weights);
|
|
free (thenodes[i].deltas);
|
|
}
|
|
free (thenodes);
|
|
free (inputs);
|
|
free (errors);
|
|
}
|
|
|
|
void Back_Layer::propagate_forward (void)
|
|
{
|
|
int i,j;
|
|
double sum;
|
|
|
|
assert ((!next) || (num_nodes == next->num_inputs));
|
|
for (i=0;i<num_nodes;i++)
|
|
{
|
|
if (!prev)
|
|
outputs[i] = inputs[i];
|
|
else
|
|
{
|
|
sum = 0.0;
|
|
for (j=0;j<num_inputs;j++)
|
|
{ sum += (inputs[j]*thenodes[i].weights[j]);
|
|
}
|
|
outputs[i] = 1.0/(1.0+exp (-1.0*sum));
|
|
}
|
|
if (next)
|
|
next->inputs[i] = outputs[i];
|
|
}
|
|
}
|
|
|
|
void Back_Layer::propagate_error (void)
|
|
{
|
|
int i,j;
|
|
|
|
assert (next);
|
|
for (i=0;i<num_nodes;i++)
|
|
{
|
|
errors[i] = 0;
|
|
for (j=0;j<next->num_nodes;j++)
|
|
{
|
|
errors[i] += (next->errors[j]*next->thenodes[j].weights[i]);
|
|
}
|
|
errors[i] *= (outputs[i] * (1.0-outputs[i]));
|
|
}
|
|
}
|
|
|
|
void Back_Network::correct (bool finetune)
|
|
{
|
|
compute_error (finetune);
|
|
propagate_error ();
|
|
adjust_weights ();
|
|
}
|
|
|
|
void Back_Network::adjust_weights (void)
|
|
{
|
|
int i,j,k;
|
|
double tochange;
|
|
|
|
for (i=1;i<num_layers;i++)
|
|
{
|
|
for (j=0;j<thelayers[i].num_nodes;j++)
|
|
{
|
|
for (k=0;k<thelayers[i].num_inputs;k++)
|
|
{
|
|
tochange = thelayers[i].inputs[k]*eta*thelayers[i].errors[j];
|
|
tochange += (alpha*thelayers[i].thenodes[j].deltas[k]);
|
|
thelayers[i].thenodes[j].deltas[k] = tochange;
|
|
thelayers[i].thenodes[j].weights[k] += tochange;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Back_Network::propagate_error (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=(num_layers-2);i>=0;i--)
|
|
{
|
|
thelayers[i].propagate_error ();
|
|
}
|
|
}
|
|
|
|
void Back_Network::compute_error (bool finetune)
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i<num_outputs;i++)
|
|
{
|
|
if (!finetune)
|
|
thelayers[num_layers-1].errors[i] = (wanted_output[i] - output[i]);
|
|
else
|
|
{
|
|
thelayers[num_layers-1].errors[i] = output[i];
|
|
thelayers[num_layers-1].errors[i] *= (1.0 - output[i]);
|
|
thelayers[num_layers-1].errors[i] *= (wanted_output[i] - output[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function does not work, the net will not stabalize to a solution
|
|
void Back_Network::Learn (bool iscorrect,bool finetune,double error)
|
|
{
|
|
int i;
|
|
double *temp;
|
|
|
|
if (iscorrect)
|
|
{
|
|
temp = get_answer ();
|
|
for (i=0;i<thelayers[num_layers-1].num_nodes;i++)
|
|
{
|
|
if (temp[i] > 0.5)
|
|
wanted_output[i] = 1.0;
|
|
else
|
|
wanted_output[i] = 0.0;
|
|
}
|
|
correct (finetune);
|
|
}
|
|
else
|
|
{
|
|
temp = get_answer ();
|
|
for (i=0;i<thelayers[num_layers-1].num_nodes;i++)
|
|
{
|
|
if ((rand ()%100) < error)
|
|
{
|
|
if (temp[i] > 0.5)
|
|
wanted_output[i] = 1.0;
|
|
else
|
|
wanted_output[i] = 0.0;
|
|
}
|
|
else
|
|
{
|
|
if ((rand ()&0x01))
|
|
wanted_output[i] = 1.0;
|
|
else
|
|
wanted_output[i] = 0.0;
|
|
}
|
|
}
|
|
correct (finetune);
|
|
}
|
|
}
|
|
|
|
Back_Network::Back_Network (int layers,int *num_nodes,double neta,double nalpha)
|
|
{
|
|
int i;
|
|
|
|
eta = neta;
|
|
alpha = nalpha;
|
|
|
|
num_inputs = num_nodes[0];
|
|
num_outputs = num_nodes[layers-1];
|
|
input = (double *) calloc (sizeof (double),num_inputs);
|
|
output = (double *) calloc (sizeof (double),num_outputs);
|
|
wanted_output = (double *) calloc (sizeof (double),num_outputs);
|
|
num_layers = layers;
|
|
thelayers = (Back_Layer *) calloc (sizeof (Back_Layer),layers);
|
|
thelayers[0].Create (num_nodes[0],num_nodes[0],true);
|
|
thelayers[0].next = &(thelayers[1]);
|
|
for (i=1;i<layers;i++)
|
|
{
|
|
thelayers[i].Create (num_nodes[i],num_nodes[i-1],false);
|
|
thelayers[i].prev = &(thelayers[i-1]);
|
|
thelayers[i].next = &(thelayers[i+1]);
|
|
}
|
|
thelayers[layers-1].next = NULL;
|
|
}
|
|
|
|
Back_Network::~Back_Network (void)
|
|
{
|
|
int i;
|
|
for (i=0;i<num_layers;i++)
|
|
{
|
|
thelayers[i].Destroy ();
|
|
}
|
|
free (thelayers);
|
|
}
|
|
|
|
void Back_Network::propagate_forward (double *ninputs)
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i<num_inputs;i++)
|
|
{
|
|
input[i] = ninputs[i];
|
|
thelayers[0].inputs[i] = input[i];
|
|
}
|
|
for (i=0;i<num_layers;i++)
|
|
{
|
|
if (i != (num_layers-1))
|
|
assert (thelayers[i].num_nodes == thelayers[i+1].num_inputs);
|
|
thelayers[i].propagate_forward ();
|
|
}
|
|
for (i=0;i<num_outputs;i++)
|
|
{
|
|
output[i] = thelayers[num_layers-1].outputs[i];
|
|
}
|
|
}
|