// generate definitions for state BJSumState
struct BJSumState {

	BJSum mySum;
	BJSumState() {}
	BJSumState(BJSum p_mySum) {
		mySum = p_mySum;
	}
};
//should provide output operator for generic results output
ostream& operator<< (ostream& out, BJSumState st) {
	out <<  st.mySum;
}
//should provide operator for map container usage
bool operator< (BJSumState st1, BJSumState st2) {

	return st1.mySum < st2.mySum;
}
bool operator== (BJSumState st1, BJSumState st2) {
	return
	(st1.mySum == st2.mySum);
}

// generate definitions for state BJSumCardState
struct BJSumCardState {

	BJSum mySum;
	BJCardVal oppCard;
	BJSumCardState() {}
	BJSumCardState(BJSum p_mySum,BJCardVal p_oppCard) {
		mySum = p_mySum;
		oppCard = p_oppCard;
	}
};
//should provide output operator for generic results output
ostream& operator<< (ostream& out, BJSumCardState st) {
	out << st.mySum << "," <<  st.oppCard;
}
//should provide operator for map container usage
bool operator< (BJSumCardState st1, BJSumCardState st2) {

	if (st1.mySum != st2.mySum) return  st1.mySum < st2.mySum;
	return st1.oppCard < st2.oppCard;
}
bool operator== (BJSumCardState st1, BJSumCardState st2) {
	return
	(st1.mySum == st2.mySum) && 
	(st1.oppCard == st2.oppCard);
}


// generate definitions for player SmartPlayer
// generate definitions for policy PolicySumCard16
// generate definitions for policy PolicyHitOnly2
// PARAMS: KIND STATE OBS2STATE MDPINIT POLICIES
//"template" for auto-generation process

 
template <class Observation, class Action>
class SmartPlayer_PlayerImp : public PlayerImp<Observation,Action>  {

  BJSumCardState _currState;
  Action _lastAction;
  Policy<BJSumCardState,Action>* _myPolicy;
  Learning_Alg<BJSumCardState,Action>* _myAlg;

 public:

  SmartPlayer_PlayerImp (
	  Policy<BJSumCardState,Action>* policy,
	  Learning_Alg<BJSumCardState,Action>* alg) {

	_myPolicy = policy;
	_myAlg    = alg;

  }	

  virtual void set_state (Observation* currObserv) {

    if (currObserv->m_Sum == 40) _currState.mySum = FINAL;else if (currObserv->m_Sum > 22) _currState.mySum = OVER; else _currState.mySum = BJSum(currObserv->m_Sum);_currState.oppCard = currObserv->m_OpponentCard;
  }
    
  virtual Action choose_action() {

    _lastAction =  _myPolicy->choose_action(_currState);
    return _lastAction;
  }

  virtual void get_step_reward (double lastReward) {

    _myAlg->get_step (_lastAction,_currState,lastReward);
  }

  virtual void start_run () {

    _myAlg->start_run(_currState);
  }

  virtual void finish_run () {

    _myAlg->finish_run();
  }

  virtual void print_stats () {

    _myAlg->print_stats();
  }

};
 

//static data member templates are not implemented - so we have
//to use this "trick" for singelton implementation !?
void* builder_SmartPlayer = 0; 

