#include <vector.h>
#include <algo.h>
#include <iostream.h>
// A piece has several "orientations".
// Each orientation is composed by a vector,
// corresponding to the piece... first element should
// always be zero.

// Orientation: vector<int>
// Piece: vector<vector<int>>

void normalize (vector<int> orient) {
  sort(orient.begin(), orient.end());
  int small = orient[0];
  for (vector<int>::iterator i=orient.begin(); i!=orient.end(); i++) {
    *i -= small;
  }
}

vector<int> makeOrientation (
   int units,
   vector<int> xvec,
   vector<int> yvec,
   vector<int> zvec,
   int xcf,
   int ycf,
   int zcf) {
 vector<int> temp;
 for (int i=0;i<units;i++) 
   temp.push_back(zcf*zvec[i]+ycf*yvec[i]+xcf*xvec[i]);
 normalize(temp);
 return(temp);
}

class compOrient {
  public:
   bool operator()(const vector<int> vec1, const vector<int> vec2) {
     for (int i=0; i<vec1.size(); i++) {
       if (vec1[i] < vec2[i]) return(true);
       if (vec1[i] > vec2[i]) return(false);
     }
     return(true);
   }
};

class vecEqual {
  public:
   bool operator()(const vector<int> vec1, const vector<int> vec2) {
     return(equal(vec1.begin(),vec1.end(),vec2.begin()));
   }
};

vector< vector <int> > makePiece (vector<int> *orient, int x, int y, int z) {
 // x, y, and z are the "base" vectors.
 vector<int> xvec;
 vector<int> yvec;
 vector<int> zvec;
 int units = 0;
 for (vector<int>::iterator i=(*orient).begin(); i!=(*orient).end(); i++) {
   zvec.push_back((*i)/z);
   yvec.push_back((*i)%z/y);
   xvec.push_back((*i)%y/x);
   units++;
 }

 vector< vector<int> > piece;

 // there are 24 orientations for the piece.
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,x,y,z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-x,-y,z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-x,y,-z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,x,-y,-z));

 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-x,z,y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,x,-z,y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,x,z,-y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-x,-z,-y));

 piece.push_back(makeOrientation(units,xvec,yvec,zvec,y,z,x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-y,-z,x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-y,z,-x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,y,-z,-x));

 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-y,x,z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,y,-x,z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,y,x,-z));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-y,-x,-z));

 piece.push_back(makeOrientation(units,xvec,yvec,zvec,z,x,y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-z,x,-y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,z,-x,-y));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-z,-x,y));

 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-z,y,x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,z,-y,x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,z,y,-x));
 piece.push_back(makeOrientation(units,xvec,yvec,zvec,-z,-y,-x));

 sort(piece.begin(),piece.end(),compOrient());
 piece.erase(unique(piece.begin(),piece.end(),vecEqual()),piece.end());
 

 return(piece);
}

ostream& operator<<(ostream& os, vector<int> vv) {
 os << "(";
 for (vector<int>::iterator i=vv.begin(); i!=vv.end(); i++) {
   if (i!=vv.begin()) 
     os << ", ";
   os << (*i);
 }
 os << ")";
}

ostream& operator<<(ostream& os, vector< vector<int> > vv) {
 os << " [";
 for (vector<vector<int> >::iterator i=vv.begin(); i!=vv.end(); i++) {
   if (i!=vv.begin()) 
     os << ",\n  ";
   os << (*i);
 }
 os << "\n ]\n";
}

int main() {
  int x=1;
  int y=8;
  int z=64;
  vector<vector<int> > pieces[10];

  const int raw[][5] = {
    { 0, 1, 2, 8, 9 }, //P
    { 0, 1, 2, 3, 8 }, //Q
    { 0, 1, 9, 10, 17 }, //R
    { 0, 1, 9, 17, 18 }, //S
    { 0, 1, 2, 9, 17 }, //T
    { 0, 0, 0, 0, 0 }, //dummy U
    { 0, 1, 2, 8, 16 }, //V
    { 1, 2, 8, 9, 16 }, //W
    { 1, 8, 9, 10, 17 }, //X
    { 0, 1, 2, 3, 9 }, //Y
  };;
  for (int i=0;i<10;i++) {
    vector<int> PPP(&raw[i][0], &raw[i][5]);
    //pieces[i] = makePiece(&PPP,x,y,z);
  }

  const int giant[] = {
    // O piece
    64, 65,
    72, 73, 74,
        81, 82, 83,
            90, 91,
    // N piece
    80, //,
        145, 146, 147,
    // U piece
     0, 
     8,
    128,
    136,
  };
  /*
  vector<int> junk(&(giant[0]),&(giant[17]));
  vector<vector<int> > temp(&junk,&junk);
  pieces[5] = temp;

  for (int i=0;i<10;i++) {
    cout << pieces[i]; 
  }
  */
   
}
