#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <stdlib.h>
using namespace std;

int min(int& a, int& b) {
  return( (a<b) ? a : b );
};

int max(int& a, int& b) {
  return( (a>b) ? a : b );
};

class Direction {
 public:
  int v;
  Direction(int value) {
    v = value;
  };
  static const int West = 1;
  static const int East = 6;
  static const int North = 2;
  static const int South = 5;
  static const int Above = 3;
  static const int Below = 4;
  string LongName() const {
    if (v == West) return "West";
    if (v == East) return "East";
    if (v == North) return "North";
    if (v == South) return "South";
    if (v == Above) return "Above";
    if (v == Below) return "Below";
    return "Unknown";
  };
  char ShortName() const {
    if (v == West) return 'w';
    if (v == East) return 'e';
    if (v == North) return 'n';
    if (v == South) return 's';
    if (v == Above) return 'a';
    if (v == Below) return 'b';
    return 'u';
  };
  Direction Inverse() const {
    return(Direction(7-v));
  };
  bool WestP() const { return( v == West ); }
  bool EastP() const { return( v == East ); }
  bool NorthP() const { return( v == North ); }
  bool SouthP() const { return( v == South ); }
  bool AboveP() const { return( v == Above ); }
  bool BelowP() const { return( v == Below ); }
};

class Cell {
 public:
  int x, y, z;
  Cell(int xa, int ya, int za): x(xa), y(ya), z(za) {}
  bool WestOf(Cell& c) const
    {return((c.x == x+1) && (c.y == y) && (c.z == z));}
  bool EastOf(Cell& c) const
    {return((c.x == x-1) && (c.y == y) && (c.z == z));}
  bool NorthOf(Cell& c) const
    {return((c.x == x) && (c.y == y-1) && (c.z == z));}
  bool SouthOf(Cell& c) const
    {return((c.x == x) && (c.y == y+1) && (c.z == z));}
  bool Above(Cell& c) const
    {return((c.x == x) && (c.y == y) && (c.z == z-1));}
  bool Below(Cell& c) const
    {return((c.x == x) && (c.y == y) && (c.z == z+1));}
  bool Rel(const Direction& r, Cell& c) const {
    if (r.WestP()) return WestOf(c);
    if (r.EastP()) return EastOf(c);
    if (r.NorthP()) return NorthOf(c);
    if (r.SouthP()) return SouthOf(c);
    if (r.AboveP()) return Above(c);
    if (r.BelowP()) return Below(c);
    return false;
  }
  void Move(const Direction& r) {
    if (r.WestP()) x--;
    if (r.EastP()) x++;
    if (r.NorthP()) y++;
    if (r.SouthP()) y--;
    if (r.AboveP()) z++;
    if (r.BelowP()) z--;
  }
  bool Occupies(int xc, int yc, int zc) {
    return (xc == x && yc == y && zc == z);
  }
};

class Piece {
 public:
  char name;
  vector<Cell> cells;
  Piece() { }
  bool Rel(const Direction& r, Cell& c) {
    for (vector<Cell>::iterator i = cells.begin(); i != cells.end(); ++i)
      if (i->Rel(r,c)) return true;
    return false;
  }
  bool Rel(const Direction& r, Piece& c) {
    for (vector<Cell>::iterator i = cells.begin(); i != cells.end(); ++i)
      if (c.Rel(r.Inverse(),*i)) return true;
    return false;
  }
  void Add(Cell c) {
    cells.push_back(c);
  }
  int Extent(const Direction& r) {
    int answer;
    if (r.WestP() || r.SouthP() || r.BelowP()) {
      answer = 50000;
    } else {
      answer = -50000;
    }
    for (vector<Cell>::iterator i = cells.begin(); i != cells.end(); ++i) {
      if (r.WestP()) answer = min(i->x, answer);
      if (r.EastP()) answer = max(i->x, answer);
      if (r.NorthP()) answer = max(i->y, answer);
      if (r.SouthP()) answer = min(i->y, answer);
      if (r.AboveP()) answer = max(i->z, answer);
      if (r.BelowP()) answer = min(i->z, answer);
    }
    return answer;
  }
  bool Occupies(int x, int y, int z) {
    for (vector<Cell>::iterator i = cells.begin(); i != cells.end(); ++i) {
      if (i->Occupies(x,y,z)) return true;
    }
    return false;
  }
};

class Move {
 public:
  vector<Piece*> pieces;
  Direction dir;
}

class Puzzle {
 public:
  vector<Piece> pieces;
  void Read(string filename) {
    ifstream file;
    file.open(filename.c_str(), ios::in);
    char buffer[256];
    int x = 0;
    int y = 0;
    int z = 0;
    while (!file.eof()) {
      file.getline(buffer,250);
      cout << "Read " << buffer << "\n";
      if (buffer[0] == '.') {
        x = 0;
        while (buffer[x] != '\0') {
          char value = buffer[x];
          if (value != '.') {
            bool found = false;
            for (vector<Piece>::iterator i = pieces.begin(); 
                 i != pieces.end(); ++i) if (value == i->name) {
              i->Add(Cell(x,y,z));
//              cout << "Added " << x << y << z << " to " << i->name << "\n";
              found = true;
            }
            if (!found) {
              Piece p;
              p.name = value;
              p.Add(Cell(x,y,z));
//              cout << "Added " << x << y << z << " to " << p.name << "\n";
              pieces.push_back(p);
            }
          }
          x++;
        }
        y++;
      } else {
        z = (int) strtol(buffer, (char**)NULL, 10);      
        x = 0;
        y = 0;
      }
    }
    file.close();
  }
  void Print() {
    int xmin = 50000; int ymin = 50000; int zmin = 50000;
    int xmax = -50000; int ymax = -50000; int zmax = -50000;
    for (vector<Piece>::iterator i = pieces.begin(); i != pieces.end(); ++i) {
      xmin = min(i->Extent(Direction::West),xmin);
      xmax = max(i->Extent(Direction::East),xmax);
      ymin = min(i->Extent(Direction::South),ymin);
      ymax = max(i->Extent(Direction::North),ymax);
      zmin = min(i->Extent(Direction::Below),zmin);
      zmax = max(i->Extent(Direction::Above),zmax);
    }
    for (int y=ymin;y<=ymax;y++) {
      for (int z=zmin;z<=zmax;z++) {
        for (int x=xmin;x<=xmax;x++) {
          bool found = false;
          for (vector<Piece>::iterator i = pieces.begin(); 
               i != pieces.end(); ++i) {
            if (found) break;
            if (i->Occupies(x,y,z)) {
              cout << i->name;
              found = true;
            }
          }
          if (!found) cout << ".";
        }
        cout << " ";
      }
      cout << "\n";
    }
    cout << "\n";
  }
  
};

int main() {
  Puzzle p;
  p.Read("extremetorture.puz");
  cout << "hello world\n";
  p.Print();
}
