#include<iostream>
#include<sstream>

#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>

#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include <stdio.h>

using namespace std;

vector< pair<string,string> > edgeVec;
vector< char > weightVec;
set< string > unsafeSet;
set< string > stateSet;

string pos2state(int xr, int yr, int xk, int yk, int key)
{
  string state;
  char buff[1];
  int temp;

  for(int i=0;i<4;i++)
    {
      switch(i)
	{
	case 0:
	  temp = xr;
	  break;
	case 1:
	  temp = yr;
	  break;
	case 2:
	  temp = xk;
	  break;
	case 3:
	  temp = yk;
	  break;
	default:
	  temp = -1;
	}
      sprintf(buff,"%d",temp);
      state+=buff;
    }
  
  if(key)
    {
      state = 'r' + state;
    }
  else
    {
      state = 'k' + state;
    }
  return state;
}

void state2pos(string state, int& xr, int& yr, int& xk, int& yk, int& key)
{
  char str[5];
  stringstream ss(state);
  ss>>str[0]>>str[1]>>str[2]>>str[3]>>str[4];
  xr = str[1] - '0';
  yr = str[2] - '0';
  xk = str[3] - '0';
  yk = str[4] - '0';
  if(str[0] == 'r')
    key = 1;
  else
    key = 0;
}