template <class Observation, class Action>
class SmartPlayer_PlayerBuilder : 
	public PlayerImpBuilder<Observation,Action> {

  Policy<BJSumCardState,Action>* _myPolicy;
  Learning_Alg<BJSumCardState,Action>* _myAlg;

 protected:
  SmartPlayer_PlayerBuilder<Observation,Action>() {}
  
 public:

  virtual void create_algorithm (AlgorithmKind algKind, double lambdaVal) {

    _myAlg = 0;

    if (algKind == ALG_TD0)
      _myAlg = new TD0_Alg<BJSumCardState,Action>(lambdaVal);

    else 
      if (algKind == ALG_QLRN)
	_myAlg = new QLrn_Alg<BJSumCardState,Action>(lambdaVal);

    // GENERATED CODE FOR MDP INITIALIZATION - START
    for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),FINISH);

    // GENERATED CODE FOR MDP INITIALIZATION - END
  }

  virtual void create_policy (char* policyKind) {
    
    _myPolicy = 0;

    // GENERATED CODE FOR POLICY CHOISE - START
    const_policy <BJSumCardState,Action>* myPolicy = new const_policy<BJSumCardState,Action>;
if (! strcmp(policyKind,"PolicySumCard16")) {
for (BJSum mySum_cnt = MIN;  mySum_cnt <= 16; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = 17;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),FINISH);
_myPolicy = myPolicy;}

if (! strcmp(policyKind,"PolicyHitOnly2")) {
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),FINISH);
_myPolicy = myPolicy;}


    // GENERATED CODE FOR POLICY CHOISE - END

  }

  virtual void create_online_algorithm (AlgorithmKind algKind, 
					double lambdaVal,
					double eps) {

    _myPolicy = 0;
    _myAlg    = 0;

    if (algKind == ALG_SARSA) {
        Sarsa_Alg<BJSumCardState,Action>* sarsa =  
	  new Sarsa_Alg<BJSumCardState,Action> (eps,lambdaVal);

        _myPolicy = sarsa;
        _myAlg    = sarsa;
	
        // GENERATED CODE FOR MDP INITIALIZATION - START
        for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJ2;  oppCard_cnt <= BJACE; oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),FINISH);
	
        // GENERATED CODE FOR MDP INITIALIZATION - END

    }
      
  }
  
  virtual PlayerImp<Observation,Action>* get_player_imp() {

    if (!_myAlg) return 0;
    if (!_myPolicy) return 0;	

    return new SmartPlayer_PlayerImp<Observation,Action>(_myPolicy,_myAlg);
  }


  static SmartPlayer_PlayerBuilder<Observation,Action>* Instance() {

    if (!builder_SmartPlayer) 
      builder_SmartPlayer = 
	new SmartPlayer_PlayerBuilder<Observation,Action>();
    
    return builder_SmartPlayer;
  }

};




// generate definitions for player SimplePlayer
// generate definitions for policy PolicyHitOnly
// generate definitions for policy PolicySum16
// PARAMS: KIND STATE OBS2STATE MDPINIT POLICIES
//"template" for auto-generation process

 
template <class Observation, class Action>
class SimplePlayer_PlayerImp : public PlayerImp<Observation,Action>  {

  BJSumState _currState;
  Action _lastAction;
  Policy<BJSumState,Action>* _myPolicy;
  Learning_Alg<BJSumState,Action>* _myAlg;

 public:

  SimplePlayer_PlayerImp (
	  Policy<BJSumState,Action>* policy,
	  Learning_Alg<BJSumState,Action>* alg) {

	_myPolicy = policy;
	_myAlg    = alg;

  }	

  virtual void set_state (Observation* currObserv) {

    if (currObserv->m_Sum == 40) _currState.mySum = FINAL;else if (currObserv->m_Sum > 22) _currState.mySum = OVER; else _currState.mySum = BJSum(currObserv->m_Sum);
  }
    
  virtual Action choose_action() {

    _lastAction =  _myPolicy->choose_action(_currState);
    return _lastAction;
  }

  virtual void get_step_reward (double lastReward) {

    _myAlg->get_step (_lastAction,_currState,lastReward);
  }

  virtual void start_run () {

    _myAlg->start_run(_currState);
  }

  virtual void finish_run () {

    _myAlg->finish_run();
  }

  virtual void print_stats () {

    _myAlg->print_stats();
  }

};
 

//static data member templates are not implemented - so we have
//to use this "trick" for singelton implementation !?
void* builder_SimplePlayer = 0; 

