C, 824 803 ไบต์
#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);}
หมายเหตุ: รวมการแก้ไขข้อบกพร่อง (รายการก่อนหน้านี้ระบุ tromino และโดมิโนสองอันว่าเป็นคิวบ์)
ในรหัสไดรเวอร์ TIO มีกรณีทดสอบเพิ่มเติมและตอนนี้มีตัวติดตามผ่าน / ไม่ผ่าน กรณีทดสอบ hexomino ได้รับการอัปเดตพร้อมกับค่า pass / fail ในฉลาก
ลองออนไลน์!
... และก่อนที่จะอธิบายในรายละเอียดมันมีค่าภาพรวมระดับสูง
ภาพรวมพื้นฐาน
อัลกอริทึมนี้ใช้ตัวจับคู่รูปแบบเพื่อจัดประเภทแต่ละโพลีโนที่พบด้วยรูปแบบที่กำหนดเป็นชุดย่อย เนื่องจากการจับคู่แบบโพลีโม่พวกเขาจะถูก "ไม่ทำเครื่องหมาย" ยกเว้นพวกเขาจากการจับคู่รูปแบบอีกครั้ง การจำแนกประเภทเริ่มต้นที่กำหนดโดยผู้จับคู่นั้นเป็นเพียงการนับจำนวนไพ่ในโพลีโนมิน
Matcher จะถูกนำไปใช้ก่อนเพื่อกำจัดโพลีโอโมทั้งหมดที่ไม่สามารถพับลงบนคิวบ์ได้ การจำแนกประเภทของโพลีมิโนเหล่านี้จะถูกยกเลิก การแข่งขันประสบความสำเร็จหากโพลีโอโมเหล่านี้ปรากฏภายในกลุ่มที่สูงกว่า ดังนั้นเราสนใจเฉพาะเซตย่อยที่เล็กที่สุดของ "unfoldable" สำหรับแต่ละชั้นเรียน แสดงให้เห็นที่นี่พร้อมกับการเข้ารหัสเบาะเป็น polyominoes ดังกล่าวทั้งหมด (ไม่รวมการสะท้อนแนวตั้ง) การเข้ารหัสใช้บิต 4-0 ของตัวละครแต่ละตัวเพื่อเป็นตัวแทนของช่องสี่เหลี่ยมในแต่ละแถว:
[^C```] [XHX``] [PPPXH] [XHHX`] [PXN``] [|PP``]
####. ##... #.... ##... #.... ###..
...## .#... #.... .#... ##... #....
..... ##... #.... .#... .###. #....
..... ..... ##... ##... ..... .....
..... ..... .#... ..... ..... .....
[|FB``] [XPX``] [PPXL`] [XLDD`] [XPPX`] [|DD``]
###.. ##... #.... ##... ##... ###..
..##. #.... #.... .##.. #.... ..#..
...#. ##... ##... ..#.. #.... ..#..
..... ..... .##.. ..#.. ##... .....
..... ..... ..... ..... ..... .....
[|T```] [^R```] [PXHHH] [XO```] [_````] [PPPPP]
###.. ####. #.... ##... ##### #....
#.#.. #..#. ##... .#### ..... #....
..... ..... .#... ..... ..... #....
..... ..... .#... ..... ..... #....
..... ..... .#... ..... ..... #....
[XX```]
##...
##...
.....
.....
.....
เมื่อโพลีโม่เหล่านี้ถูกคัดออกแล้วเราจะจัดหมวดหมู่โพลีโอโมที่เหลือออกเป็นหมวดหมู่ที่เกี่ยวข้อง เป็นที่น่าสังเกตว่าในเกือบทุกกรณีมีเพียงคนเดียวที่สามารถหาโพลีโอโมที่ยังคงอยู่ มีข้อยกเว้นสองประการ:
- tromino มุมและ line tromino ไม่สามารถสร้างคิวบ์ได้
- บรรทัด tetromino และ domino ไม่สามารถสร้างคิวบ์ได้
เพื่อให้สามารถรองรับข้อ จำกัด นี้เราได้จัดทำ 8 หมวดหมู่จาก AH: A สำหรับ monominoes (lone tile), B สำหรับแต้ม, C สำหรับ trominoes มุม, D สำหรับ trominoes สาย, E สำหรับ tetrominoes อื่น ๆ , G สำหรับ tetrominoes อื่น ๆ , G สำหรับ pentominoes และ H สำหรับ hexominoes สิ่งใดก็ตามที่ไม่ได้อยู่ในหมวดหมู่เหล่านี้จะถูกเพิกเฉย การนับจำนวนโพลีโม่โนมที่พอเพียงในแต่ละหมวดหมู่
ในตอนท้ายเราแค่คืนความจริงหรือความเท็จตามสมการขนาดยักษ์และตารางเหล่านี้
ไม่พอใจกับความคิดเห็น
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
;
}