int main()
{
  int M, N;
  char ctemp;
  cout<<"Please specify the size of the room (M * N): ";
  cin>>M>>ctemp>>N;

  M = M-1;
  N = N-1;
  string init = pos2state(0,0,M,N,1);

  int xr = 0, yr = 0, xk = M, yk = N;
  int key = 1;
  int tempkey;

  string statecurr;
  string statenext;

  queue<string> statesCurr;
  queue<string> statesNext;

  statesCurr.push(init);
  stateSet.insert(init);

  while(!statesCurr.empty())
    {
      while(!statesCurr.empty())
	{
	  statecurr = statesCurr.front();
	  state2pos(statecurr,xr,yr,xk,yk,tempkey);
	  
	  if(key)
	    {
	      if(xr>0&&xr<=M&&yr>=0&&yr<N&&!(xr==1&&yr==1)&&!(xr==2&&yr==1)&&!(xr==xk&&yr+1==yk))//UL  'a'
		{
		  statenext = pos2state(xr-1,yr+1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('a');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr-1==xk&&yr+1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>0&&xr<=M&&yr>=0&&yr<N&&!(xr==2&&yr==2)&&!(xr==2&&yr==1)&&!(xr==4&&yr==0)&&!(xr-1==xk&&yr==yk))//LU  'b'
		{
		  statenext = pos2state(xr-1,yr+1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('b');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr-1==xk&&yr+1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>=0&&xr<M&&yr>=0&&yr<N&&!(xr==1&&yr==1)&&!(xr==0&&yr==1)&&!(xr==xk&&yr+1==yk))//UR  'c'
		{
		  statenext = pos2state(xr+1,yr+1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('c');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr+1==xk&&yr+1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>=0&&xr<M&&yr>=0&&yr<N&&!(xr==0&&yr==2)&&!(xr==0&&yr==1)&&!(xr==2&&yr==0)&&!(xr+1==xk&&yr==yk))//RU  'd'
		{
		  statenext = pos2state(xr+1,yr+1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('d');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr+1==xk&&yr+1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>0&&xr<=M&&yr>0&&yr<=N&&!(xr==1&&yr==3)&&!(xr==2&&yr==3)&&!(xr==3&&yr==1)&&!(xr==4&&yr==1)&&!(xr==xk&&yr-1==yk))//DL  'e'
		{
		  statenext = pos2state(xr-1,yr-1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('e');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr-1==xk&&yr-1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>0&&xr<=M&&yr>0&&yr<=N&&!(xr==2&&yr==2)&&!(xr==2&&yr==3)&&!(xr==4&&yr==1)&&!(xr-1==xk&&yr==yk))//LD  'f'
		{
		  statenext = pos2state(xr-1,yr-1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('f');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr-1==xk&&yr-1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>=0&&xr<M&&yr>0&&yr<=N&&!(xr==1&&yr==3)&&!(xr==0&&yr==3)&&!(xr==2&&yr==1)&&!(xr==3&&yr==1)&&!(xr==xk&&yr-1==yk))//DR  'g'
		{
		  statenext = pos2state(xr+1,yr-1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('g');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr+1==xk&&yr-1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>=0&&xr<M&&yr>0&&yr<=N&&!(xr==0&&yr==2)&&!(xr==0&&yr==3)&&!(xr==2&&yr==1)&&!(xr+1==xk&&yr==yk))//RD  'h'
		{
		  statenext = pos2state(xr+1,yr-1,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('h');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr+1==xk&&yr-1==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xr>=0&&xr<=M&&yr>=0&&yr<=N)//ST  'i'
		{
		  statenext = pos2state(xr,yr,xk,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('i');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr==xk&&yr==yk)
			unsafeSet.insert(statenext);
		    }
		}	 
	    }
	  else if(!key)
	    {
	      if(xk>0&&xk<=M&&yk>=0&&yk<=N&&!(xk==2&&yk==2)&&!(xk==4&&yk==0))//L  'u'
		{
		  statenext = pos2state(xr,yr,xk-1,yk,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('u');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr==xk-1&&yr==yk)
			unsafeSet.insert(statenext);
		    }
		}
	      if(xk>=0&&xk<=M&&yk>0&&yk<=N&&!(xk==1&&yk==3)&&!(xk==3&&yk==1))//D  'u'
		{
		  statenext = pos2state(xr,yr,xk,yk-1,!tempkey);
		  edgeVec.push_back(make_pair(statecurr,statenext));
		  weightVec.push_back('u');
		  if(stateSet.find(statenext)==stateSet.end())
		    {
		      stateSet.insert(statenext);
		      statesNext.push(statenext);
		      if(xr==xk&&yr==yk-1)
			unsafeSet.insert(statenext);
		    }
		}
	    }   
	  statesCurr.pop();
	}
      statesCurr = statesNext;
      statesNext = queue<string>();
      key = !key;
    }

  int r = -1;
  int k = 0;
  map<string,int> stateMap;  //renumbering the states

  set<string>::iterator it4;
  for(it4=stateSet.begin();it4!=stateSet.end();it4++)
    {
      string tempstr = *it4;
      if(tempstr[0]=='r')
	{
	  r = r+2;
	  stateMap[*it4] = r;
	}
      else
	{
	  k = k+2;
	  stateMap[*it4] = k;
	}
    }

  cout<<"Numbering states:"<<endl;
  map<string,int>::iterator it5;
  for(it5=stateMap.begin();it5!=stateMap.end();it5++)
    cout<<it5->first<<"->"<<it5->second<<", ";
  cout<<endl;

  cout<<"Graph[{";
  vector< pair<string,string> >::iterator it;
  for(it=edgeVec.begin();it!=edgeVec.end();it++)
    cout<<stateMap[it->first]<<" -> "<<stateMap[it->second]<<", ";
  cout<<"}, EdgeWeight -> {";
  vector< char >::iterator it1;
  for(it1=weightVec.begin();it1!=weightVec.end();it1++)
    cout<<*it1<<", ";
  cout<<"}];"<<endl;

  cout<<"Unsafe states: ";
  set< string >::iterator it2;
  for(it2=unsafeSet.begin();it2!=unsafeSet.end();it2++)
    cout<<stateMap[*it2]<<", ";
  cout<<";"<<endl;

  cout<<"State space: ";;
  set< string >::iterator it3;
  for(it3=stateSet.begin();it3!=stateSet.end();it3++)
    cout<<stateMap[*it3]<<", ";
  cout<<";"<<endl;

  cout<<"#states = "<<stateSet.size()<<endl;
  cout<<"#unsafe states = "<<unsafeSet.size()<<endl;
  cout<<"#edges = "<<edgeVec.size()<<endl;
  cout<<"#weights = "<<weightVec.size()<<endl;

  return 0;
}
