// 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

// It is specific implementation for "player implementation"
// concept created in code generation process.
// Implementation is specified by STATE data used by the 
// implementation & transform needed to obtain this STATE 
// data from observation provided to player.
// Also, there is information concerning 

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

  BJSumCardState _currState;                   // Current state.
  Action _lastAction;                     // Action which was choosen 
			                  // last time.
  // policy : State -> Action should be provided for any implementation 
  Policy<BJSumCardState,Action>* _myPolicy;    
  // algorithm : learning for states used in this implementation...
  Learning_Alg<BJSumCardState,Action>* _myAlg;

 public:

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

	_myPolicy = policy;
	_myAlg    = alg;

  }	

  // Perform Observation->State transform.
  // May be manually updated!
  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;
  }
    
  // choose action according to the implementation policy/strategy
  virtual Action choose_action() {

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

  // update algorithm statistics when information about reward
  // obtained by last action is received
  virtual void get_step_reward (double lastReward) {

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

  // algorithm should be notified that new run is started
  virtual void start_run () {

    _myAlg->start_run(_currState);
  }

  // some kinds of algorithms should be notified that run is finished
  virtual void finish_run () {

    _myAlg->finish_run();
  }

  // print all statistics obtained by algorithm.
  virtual void print_stats () {

    _myAlg->print_stats();
  }

};
 
// It's builder for specific implementation.

//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:

  // creates algorithm object & specifies what actions may be
  // executed for every possible state.
  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 = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(OVER);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(FINAL); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(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;

    // create policy object - for implementation using fixed
    // and not on-line (eps-greedy) policy.

    // GENERATED CODE FOR POLICY CHOISE - START
    const_policy <BJSumCardState,Action>* myPolicy = new const_policy<BJSumCardState,Action>;
if (! strcmp(policyKind,"PolicySumCard16")) {
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(16); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = BJSum(17);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(FINAL); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(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 = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = BJSum(OVER);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
myPolicy->set_state_action(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(FINAL); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(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) {
    // Same actions as for any algorithm creation, but  this time
    // policy is on-line (eps-greedy) which means it is specified
    // by algorithm itself.
	
    _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 = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),HIT);
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(OVER);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(BJACE); oppCard_cnt = BJCardVal(int (oppCard_cnt) + 1))
_myAlg->set_in_table(BJSumCardState(mySum_cnt,oppCard_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(FINAL); mySum_cnt = BJSum(int (mySum_cnt) + 1))
for (BJCardVal oppCard_cnt = BJCardVal(BJ2);  oppCard_cnt <= BJCardVal(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) {
	cerr << "Algorithm creation is failed!\n"; 
	return 0;
    }
    if (!_myPolicy) {
	cerr << "Policy creation is failed!\n"; 
	return 0;
    }

    // only if policy and algorithm were created successfully - 
    // implementation creation succeded
    return new SmartPlayer_PlayerImp<Observation,Action>(_myPolicy,_myAlg);
  }


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

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

};




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

// It is specific implementation for "player implementation"
// concept created in code generation process.
// Implementation is specified by STATE data used by the 
// implementation & transform needed to obtain this STATE 
// data from observation provided to player.
// Also, there is information concerning 

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

  BJSumState _currState;                   // Current state.
  Action _lastAction;                     // Action which was choosen 
			                  // last time.
  // policy : State -> Action should be provided for any implementation 
  Policy<BJSumState,Action>* _myPolicy;    
  // algorithm : learning for states used in this implementation...
  Learning_Alg<BJSumState,Action>* _myAlg;

 public:

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

	_myPolicy = policy;
	_myAlg    = alg;

  }	

  // Perform Observation->State transform.
  // May be manually updated!
  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);
  }
    
  // choose action according to the implementation policy/strategy
  virtual Action choose_action() {

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

  // update algorithm statistics when information about reward
  // obtained by last action is received
  virtual void get_step_reward (double lastReward) {

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

  // algorithm should be notified that new run is started
  virtual void start_run () {

    _myAlg->start_run(_currState);
  }

  // some kinds of algorithms should be notified that run is finished
  virtual void finish_run () {

    _myAlg->finish_run();
  }

  // print all statistics obtained by algorithm.
  virtual void print_stats () {

    _myAlg->print_stats();
  }

};
 
// It's builder for specific implementation.

//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:

  // creates algorithm object & specifies what actions may be
  // executed for every possible state.
  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 = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = BJSum(OVER);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(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;

    // create policy object - for implementation using fixed
    // and not on-line (eps-greedy) policy.

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

if (! strcmp(policyKind,"PolicySum18")) {
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(18); mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = BJSum(19);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
myPolicy->set_state_action(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(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) {
    // Same actions as for any algorithm creation, but  this time
    // policy is on-line (eps-greedy) which means it is specified
    // by algorithm itself.
	
    _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 = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),HIT);
for (BJSum mySum_cnt = BJSum(MIN);  mySum_cnt <= BJSum(POINT); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = BJSum(OVER);  mySum_cnt <= BJSum(OVER); mySum_cnt = BJSum(int (mySum_cnt) + 1))
_myAlg->set_in_table(BJSumState(mySum_cnt),STOP);
for (BJSum mySum_cnt = BJSum(FINAL);  mySum_cnt <= BJSum(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) {
	cerr << "Algorithm creation is failed!\n"; 
	return 0;
    }
    if (!_myPolicy) {
	cerr << "Policy creation is failed!\n"; 
	return 0;
    }

    // only if policy and algorithm were created successfully - 
    // implementation creation succeded
    return new SimplePlayer_PlayerImp<Observation,Action>(_myPolicy,_myAlg);
  }


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

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

};




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

// This file contains code for player implementation choise.
// Generated code containing specific implementations names
// is included. 

//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() {
	// Singelton...

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

	// Use generated code for specific implementation choise.
  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;
  }

};


