#ifndef USTATE_HPP
#define USTATE_HPP

#include <iostream>
#include <vector>

struct ustate
{
  ustate(int n):numat(n),n_(n){}//{std::cerr<<n_<<"\n";}

  static const int maxel=2;

  std::vector<int> numat;

  int n_;

  int hash()const
  {
    int x=0;
    for(int i=0;i<n_;++i)
    {
      x*=(1+maxel);
      x+=numat[i];
    }
    return x;
  }
  
  ustate& from_hash(int h)
  {
//    std::cerr<<h<<"fh\n";
    for(int i=n_;i>0;--i)
    {
      
//      std::cerr<<i-1<<"/"<<numat.size()<<"\n";
      numat[i-1]=h%(1+maxel);
      h/=(1+maxel);
    }
    return *this;
  }

  double prob(const double* ps)const
  {
    double p=1.;
    
    for(int i=0;i<n_;++i)
    {
//      std::cerr<<i<<"\t"<<n_<<"\n";
 //     std::cerr<<numat.size()<<"\n";
  //    std::cerr<<numat[i]<<"\n";
      p*=ps[(1+maxel)*i+numat[i]];
    }
    return p;
  }
  

  bool operator<(const ustate& other)const
  {
    return hash()<other.hash();
  }

};

struct ustate_it
{
  ustate_it(int n,bool b):n_(n),x_(0)
  {
    if(!b)
    {
      x_=(1+ustate::maxel);
      for(int i=1;i<n_;++i)
        x_*=(1+ustate::maxel);
    }
//    std::cerr<<x_<<"/"<<n_<<"\n";
  }

  ustate operator*(){ ustate z=n_;
   z.from_hash(x_);
   return z;}

  ustate_it& operator++(){++x_; return *this;}
  
  ustate_it operator++(int)
  {
ustate_it temp=*this;
    ++x_; 
    return temp;
  }

  bool operator==(const ustate_it&other)const
  {
    return x_==other.x_;
  }

  bool operator!=(const ustate_it&other)const
  {
    return x_!=other.x_;
  }

  bool operator<(const ustate_it&other)const
  {
    return x_<other.x_;
  }

  int x_,n_;
};

#endif
