//
//
#ifndef	WINDY_H
#define	WINDY_H

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

typedef	int WindyAction;
const int West = 0;
const int East = 1;
const int North	= 2;
const int South	= 3;
#define	NROWS 7
#define	NCOLUMNS 10

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

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

  // data
  int n1, n2;
};

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


class WindyStateIterator: public iterator<WindyState>
{
public:
  WindyStateIterator():	current(0,0) {init();};

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


class WindyProblem: public Problem<WindyState, WindyAction>
{
public:
  float	gamma;
  clrandom rngenerator;

  WindyProblem(unsigned	int seed1 = 718373,
		 unsigned int seed2 = 373601):
    rngenerator(seed1,seed2),
    gamma(1.0),
    si(NROWS * NCOLUMNS),
    pi(NROWS * NCOLUMNS)
  {
    buildModel();
  };

  virtual float	discountFactor() { return gamma; };

  virtual unsigned int maxState() {
    return NROWS * NCOLUMNS;
  };
  virtual unsigned int maxAction() {
    return 4;
  }

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

  virtual WindyAction nullAction() { return 0; };

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

  virtual WindyAction randomAction() { return rngenerator.between(0, 3); }

  virtual iterator<WindyAction>	* actionIterator() {
    return new rangeIterator(0,	3);
  }

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

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

  virtual unsigned int stateIndex(WindyState s)	{
    return s.n1	* NROWS	+ s.n2;
  };

  virtual unsigned int actionIndex(WindyAction a) {
    return a;
  };

  virtual void printState(ostream & str, WindyState & s) {
    str	<< s;
  };
  virtual void printAction(ostream & str, WindyAction &	a) {
    str	<< a;
  };

  // always start in (0,3)
  virtual void init(WindyState & s) {
    s.n1 = 0;
    s.n2 = 3;
  };

  virtual int applicable(WindyAction & a, WindyState & s) {
    return 1;
  };

  virtual int terminated(WindyState & s) {
    return (s.n1 == 7 && s.n2 == 3);
  }

  virtual float	execute(WindyAction & a, WindyState & s);

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

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

#endif
