//
//
#ifndef	JACKS_H
#define	JACKS_H

#include "mdp.h"
#include "clrandom.h"

#define	MAXCARS	10
#define	MAXMOVE	3

class JacksProblem;
typedef	int JackAction;

class JackState
{
public:
  // constructors
  JackState(int	a1, int	a2): n1(a1), n2(a2) {};

  int operator== (JackState & other) {
    return (n1 == other.n1 && n2 == other.n2);
  };

  // data
  int n1, n2;
};

istream	& operator >> (istream &, JackState &);
ostream	& operator << (ostream &, JackState &);


class JackStateIterator: public	iterator<JackState>
{
public:
  JackStateIterator(): current(0,0) {init();};

  // iterator protocol
  virtual int init() { current.n1 = current.n2 = 0; return !(*this);};
  virtual int operator!() {return (current.n1 <= MAXCARS && current.n2 <= MAXCARS);};
  virtual JackState & operator () () { return current; };
  virtual int operator++()
  {
    current.n2++;
    if (current.n2 > MAXCARS) {
      current.n2 = 0;
      current.n1++;
    }
    return !(*this);
  }
  virtual void operator	= (JackState newValue) {
    current = newValue;
  }
protected:
  JackState current;
};


class JacksProblem: public Problem<JackState, JackAction>
{
public:
  float	gamma;	    // discount	factor
  clrandom rngenerator;	    // random number generator
  JacksProblem(int model = 1,
	       unsigned	int seed1 = 718374,
	       unsigned	int seed2 = 374608):
    gamma(0.9),
    rngenerator(seed1, seed2),
    si((MAXCARS	+ 1)*(MAXCARS +	1)),
    pi((MAXCARS	+ 1)*(MAXCARS +	1))
  {
    if (model) buildModel();
  };

  virtual float	discountFactor() { return gamma; };

  virtual unsigned int maxState() {
    return (MAXCARS + 1) * (MAXCARS + 1);
  };

  virtual unsigned int maxAction() {
    return 11;
  }

  virtual JackAction nullAction() {
    return 0;
  }

  virtual JackAction randomAction() {
    return rngenerator.between(-MAXMOVE, +MAXMOVE);
  }

  virtual JackState nullState()	{
    return JackState(0,0);
  }

  // return an iterator	that iterates over the states
  virtual iterator<JackState> *	stateIterator()	{
    return new JackStateIterator;
  }

  virtual iterator<JackAction> * actionIterator() {
    return new rangeIterator(-MAXMOVE, +MAXMOVE);
  }

  virtual list<SuccessorInfo<JackState,	JackAction> *> *
  successors(JackState s)
  {
    return &si[stateIndex(s)];
  };

  virtual list<PredecessorInfo<JackState, JackAction> *> *
  predecessors(JackState s)
  {
    return &pi[stateIndex(s)];
  };

  virtual unsigned int stateIndex(JackState s) {
    return s.n1	* (MAXCARS + 1)	+ s.n2;
  };

  virtual unsigned int actionIndex(JackAction a) {
    return a + MAXMOVE;
  };

  virtual void printState(ostream & str, JackState & s)	{
    str	<< s;
  };

  virtual void printAction(ostream & str, JackAction & a) {
    str	<< a;
  };

  virtual void init(JackState &	s) {
    //	  s.n1 = rngenerator.between(0,	MAXCARS);
    //	  s.n2 = rngenerator.between(0,	MAXCARS);
    s.n1 = 5;
    s.n2 = 5;
  };

  virtual int applicable(JackAction & a, JackState & s)	{
    // a is amount to move from	n1 to n2
    return ((a >= 0 && a <= s.n1)  ||
	    (a < 0) && -a <= s.n2);
  };

  virtual int terminated(JackState & s){
    // this is a continuing task.  There are no	terminal states.
    return 0;
  };

  virtual float	execute(JackAction & a,	JackState & s);

  virtual clrandom & rng() { return rngenerator; };

  // construct the model, fill in the following	two vectors.
  void buildModel();
  void UpdateInverseModel(JackState &, JackAction &, JackState &, float	p);
  vector<list<SuccessorInfo<JackState, JackAction> *> >	 si;
  vector<list<PredecessorInfo<JackState, JackAction> *>	> pi;

};

#endif
