// implementation of the 4x3 MDP

#include "4x3.h"
#include "minmax.h"
#include <fstream.h>

float FourBy3Problem::execute(FourBy3Action & act, FourBy3State	& s)
{
  if (act < 0 || act > 3) {
    cerr << "Illegal action passed to FourBy3State::execute = "	<< act
	 << endl;
    abort();
  }

  FourBy3Action	a = act;
  // implement randomness.
  double r = rngenerator.between(0.0, 1.0);
  if (r	> 0.9) {
    // the last	10% of probability turns us left
    switch (a) {
    case North:	a = West; break;
    case East: a = North; break;
    case South:	a = East; break;
    case West: a = South; break;
    default: {
      cout << "Bad action " << a << " in FourBy3Problem::execute" << endl;
      abort();
    }
    }
  }
  else if (r > 0.8) {
    // the second 10% of probability turns us right
    switch (a) {
    case North:	a = East; break;
    case East: a = South; break;
    case South:	a = West; break;
    case West: a = North; break;
    default: {
      cout << "Bad action " << a << " in FourBy3Problem::execute" << endl;
      abort();
    }
    }
  }
  // 80% goes in the intended direction

  // now implement semantics of	actions	deterministically
  switch (a)
    {
    case West:
      s.n1--;
      if (s.n1 < 0) s.n1 = 0;
      else if (s.n1 == 1 && s.n2 == 1) s.n1 = 2;
      break;
    case East:
      s.n1++;
      if (s.n1 > 3) s.n1 = 3;
      else if (s.n1 == 1 && s.n2 == 1) s.n1 = 0;
      break;
    case North:
      s.n2++;
      if (s.n2 > 2) s.n2 = 2;
      else if (s.n1 == 1 && s.n2 == 1) s.n2 = 0;
      break;
    case South:
      s.n2--;
      if (s.n2 < 0) s.n2 = 0;
      else if (s.n1 == 1 && s.n2 == 1) s.n2 = 2;
      break;
    default: {
	cout <<	"Bad action " << a << "	in FourBy3Problem::execute" << endl;
	abort();
      }
    }
  // now compute rewards
  if (s.n1 == 3	&& s.n2	== 2) return 0.96;
  else if (s.n1	== 3 &&	s.n2 ==	1) return -1.04;
  else return -0.04;
}


void FourBy3Problem::UpdateInverseModel(FourBy3State & startState,
					FourBy3Action &	act,
					FourBy3State & endState,
					float probability)
{
  list<PredecessorInfo<FourBy3State, FourBy3Action> *> & piList	=
    pi[stateIndex(endState)];
  // need to see if state and action all ready exist.  They shouldn't
  // but we will check just in case.
  listIterator<PredecessorInfo<FourBy3State, FourBy3Action> *> itr(piList);
  for (itr.init(); !itr; ++itr)	{
    if (itr()->state ==	startState &&
	itr()->action == act) {
      cerr << "startState and act already exist	in model!";
      cerr << "	startState = " << stateIndex(startState)
	   << "	act = "	<< act << endl;
      break;
    }
  }
  piList.add(new PredecessorInfo<FourBy3State,
	     FourBy3Action>(startState,	act, probability));
}

// the numbers in the input file begin with 1.
istream	& operator >> (istream & str, FourBy3State & s)
{
  char delim;
  str >> delim;
  if (delim != '(') {
    cerr << "Found `" << delim << "' where `(' was expected." << endl;
  }
  str >> s.n1;	s.n1--;
  str >> s.n2;	s.n2--;
  str >> delim;
  if (delim != ')') {
    cerr << "Found `" << delim << "' where `)' was expected." << endl;
  }
  return str;
}

ostream	& operator << (ostream & str, FourBy3State & s)
{
  str << "(" <<	s.n1 + 1 << " "	<< s.n2	+ 1 << ")";
  return str;
}

void FourBy3Problem::buildModel()
{
  // we	read the model in from a file.
  ifstream  str("4x3.txt");
  if (!str) {
    cerr << "Unable to open 4x3.txt" <<	endl;
    abort();
  }
  for (int i = 0; i < 9; i++) {
    char delim;
    str	>> delim;
    if (delim != '(') {
      cerr << "While reading model, saw	`" << delim << "' but expected `('."
	   << endl;
      abort();
    }
    FourBy3State s;
    str	>> s;
    cout << "Reading model for state " << s << endl;
    list<SuccessorInfo<FourBy3State, FourBy3Action> *> & siList	=
      si[stateIndex(s)];
    str	>> siList;

    str	>> delim;
    if (delim != ')') {
      cerr << "While reading model, saw	`" << delim << "' but expected `)'."
	   << endl;
      abort();
    }
  }
  cout << "Finished reading model" << endl;

  // now visit every state and update the inverse model
  FourBy3StateIterator itr;
  for (itr.init(); !itr; ++itr)	{
    list<SuccessorInfo<FourBy3State, FourBy3Action> *> *
      si = successors(itr());
    listIterator<SuccessorInfo<FourBy3State, FourBy3Action> *>
      sitr(*si);
    for	(sitr.init(); !sitr; ++sitr) {
      listIterator<ResultInfo<FourBy3State> *> ritr(sitr()->resultStates);
      for (ritr.init();	!ritr; ++ritr) {
	UpdateInverseModel(itr(),
			   sitr()->action,
			   ritr()->state,
			   ritr()->probability);
      }
    }
  }
}
