#include <iostream>

class Piece {
 public:
  int x, y, o;
  bool xff;
  Piece(int xv, int yv, int ov, bool xffv)
    : x(xv), y(yv), o(ov), xff(xffv) {}
  Piece transpose() {
    if (o == 0) return Piece(x,y,0,!xff);
    if (o == 1) return Piece(-y+1,x-1,3,xff);
    if (o == 2) return Piece(-x+2,-y,2,!xff);
    if (o == 3) return Piece(y+1,-x+1,1,xff);
  }
};

class Position {
 public:
  int x, y, o;
  Position(int xv, int yv, int ov)
    : x(xv), y(yv), o(ov) {}
  Position addPiece(Piece p) {
    if (o == 0) return Position(x+p.x,y+p.y,(o+p.o)%4);
    if (o == 1) return Position(x+p.y,y-p.x,(o+p.o)%4);
    if (o == 2) return Position(x-p.x,y-p.y,(o+p.o)%4);
    if (o == 3) return Position(x-p.y,y+p.x,(o+p.o)%4);
  }
};

int placed[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 };
// 1-12, ordinal, 13-24, transpose

  Piece pieces[12] = {
    Piece(2,-2,1,true),
    Piece(3,-3,1,true),
    Piece(4,-1,1,true),
    Piece(5,-1,1,true),
    Piece(2,-4,1,true),
    Piece(2,-1,2,true),
    Piece(3,2,3,false),
    Piece(0,3,1,false),
    Piece(2,2,0,true),
    Piece(4,-2,3,false),
    Piece(6,1,2,true),
    Piece(6,-1,2,true),
  };

int dist[12] = { 4,6,5,6,6,3,5,5,4,6,7,7 };

void longprint() {
    Position pos(0,0,0);
    for (int p=1; p<13; p++) {
      for (int piece=0; piece<12; piece++) {
        if (placed[piece] == p) {
          cout << (char)('A' + piece);
          pos = pos.addPiece(pieces[piece]);
          cout << ":" << pos.x << ":" << pos.y << ":" << pos.o << "\n";
        }
        if (placed[piece] == p+12) {
          cout << (char)('a' + piece);
          pos = pos.addPiece(pieces[piece].transpose());
          cout << ":" << pos.x << ":" << pos.y << ":" << pos.o << "\n";
        }
      }
    }
    cout << "-----\n";
}

void print() {
    for (int p=1; p<13; p++) {
      for (int piece=0; piece<12; piece++) {
        if (placed[piece] == p) cout << (char)('A' + piece);
        if (placed[piece] == p+12) cout << (char)('a' + piece);
      }
    }
    cout << "\n";
}

long solcount = 0;

void recurse(int count, Position pos, int di) {
  if (count <= 3) {
    cout << solcount << " solutions so far; calculating ..";
    print();
  }
// cout << "called: " << count << "\n";
  if (count == 12) {
// cout << "possible sol, checking\n";
    if (pos.x != 0) return;
    if (pos.y != 0) return;
    if (pos.o != 0) return;
    solcount ++;
//    if (solcount % 10000 == 0) {
//       cout << solcount << " solutions so far\n";
//       print();
//    }
  } else if (di < 
       (((pos.x>0)?pos.x:(-pos.x)) + ((pos.y>0)?pos.y:(-pos.y)))) {
// cout << "too far away, returning\n";
    return;
  } else {
    for (int piece=0; piece<12; piece++) {
// cout << "trying piece " << piece << "\n";
      if (placed[piece] != 0) continue;
      placed[piece] = count+1;
      recurse(count+1, pos.addPiece(pieces[piece]), di-dist[piece]);

      Piece tp = pieces[piece].transpose();
      placed[piece] = count+13;
      recurse(count+1, pos.addPiece(tp), di-dist[piece]);
      placed[piece] = 0;
    }
  }
}

int main () {
  placed[0] = 1;
  Position pos = Position(0,0,0);
// print();
  pos = pos.addPiece(pieces[0]);
  recurse(1, pos, 60);
  cout << "total solutions: " << solcount << "\n";
}
