// TSolver.cpp: implementation of the TSolver class.
//
//////////////////////////////////////////////////////////////////////

#include <math.h>

#include "stdafx.h"
#include "TSolver.h"
#include "TPattern.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

TSolver::TSolver() :
 NetBP( 3,    // 3 слоя распознавания
      SOLVER_INPUTS_NUMB,  // количество входов - данных сенсоров (см. Описание нейросетей и реализации)
      SOLVER_MIDDLE_NUMB,  // количество нейронов промежуточного слоя (подсчитано эмпирически)
      SOLVER_OUTPUTS_NUMB  // количество выходов - что делать лифту (см. Описание нейросетей и реализации)
      )
{
   name[0] = '\0';

   stopLearning = false;

   FullConnect();
   Randomize( 1 );
   SetCycle( 0 );
}

TSolver::~TSolver()
{
   name[0] = '\0';
}

void TSolver::reset()
{
//   Randomize( 1 );
   SetCycle( 0 );
}

int TSolver::loadFromFile( const char *fileName )
{
   if( LoadFromFile( fileName ) )
      return 1;

   FullConnect();

   strcpy( name, fileName );

   return 0;
}

int TSolver::saveToFile( const char *fileName )
{
   if( SaveToFile( fileName ) )
      return 1;

   strcpy( name, fileName );

   return 0;
}

#define LAST_DIFF_DELTA 0.05

void TSolver::learn( TSolverLearnPattern &p )
{
//   int isConverged = 0;

   lastDiff = 1.0;

   //while( (GetCycle() >= 0 || isConverged < 10) && !stopLearning )
   while( lastDiff > LAST_DIFF_DELTA  && !stopLearning )
   {
      //if( IsConverged() )
      //{   isConverged++; }
      //else
      //{   
      //   if( isConverged > 0 ) 
      //      isConverged--;  
      //}

      NextCycle();

      int numb = p.getNumb();

      int *ref = new int[numb];
      
      for( int i = 0; i < numb; i++ )
         ref[i] = 0;

      lastDiff = 0.0;
      for( i = 0; i < numb; i++ )
      {
         //srand( (unsigned) time(NULL));
         int j = rand()%numb;
         while( ref[j] )
         {
            j = rand()%numb;
         }

         ref[j] = 1;
         Cycle( p.get(j)->i, p.get(j)->o );
      }
     
      delete [] ref;
   }

   if( stopLearning ) stopLearning = false;
}

static int calcOut( float out )
{
//   float round = floorf( out + 0.5 );
//   if( round - out > 0.2 ) return UNDEFINED;
//   else return round;

   return floorf( out + 0.5 );
}

void TSolver::solve(  TEnvStateSet &envStateSet, TControlSet &controlSet )
{
   LayerBP    *layer;
   unsigned    rL, numbImgs;
   float       inp[SOLVER_INPUTS_NUMB];
   float       out[SOLVER_OUTPUTS_NUMB];
   int         numbMin;

   inp[0] = (float)(int)envStateSet.doorsState;
   inp[1] = (float)(int)envStateSet.elevState;
   inp[2] = (float)(int)envStateSet.elevTask;
   inp[3] = (float)(int)envStateSet.whereUppestButt;
   inp[4] = (float)(int)envStateSet.isElevOnThisFloorPressed;
   inp[5] = (float)(int)envStateSet.isButtUpOnThisFloorPressed;
   inp[6] = (float)(int)envStateSet.isButtDownOnThisFloorPressed;

   for( int i = 0; i < SOLVER_INPUTS_NUMB - 1; i++ )
      inp[i] = ((float)inp[i])/SOLVER_PATT_COEFF;

   inp[7] = envStateSet.wherePopulestFloor + 1.5;
   inp[7] /= 6;
   
   SetNetInputs( inp );
   
   Propagate();
   layer = GetLayer( rang - 1 );

      // Находим выходы
   for( rL = 0; rL < SOLVER_OUTPUTS_NUMB; rL++ )
      out[rL] = layer->neurons[rL].axon;

   for( int o = 0; o < SOLVER_OUTPUTS_NUMB; o++ )
      out[o] *= SOLVER_PATT_COEFF;

   for( o = 0; o < SOLVER_OUTPUTS_NUMB; o++ )
   {
      if( out[o] > 4.5 ) out[o] = 1; 
      else               out[o] = 0; 
   }

   controlSet.doorsCmd = (TElevDoorsCmd)9;
   controlSet.elevCmd  = (TElevCmd)9;
   controlSet.elevTask = (TElevTask)9;
   if( out[0] == 1 ) 
   {
      if( out[1] == 0 )
         controlSet.doorsCmd = ELEV_DOORS_CMD_OPEN;
   }
   else if( out[1] = 1 )
   {
      if( out[0] == 0 )
         controlSet.doorsCmd = ELEV_DOORS_CMD_CLOSE;
   }

   if( out[2] == 1 )
   {
      if( out[3] == 0 && out[4] == 0 )
         controlSet.elevCmd = ELEV_CMD_STOP;
   }
   else if( out[3] == 1 )
   {
      if( out[2] == 0 && out[4] == 0 )
         controlSet.elevCmd = ELEV_CMD_UP;
   }
   else if( out[4] == 1 )
   {
      if( out[2] == 0 && out[3] == 0 )
         controlSet.elevCmd = ELEV_CMD_DOWN;
   }
   
   if( out[5] == 1 )
   {
      if( out[6] == 0 && out[7] == 0 )
         controlSet.elevTask = ELEV_TASK_STOP;
   }
   else if( out[6] == 1 )
   {
      if( out[5] == 0 && out[7] == 0 )
         controlSet.elevTask = ELEV_TASK_UP;
   }
   else if( out[7] == 1 )
   {
      if( out[5] == 0 && out[6] == 0 )
         controlSet.elevTask = ELEV_TASK_DOWN;
   }

   if( controlSet.elevCmd == 9 && controlSet.elevTask == 9 )
   {
      controlSet.elevCmd   = ELEV_CMD_STOP;
      controlSet.elevTask  = ELEV_TASK_STOP;
   }
}

