#include "game_def.h"
#include <iostream.h>
#include <list>

#include "pack.h"

#include "../rl_headers/rl_player.h"
#include "pl_imp1.h"


Pack thePack;

//card values are given according to "our" rules (ACE is always 11)
BJCardVal card_value (CardVal theCard) {

  if (theCard < JACK) {
    return BJCardVal (theCard);
  }
  if (theCard == ACE) {
    return BJACE;
  }
  return BJPICT;
}

typedef list<BJCardVal> ListOfCards;

// This structure contains all the data observable to gambler.
struct GamblerObservStruct {
  ListOfCards    m_MyCards; //should be implemented...
  BJCardVal      m_OpponentCard;
  int            m_Sum;
};

GamblerObservStruct GamblerObservation;

int play_result (int playerSum, int houseSum) {

  //  cout << playerSum << " " << houseSum << "\n";
  
  if (playerSum > 21 && houseSum > 21) return 0;
  if (playerSum > 21 && houseSum <= 21) return -1;
  if (playerSum <= 21 && houseSum > 21) return 1;
  if (playerSum < houseSum) return -1;
  if (playerSum > houseSum) return 1;
  return 0;
} 

BJCardVal get_card_from_pack (Pack* myPack) {

  return card_value((myPack->give_card()).Val());
}


void play_game (Player<GamblerObservStruct,BJActionType>* my_player) { 

  BJCardVal currCard;
  int       houseSum;
  BJActionType act;
  Pack*      myPack = &thePack;

  myPack->do_shuffle();
  currCard = get_card_from_pack(myPack);
  GamblerObservation.m_OpponentCard = get_card_from_pack(myPack);
  houseSum = (int) currCard;
  houseSum += (int) get_card_from_pack(myPack);
  
  GamblerObservation.m_Sum = (int) get_card_from_pack(myPack);
  GamblerObservation.m_Sum += (int) get_card_from_pack(myPack);

  // cout << "HERE\n";
  act = my_player->start_run(&GamblerObservation);
  // cout << "STARTED\n";

  while (act == HIT) {
    // cout << "HIT " << GamblerObservation.m_Sum << " " << houseSum << "\n" ;
    GamblerObservation.m_Sum += (int) get_card_from_pack(myPack);
    act = my_player->do_step(&GamblerObservation,0);
  }

  // cout << "STOP " << GamblerObservation.m_Sum << " " << houseSum << "\n" ;
  while (houseSum < 17) {

    houseSum += (int) get_card_from_pack(myPack);
  }
  
  double res = play_result(GamblerObservation.m_Sum,houseSum);
  GamblerObservation.m_Sum = int(FINAL);
  my_player->end_run (&GamblerObservation,res);
		      
}




using namespace std;

int main(int argc,char* argv[]) {

  istrstream ist(argv[1]);
  int rnd ;
  int stat ;
  int count;

  ist >> rnd >> stat >> count;

  PlayerFactory<GamblerObservStruct,BJActionType>* factory = 
    RL_PlayerFactory<GamblerObservStruct,BJActionType>::Instance(); 
 
  //  Player<GamblerObservStruct,BJActionType>* gambler1 = 
  //  factory->CreatePlayer("RL SimplePlayer Sarsa 1 0.9"); 

  //  Player<GamblerObservStruct,BJActionType>* gambler2 = 
  //    factory->CreatePlayer("RL SimplePlayer TD0 1 PolicySum16"); 


  Player<GamblerObservStruct,BJActionType>* gambler = 
    factory->CreatePlayer(argv[2]); 

  if (!gambler) {
    cerr << "ERROR : Can't create player!\n";
    exit (1);
  }

  srand(rnd);
  int cnt = 0;
  while (cnt < count) {
    //  cout << cnt << "\n";
    play_game (gambler);

    if (cnt % stat == 0)
      gambler->print_stats();
    cnt ++;
  }

  gambler->print_stats();
}

