//-------------------------------------------------------------------------- // Program to figure out all the ways of placing the 12 pentominoes to // tile a 6x12 field, by recursively trying out all possible placements. // // Dec 30 2000 Matthias Wandel //-------------------------------------------------------------------------- #include #include #include #define SUPERFAST // Makes it un in 48 seconds on my Celeron 500 typedef unsigned char BYTE; typedef unsigned long DWORD; typedef unsigned short WORD; #define FALSE 0 #define TRUE 1 //#pragma pack(push,1) typedef struct { BYTE Used[5][8]; }Piece_t; char Desc[] = ".0123456789ABCDEF"; // Definition for the pieces. BYTE Pc00[5][8] = {{3,3,3},{3},{3}}; // L BYTE Pc01[5][8] = {{1,1},{1},{1,1}}; // c BYTE Pc02[5][8] = {{2,2},{2,2},{2}}; // b BYTE Pc03[5][8] = {{4,4},{4},{4},{4}}; // l BYTE Pc04[5][8] = {{5},{5,5},{0,5},{0,5}}; // h BYTE Pc05[5][8] = {{6},{6,6},{6},{6}}; // t BYTE Pc06[5][8] = {{7,7,7},{0,7},{0,7}}; // T BYTE Pc07[5][8] = {{0,8},{8,8,8},{0,8}}; // x BYTE Pc08[5][8] = {{0,9},{9,9},{0,9,9}}; // r BYTE Pc09[5][8] = {{10,10,10,10,10}};// I BYTE Pc10[5][8] = {{0,11,11},{11,11},{11}};// w BYTE Pc11[5][8] = {{12,12},{0,12},{0,12,12}};// z Piece_t * Originals[] = { (Piece_t *) Pc00, (Piece_t *) Pc01, (Piece_t *) Pc02, (Piece_t *) Pc03, (Piece_t *) Pc04, (Piece_t *) Pc05, (Piece_t *) Pc06, (Piece_t *) Pc07, (Piece_t *) Pc08, (Piece_t *) Pc09, (Piece_t *) Pc10, (Piece_t *) Pc11, }; // Each of 12 pieces has up to 8 varians for how it can be placed. Piece_t Variants[12][8]; int NumVariants[12]; // Number of variants. typedef struct { BYTE Pos[12][8]; // Grid for where the pieces go. BYTE Placed[12]; // These pieces are already placed. }Field_t; void TryPieces(Field_t * Field); //-------------------------------------------------------------------------- // Show a piece. //-------------------------------------------------------------------------- void ShowPiece(Piece_t * Piece) { int x,y,a; for (y=5;;){ if (!y--) break; for (x=0;x<5;x++){ a = Piece->Used[y][x]; if (a == 0){ printf("."); }else{ printf("%c",Desc[a & 15]); } } printf("\n"); } printf("\n"); } //-------------------------------------------------------------------------- // Show a piece. //-------------------------------------------------------------------------- void ShowField(Field_t * Field) { int x,y,a; for (y=12;;){ if (!y--) break; for (x=0;x<8;x++){ a = Field->Pos[y][x]; if (a == 0){ printf("."); }else{ if (a == 0xff){ printf("+"); }else{ printf("%c",Desc[a & 15]); } } } printf("\n"); } } //-------------------------------------------------------------------------- // Show the field fancy. //-------------------------------------------------------------------------- void ShowFancy(Field_t * Field) { int row,col; int r; for (row=10;row>0;row--){ for (r=0;r<2;r++){ // Print the same stuff 3 times for clarity... for (col=1;col<=6;col++){ if (Field->Pos[row][col]){ printf("####"); }else{ printf(" "); } if (col < 6){ if (Field->Pos[row][col] == Field->Pos[row][col+1]){ if (Field->Pos[row][col]){ printf("#"); }else{ printf(":"); } }else{ printf(" "); } } } printf ("\n"); } if (row > 1){ for (col=1;col<=6;col++){ if (Field->Pos[row][col] == Field->Pos[row-1][col]){ if (Field->Pos[row][col]){ printf("####"); }else{ printf("----"); } }else{ printf(" "); } printf(" "); } printf("\n"); } } } //-------------------------------------------------------------------------- // Copy and rotate a piece ccw. //-------------------------------------------------------------------------- void RotatePiece(Piece_t * Dest, Piece_t * Src) { int x,xput,y,Flag; memset(Dest, 0, sizeof(Piece_t)); Flag=FALSE; xput = 0; for (x=5;;){ if (!x--) break; for (y=0;y<5;y++){ Dest->Used[xput][y] = Src->Used[y][x]; if (Src->Used[y][x]) Flag=TRUE; } if(Flag) xput++; } } //-------------------------------------------------------------------------- // Copy and mirror image a piece. //-------------------------------------------------------------------------- void FlipPiece(Piece_t * Dest, Piece_t * Src) { int x,xput,y,Flag; memset(Dest, 0, sizeof(Piece_t)); Flag=FALSE; xput = 0; for (x=5;;){ if (!x--) break; for (y=0;y<5;y++){ Dest->Used[y][xput] = Src->Used[y][x]; if (Src->Used[y][x]) Flag=TRUE; } if(Flag) xput++; } } int GlobalPlaces = 0; int GlobalAlmost = 0; int GlobalSolutions = 0; //-------------------------------------------------------------------------- // The recursive searching function... //-------------------------------------------------------------------------- void TryPieces(Field_t * Pre) { int pn; int BottomFreeRow = 0; int BottomFreeCol = 0; int NumPlaced; Field_t Field; // Establish left most position in bottom most free row with a free // square. The next piece MUST occupy this - cuts down on duplications. { int row,col; for (row=1;row<=12;row++){ for (col=1;col<=6;col++){ if (Pre->Pos[row][col] == 0){ BottomFreeRow = row; BottomFreeCol = col; goto done; } } } } done: // Count pieces placed so far (need that later) NumPlaced = 0; for (pn=0;pn<12;pn++){ if (Pre->Placed[pn]) NumPlaced += 1; } // Copy field for messing about with. Field = *Pre; // Now try each piece in each position. // Loop for peice number for (pn=0;pn<12;pn++){ int pv; // Check if this piece is already placed. if (Pre->Placed[pn]) continue; // Loop for piece orientation. for (pv=0;pv BottomFreeCol){ // Too far to the right. Could not possibly occupy the spot. break; } #ifdef SUPERFAST if ( *((DWORD *)&(TryPiece.Used[0][0])) & *((DWORD *)&(Field.Pos[py][px])) ){ goto pos_failed; } if ( *((DWORD *)&(TryPiece.Used[1][0])) & *((DWORD *)&(Field.Pos[py+1][px]))){ goto pos_failed; } if ( *((DWORD *)&(TryPiece.Used[2][0])) & *((DWORD *)&(Field.Pos[py+2][px]))){ goto pos_failed; } if ( *((WORD *)&(TryPiece.Used[3][0])) & *((WORD *)&(Field.Pos[py+3][px]))){ goto pos_failed; } if (TryPiece.Used[0][4] & Field.Pos[py][px+4] ){ goto pos_failed; } if (TryPiece.Used[4][0] & Field.Pos[py+4][px] ){ goto pos_failed; } if (TryPiece.Used[0][BottomFreeCol-px] == 0) continue; // does not hit the desired spot. *((DWORD *)&(Field.Pos[py+0][px])) |= *((DWORD *)&(TryPiece.Used[0][0])); Field.Pos[py+0][px+4] |= TryPiece.Used[0][4]; *((DWORD *)&(Field.Pos[py+1][px])) |= *((DWORD *)&(TryPiece.Used[1][0])); *((DWORD *)&(Field.Pos[py+2][px])) |= *((DWORD *)&(TryPiece.Used[2][0])); *((DWORD *)&(Field.Pos[py+3][px])) |= *((DWORD *)&(TryPiece.Used[3][0])); Field.Pos[py+4][px] |= TryPiece.Used[4][0]; #else // Loop for row and column trying to place it. for (row=0;row<5;row++){ for(col=0;col<5;col++){ if (TryPiece.Used[row][col] & Field.Pos[row+py][col+px]){ // There is a conflict. Position fails. goto pos_failed; } } } // Piece pn variant pv fits at px,py // Place the piece. for (row=0;row<5;row++){ for(col=0;col<5;col++){ Field.Pos[row+py][col+px] |= TryPiece.Used[row][col]; } } #endif Field.Placed[pn] = 1; if (Field.Pos[BottomFreeRow][BottomFreeCol] == 0){ // The bottom left free sqare was NOT occupied by the piece. goto redundant_pos; } GlobalPlaces += 1; if (NumPlaced+1 >= 11){ GlobalAlmost += 1; } if (GlobalSolutions > 5000) return; if (NumPlaced+1 >= 12){ // Do cavity detection... printf("\nSol %4d Almost %8d Placings %8d\n", GlobalSolutions, GlobalAlmost,GlobalPlaces); //ShowField(&Field); ShowFancy(&Field); GlobalSolutions += 1; } TryPieces(&Field); // Un-place the piece for the next try... redundant_pos: Field = *Pre; pos_failed:; } } } } //-------------------------------------------------------------------------- // Main //-------------------------------------------------------------------------- int main(void) { int a,b,c; time_t start,end; Piece_t Temp1, Temp2; time(&start); /* for (a=0;a<12;a++){ printf("Piece %d\n",a); ShowPiece(Originals[a]); } */ //-------------------------------------------------------------- // Algorithm to generate unique piece variants. for (b=0;b<12;b++){ int VariantCount; Temp1 = *Originals[b]; for (a=0;a<5;a++){ for (c=0;c<5;c++){ if (Temp1.Used[a][c]){ Temp1.Used[a][c] |= 0x10; } } } VariantCount = 0; for (a=0;a<8;a++){ for (c=0;c