#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char** argv);

#define SIZE 5
#define PIECES 12
#define REPORTPIECE 2

typedef unsigned long long board_t;
#define WIDTH 10
#define HEIGHT 6

static void
copy (const char* source, char* target)
{
  unsigned x, y, minX = 0, minY = 0;
  for (x = 0; x < SIZE; x++)
    for (y = 0; y < SIZE; y++)
      if (source[x + SIZE * y] != '-')
	goto gotX;
 gotX:
  minX = x;
  for (y = 0; y < SIZE; y++)
    for (x = 0; x < SIZE; x++)
      if (source[x + SIZE * y] != '-')
	goto gotY;
 gotY:
  minY = y;

  for (x = 0; x < SIZE - minX; x++) {
    for (y = 0; y < SIZE - minY; y++)
      target[x + SIZE * y] = source[(x + minX) + SIZE * (y + minY)];
    for (; y < SIZE; y++)
      target[x + SIZE * y] = '-';
  }
  for (; x < SIZE; x++) {
    for (y = 0; y < SIZE; y++)
      target[x + SIZE * y] = '-';
  }
}

static void
rotate (char* piece)
{
  static char rotated[SIZE * SIZE];

  unsigned x, y;
  for (x = 0; x < SIZE; x++)
    for (y = 0; y < SIZE; y++)
      rotated[x * SIZE + (SIZE - 1 - y)] = piece[x + SIZE * y];

  copy (rotated, piece);
}

static void
flip (const char* piece, char* flipped)
{
  static char temp[SIZE * SIZE];

  unsigned x;
  for (x = 0; x < SIZE; x++)
    memcpy (&temp[(SIZE - 1 - x) * SIZE], &piece[x * SIZE], SIZE);

  copy (temp, flipped);
}

static void
print (const char* piece)
{
  unsigned x, y;
  for (x = 0; x < SIZE; x++) {
    for (y = 0; y < SIZE; y++)
      putchar (piece[x + SIZE * y]);
    putchar ('\n');
  }
  putchar ('\n');
}

static board_t
piecetobits (const char* piece)
{
  board_t bits = 0;
  unsigned x, y;
  for (x = 0; x < SIZE; x++)
    for (y = 0; y < SIZE; y++)
      if (piece[x + SIZE * y] != '-')
	bits |= (board_t)1 << (x + WIDTH * y);
  return bits;
}

static unsigned numPieces = 0;
static unsigned lastPiece[PIECES] = { 0, };
static unsigned chosen[PIECES] = { 0, };
static board_t *boardPieces = NULL;

static void
printchosen (unsigned num)
{
  unsigned i;
  for (i = 0; i < num; i++)
    printf (" %u", chosen[i]);
  putchar ('\n');
}

static void
printboard (board_t board)
{
  unsigned x, y, piece;
  printchosen (PIECES);

  for (y = 0; y < HEIGHT; y++) {
    for (x = 0; x < WIDTH; x++) {
      board_t bit = (board_t)1 << (x + WIDTH * y);
      if (board & bit) {
	for (piece = 0; piece < PIECES; piece++) { 
	  if (boardPieces[chosen[piece]] & bit) {
	    putchar ('a' + piece);
	    goto next;
	  }
	}
	putchar ('*');
      }
      else
	putchar ('-');
    next:
      continue;
    }
    putchar ('\n');
  }
}

static void
addtoboard (unsigned piece, board_t board)
{
  unsigned x, y, maxX, maxY;
  for (x = WIDTH; x--; )
    for (y = 0; y < HEIGHT; y++)
      if (board & ((board_t)1 << (x + WIDTH * y)))
	goto gotX;
 gotX:
  maxX = x;
  for (y = HEIGHT; y--; )
    for (x = 0; x < WIDTH; x++)
      if (board &((board_t)1 << (x + WIDTH * y)))
	goto gotY;
 gotY:
  maxY = y;

  for (x = 0; x < WIDTH - maxX; x++) {
    for (y = 0; y < HEIGHT - maxY; y++) {
      if (!numPieces)
	boardPieces = malloc (sizeof (board_t));
      else
	boardPieces = realloc (boardPieces,
			       (1 + numPieces) * sizeof (board_t));
      boardPieces[numPieces++] = board << (x + WIDTH * y);
    }
  }

  lastPiece[piece] = numPieces;
}

static void
piecestobits ()
{
  static const char pieces[PIECES][SIZE * SIZE] = {
    "11111"
    "-----"
    "-----"
    "-----"
    "-----",
    "2222-"
    "2----"
    "-----"
    "-----"
    "-----",
    "3333-"
    "-3---"
    "-----"
    "-----"
    "-----",
    "4----"
    "444--"
    "4----"
    "-----"
    "-----",
    "-5---"
    "555--"
    "5----"
    "-----"
    "-----",
    "--6--"
    "666--"
    "6----"
    "-----"
    "-----",
    "-7---"
    "777--"
    "-7---"
    "-----"
    "-----",
    "888--"
    "8-8--"
    "-----"
    "-----"
    "-----",
    "999--"
    "99---"
    "-----"
    "-----"
    "-----",
    "aaa--"
    "a----"
    "a----"
    "-----"
    "-----",
    "bb---"
    "-bb--"
    "--b--"
    "-----"
    "-----",
    "c----"
    "cc---"
    "-c---"
    "-c---"
    "-----"
  };

  char rotated[8][SIZE * SIZE], last[SIZE * SIZE];
  unsigned i;
  for (i = 0; i < PIECES; i++) {
    unsigned j, k = 0;
    memcpy (last, pieces[i], SIZE * SIZE);
    memcpy (rotated[k], pieces[i], SIZE * SIZE);
    for (j = 1; j < 4; j++) {
      unsigned l;
      rotate (last);
      for (l = 0; l <= k && memcmp (rotated[l], last, SIZE * SIZE); l++);
      if (l > k)
	memcpy (rotated[k = l], last, SIZE * SIZE);
    }
    for (j = 0; j <= k; j++) {
      unsigned l;
      flip (rotated[j], last);
      for (l = 0; l <= k && memcmp (rotated[l], last, SIZE * SIZE); l++);
      if (l > k)
	memcpy (rotated[k = l], last, SIZE * SIZE);
    }

    for (j = 0; j <= k; j++)
      addtoboard (i, piecetobits (rotated[j]));
  }
}

static void
search (unsigned piece, board_t board)
{
  if (piece == REPORTPIECE)
    printchosen (piece);

  if (piece < PIECES) {
    unsigned i;
    for (i = lastPiece[piece - 1]; i < lastPiece[piece]; i++)
      if (!(board & boardPieces[i]))
	search (piece + 1, board | (boardPieces[chosen[piece] = i]));
  }
  else
    printboard (board);
}

static void
search1 (unsigned i)
{
  for (chosen[0] = i; chosen[0] < lastPiece[0]; chosen[0]++)
    search (1, boardPieces[chosen[0]]);
}

int main (int argc, char** argv)
{
  piecestobits ();
  setvbuf (stdout, NULL, _IOLBF, 0);
  search1 (argc > 1 ? strtoul (argv[1], NULL, 0) : 0);
  return 0;
}