template <class Observation, class Action>
class SimplePlayer_PlayerBuilder : 
	public PlayerImpBuilder<Observation,Action> {

  Policy<BJSumState,Action>* _myPolicy;
  Learning_Alg<BJSumState,Action>* _myAlg;

 protected:
  SimplePlayer_PlayerBuilder<Observation,Action>() {}
  
 public:

  virtual void create_algorithm (AlgorithmKind algKind, double lambdaVal) {

    _myAlg = 0;

    if (algKind == ALG_TD0)
      _myAlg = new TD0_Alg<BJSumState,Action>(lambdaVal);

    else 
      if (algKind == ALG_QLRN)
	_myAlg = new QLrn_Alg<BJSumState,Action>(lambdaVal);

    // GENERATED CODE FOR MDP INITIALIZATION - START
    for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),FINISH);

    // GENERATED CODE FOR MDP INITIALIZATION - END
  }

  virtual void create_policy (char* policyKind) {
    
    _myPolicy = 0;

    // GENERATED CODE FOR POLICY CHOISE - START
    const_policy <BJSumState,Action>* myPolicy = new const_policy<BJSumState,Action>;
if (! strcmp(policyKind,"PolicyHitOnly")) {
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),FINISH);
_myPolicy = myPolicy;}

if (! strcmp(policyKind,"PolicySum16")) {
for (BJSum mySum_cnt = MIN;  mySum_cnt <= 16; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = 17;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),FINISH);
_myPolicy = myPolicy;}


    // GENERATED CODE FOR POLICY CHOISE - END

  }

  virtual void create_online_algorithm (AlgorithmKind algKind, 
					double lambdaVal,
					double eps) {

    _myPolicy = 0;
    _myAlg    = 0;

    if (algKind == ALG_SARSA) {
        Sarsa_Alg<BJSumState,Action>* sarsa =  
	  new Sarsa_Alg<BJSumState,Action> (eps,lambdaVal);

        _myPolicy = sarsa;
        _myAlg    = sarsa;
	
        // GENERATED CODE FOR MDP INITIALIZATION - START
        for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = MIN;  mySum_cnt <= POINT; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = OVER;  mySum_cnt <= OVER; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = FINAL;  mySum_cnt <= FINAL; mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),FINISH);
	
        // GENERATED CODE FOR MDP INITIALIZATION - END

    }
      
  }
  
  virtual PlayerImp<Observation,Action>* get_player_imp() {

    if (!_myAlg) return 0;
    if (!_myPolicy) return 0;	

    return new SimplePlayer_PlayerImp<Observation,Action>(_myPolicy,_myAlg);
  }


  static SimplePlayer_PlayerBuilder<Observation,Action>* Instance() {

    if (!builder_SimplePlayer) 
      builder_SimplePlayer = 
	new SimplePlayer_PlayerBuilder<Observation,Action>();
    
    return builder_SimplePlayer;
  }

};




// PARAMS: IMPLEMENTATIONS
// IT'S TEMPLATE FOR CODE GENERATION PROCESS!


//static data member templates are not implemented: 
void* implement_implementChoise = 0; 
template <class Observation, class Action>
class implementChoise {

 protected:

  implementChoise<Observation,Action>() {}

 public:

  static implementChoise<Observation,Action>* Instance() {

    if (!implement_implementChoise) 
      implement_implementChoise = (void*)
        new implementChoise<Observation,Action>();
    
    return  (implementChoise<Observation,Action>*)implement_implementChoise;
  }

  PlayerImpBuilder<Observation,Action>* Choose_Impementation
    (char* playerKind) {

    cout << "Choose implementation!" << "\n";
    // GENERATED CODE - START
    if (! strcmp(playerKind,"SmartPlayer")) 
	return SmartPlayer_PlayerBuilder<Observation,Action>::Instance();
if (! strcmp(playerKind,"SimplePlayer")) 
	return SimplePlayer_PlayerBuilder<Observation,Action>::Instance();

    // GENERATED CODE - END
    
    return 0;
  }

};


