C, 824803 바이트
#define Z return
#define Y char*b
#define N --n
i,j,n,w,h,A,B,C,D,E,F,G,H;char c[9999],*r,*d;x(b)Y;{if(b<c||*b<35)Z;++n;*b^=1;x(b-1);x(b+1);x(b-w);x(b+w);}m(b,p,y)Y,*p;{d=b;if(!y)for(y=-1,--p;1[++p]&31;)d+=w;for(i=0;*p&31?!(*p&16>>i)||b[i]&1:0;++i>4?p+=y,b+=w,i=0:0);Z!(*p&31)?x(d),n:0;}a(b)Y;{for(j=n=0;j<w*h;++j)if(m(c+j,b,1)||m(c+j,b,0))Z n;Z 0;}f(Y){bzero(c,9999);for(h=0,b=strcpy(c,b);r=b,b=strchr(b+1,10);h++,w=b-r);for(A=2,r=1+"@_`^C@|T@^R@XO@XX`|FB@|PP@|DD@PXN@XHX@XPX`PPXL@XHHX@XLDD@XPPX`PPPXH@PXHHH@PPPPP@";*r;r+=A+=r[-1]/96)while(a(r));A=B=C=D=E=F=G=H=0;while(a("PX")||a("XH")) (n-=3)?N?N?N?0:++H:++G:++F:++C;while(a("^")||a("PPPP"))(n-=4)?N?N?0:++H:++G:++E;while(a("P"))N?N?N?N?N?N?0:++H:++G:++F:++D:++B:++A;Z H||(G&&A)||(F&&B+B+A>1)||(E&&A>1)||D>1||C>1||((D||C)*3+B*2+A>5)*(A>1||B>2||A*B);}
참고 : 버그 수정이 포함되어 있습니다 (이전 항목에서는 큐브를 구성하는 것으로 트로 미노와 두 개의 도미노를 잘못 식별했습니다).
TIO 드라이버 코드에는 더 많은 테스트 사례가 있으며 이제 합격 / 불합격 추적기가 있습니다. 헥소 미노 테스트 사례가 라벨의 예상 합격 / 불합격 값으로 업데이트되었습니다.
온라인으로 사용해보십시오!
... 그리고 이것을 자세히 설명하기 전에 높은 수준의 개요를 볼 가치가 있습니다.
기본 개요
이 알고리즘은 패턴 매처를 적용하여 주어진 패턴을 서브셋으로 사용하여 찾은 각 폴리 노 미노를 분류합니다. 폴리 노 미노가 일치하면 패턴 일치에서 다시 제외하고 "표시되지 않음"입니다. 매 처가 제공 한 초기 분류는 단순히 polyomino의 타일 수입니다.
정합 기는 큐브에 접을 수없는 모든 폴리 아미노를 제거하기 위해 먼저 적용됩니다. 이 polyominos의 분류는 폐기됩니다. 이러한 폴리 노 미노가 더 높은 수준 내에 있으면 일치합니다. 따라서 우리는 각 클래스에 대한 "펼칠 수없는"의 가장 작은 부분 집합에만 관심이 있습니다. 패딩 된 인코딩과 함께 여기에 표시되는 모든 폴리 아미노는 (수직 반사 제외)입니다. 인코딩은 각 문자의 4-0 비트를 사용하여 각 행의 사각형을 나타냅니다.
[^C```] [XHX``] [PPPXH] [XHHX`] [PXN``] [|PP``]
####. ##... #.... ##... #.... ###..
...## .#... #.... .#... ##... #....
..... ##... #.... .#... .###. #....
..... ..... ##... ##... ..... .....
..... ..... .#... ..... ..... .....
[|FB``] [XPX``] [PPXL`] [XLDD`] [XPPX`] [|DD``]
###.. ##... #.... ##... ##... ###..
..##. #.... #.... .##.. #.... ..#..
...#. ##... ##... ..#.. #.... ..#..
..... ..... .##.. ..#.. ##... .....
..... ..... ..... ..... ..... .....
[|T```] [^R```] [PXHHH] [XO```] [_````] [PPPPP]
###.. ####. #.... ##... ##### #....
#.#.. #..#. ##... .#### ..... #....
..... ..... .#... ..... ..... #....
..... ..... .#... ..... ..... #....
..... ..... .#... ..... ..... #....
[XX```]
##...
##...
.....
.....
.....
이러한 폴리 아미노가 제거되면 나머지 폴리 아미노는 관련 범주로 분류됩니다. 에 그 지적이의 가치가 거의 모든 경우에, 하나는 단지 (큐브 위에 그 접이식)을 유지하고 단순히 여섯의 합계를 검색 polyominoes를 찾을 수 있습니다. 두 가지 예외가 있습니다.
- 코너 트로 미노와 라인 트로 미노는 큐브를 만들 수 없습니다
- 라인 테트로 미노와 도미노는 큐브를 만들 수 없습니다
이러한 제한을 수용하기 위해 AH에서 A : 모노 노미 (A) (모노 타일), B (도미노), C (코너 트로 미노), D (라인 트로 미노), E (테로 미노 F), G 펜토미노의 경우 H, 헥소 미노의 경우 H 이러한 범주 중 하나에 속하지 않는 것은 무시됩니다. 각 범주에 해당하는 폴리오 미노를 계산하면 충분합니다.
결국, 우리는 거대한 방정식과 이러한 표를 기반으로 진실성 또는 허위성을 반환합니다.
댓글이없는 언 골프
i,j,n,w,h,A,B,C,D,E,F,G,H;char c[9999],*r,*d;
x(b)char*b;{ // recursively unmarks polyomino pointed to by b.
if(b<c||*b<35)return;
++n; *b^=1; // Tabulates tiles in n as it goes.
x(b-1);x(b+1);x(b-w);x(b+w); // left/up/down/right
}
m(b,p,y)char*b,*p;{ // pattern match area b with pattern p, direction y.
// y=1 scans down; y=0 scans up.
d=b; // d tracks a tile in the currently matched pattern for unmarking.
// Note that all patterns are oriented to where "top-left" is a tile.
if(!y) // ...when scanning up, move p to the end, set y to -1 to count backward,
// and advance d to guarantee it points to a tile (now "bottom-left")
for(y=-1,--p;1[++p]&31;)d+=w;
// Match the pattern
for(i=0;*p&31?!(*p&16>>i)||b[i]&1:0;++i>4?p+=y,b+=w,i=0:0);
return !(*p&31) // If it matches...
? x(d),n // ...unmark/count total polyomino tiles and return the count
: 0;
}
a(b)char*b;{ // Scan for an occurrence of the pattern b.
for(j=n=0;j<w*h;++j)
if(m(c+j,b,1)||m(c+j,b,0)) // (short circuit) try down then up
return n;
return 0;
}
// This is our function. The parameter is a string containing the entire area,
// delimited by new lines. The algorithm assumes that this is a rectangular area.
// '#' is used for tiles; ' ' spaces.
f(char*b) {
bzero(c,9999); // Init categories, c buffer
for(h=0,b=strcpy(c,b);r=b,b=strchr(b+1,10);h++,w=b-r); // Find width/height
// Unmark all polyominoes that contain unfoldable subsets. This was
// compacted since the last version as follows. A tracks
// the current pattern's length; r[-1], usually terminator for the
// previous pattern, encodes whether the length increases; and o/c
// the patterns were sorted by length.
for(A=2,r=1+"@_`^C@|T@^R@XO@XX`|FB@|PP@|DD@PXN@XHX@XPX`PPXL@XHHX@XLDD@XPPX`PPPXH@PXHHH@PPPPP@";*r;r+=A+=r[-1]/96)
while(a(r));
A=B=C=D=E=F=G=H=0;
// Match corner trominoes now to ensure they go into C.
while(a("PX")||a("XH"))
(n-=3)
? --n
? --n
? --n
? 0 // More than 6 tiles? Ignore it.
: ++H // 6 tiles? It's an H.
: ++G // 5 tiles? It's a G.
: ++F // 4 tiles? It's an F.
: ++C; // only 3 tiles? It's a C.
// Now match line tetrominoes to ensure they go into E.
while(a("^")||a("PPPP"))
(n-=4)
? --n
? --n
? 0 // More than 6 tiles? Ignore it.
: ++H // 6 tiles? It's an H.
: ++G // 5 tiles? It's a G.
: ++E; // only 4 tiles? It's an E.
// Find all remaining tetrominoes ("P" is a monomino pattern)
while(a("P"))
--n
? --n
? --n
? --n
? --n
? --n
? 0 // More than 6 tiles? Ignore it.
: ++H // 6 tiles? It's an H.
: ++G // 5 tiles? It's a G.
: ++F // 4 tiles? It's an F.
: ++D // 3 tiles? It's a D.
: ++B // 2 tiles? It's a B.
: ++A; // only 1 tile? It's an A.
// Figure out if we can form a cube:
return H // Yes if we have a foldable hexomino
||(G&&A) // Yes if we have a foldable pentomino
// and a monomino
||(F&&B+B+A>1) // Yes if we have a foldable non-line tetromino
// and 2 other tiles (dominoes count twice).
// Either one domino or two monominoes will do.
||(E&&A>1) // Yes if we have a foldable line tetromino (E)
// and two monominoes (A). Note we can't make a
// cube with a line tetromino and a domino (B).
||D>1 // Yes if we have two line trominoes
||C>1 // Yes if we have two corner trominoes
||((D||C)*3+B*2+A>5)
// Any combination of trominoes, dominoes, monominoes>6,
// where trominoes are used at most once
// (via logical or)...
* (A>1||B>2||A*B)
// ...times this includer/excluder fudge factor
// that culls out the one non-working case;
// see table:
//
// Trominos Dominos Monomos Cube A>1 B>2 A*B
// 1 0 3+ yes Y N 0
// 1 1 1+ yes Y N 1
// 1 2 0 no N N 0
// 0+ 3 0+ yes Y Y 1
;
}