Câu cá cho Cube Nets


30

Hình khối có thể được làm bằng sáu hình vuông như các mặt. Nhưng bạn cũng có thể gấp ba hình chữ nhật 2x1 làm đôi và dán chúng lại với nhau để tạo thành một khối lập phương. Bây giờ trong thử thách này, bạn nhận được một tập hợp các mảnh được tạo từ các hình vuông, và bạn phải xác định xem bạn có thể chọn các mảnh để tạo thành một khối đơn vị hay không. Không phải tất cả các mảnh phải được sử dụng, có thể có một số còn lại.

Chi tiết

Các mảnh được đưa ra dưới dạng một chuỗi gồm hai ký tự khác nhau hoặc hình ảnh đen trắng hoặc bất kỳ định dạng raster 2D thuận tiện nào. Trong phần sau tôi giả sử các pixel tạo thành các mảnh có màu đen và nền màu trắng.

Hai pixel chia sẻ một bên được coi là thuộc cùng một mảnh. Các mảnh chỉ có thể được gấp dọc theo các đường lưới phân tách các pixel và chúng không thể bị cắt. Mỗi bên của khối lập phương có kích thước một pixel và mỗi bên của khối chỉ có thể được tạo thành một lớp duy nhất.

Kết quả phải là một truthy hoặc falsey giá trị.

Tủ thử

Sau đây, các khoảng trắng là biểu tượng nền và biểu tượng băm #đại diện cho các mảnh.

(thêm vào)

Có hiệu lực

##  
 ## 
  ##

 #  
####
 #  

# # # # # # #

# ##
## #

không hợp lệ

###
###

#  #
####

### ## ####

Chạy đoạn mã sau để có thêm testcase.

PS: Đây là một khái quát của thách thức này


Tại sao đoạn mã JS chỉ in các testcase được mã hóa bổ sung? Tại sao không đặt chúng trong bài haha?
Bạch tuộc ma thuật Urn

1
@carusocomputing Đó chỉ là một biện pháp để ngăn chặn bài viết bị lộn xộn.
flawr

Sẽ luôn có sáu pixel trên?
Thuật sĩ lúa mì

Không, có thể ít nhiều có thể trên.
flawr

1
@Blue Ah không, phân tích đầu vào cho các mảnh là một phần của thách thức. Đầu vào này sẽ đơn giản hóa điều đó một chút, vì vậy tôi sẽ không cho phép điều đó. Cảm ơn bạn đã hỏi thăm!
flawr

Câu trả lời:


7

C, 824 803 byte

#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);}

Lưu ý: Bao gồm sửa lỗi (mục trước đó đã xác định sai một tromino và hai domino là tạo thành một khối). Trong mã trình điều khiển TIO, có nhiều trường hợp kiểm tra hơn và giờ đây có trình theo dõi pass / fail; trường hợp kiểm tra hexomino đã được cập nhật với giá trị vượt qua / thất bại dự kiến ​​trong nhãn.

Hãy thử trực tuyến!

... Và trước khi giải thích điều này một cách chi tiết, nó đáng để xem xét tổng quan ở cấp độ cao.

Tổng quan cơ bản

Thuật toán này áp dụng một công cụ đối sánh mẫu để phân loại từng polyomino mà nó tìm thấy với một mẫu nhất định là tập hợp con của nó. Vì đa giác được khớp, chúng "không được đánh dấu", loại trừ chúng khỏi khớp mẫu một lần nữa. Việc phân loại ban đầu được đưa ra bởi công cụ đối sánh chỉ đơn giản là đếm số lượng gạch trong polyomino.

Bộ so khớp được áp dụng trước tiên để loại bỏ tất cả các đa giác không thể gấp lại thành một khối; việc phân loại các polyominos bị loại bỏ. Trận đấu thành công nếu những đa giác này xuất hiện trong những cấp độ cao hơn; do đó, chúng tôi chỉ quan tâm đến tập hợp con nhỏ nhất "không thể bán được" cho mỗi lớp. Thể hiện ở đây cùng với các bảng mã được đệm là tất cả các đa giác như vậy (không bao gồm các phản xạ dọc của chúng). Mã hóa sử dụng các bit 4-0 của mỗi ký tự để biểu thị các ô vuông trên mỗi hàng:

[^C```] [XHX``] [PPPXH] [XHHX`] [PXN``] [|PP``]
 ####.   ##...   #....   ##...   #....   ###..
 ...##   .#...   #....   .#...   ##...   #....
 .....   ##...   #....   .#...   .###.   #....
 .....   .....   ##...   ##...   .....   .....
 .....   .....   .#...   .....   .....   .....
[|FB``] [XPX``] [PPXL`] [XLDD`] [XPPX`] [|DD``]
 ###..   ##...   #....   ##...   ##...   ###..
 ..##.   #....   #....   .##..   #....   ..#..
 ...#.   ##...   ##...   ..#..   #....   ..#..
 .....   .....   .##..   ..#..   ##...   .....
 .....   .....   .....   .....   .....   .....
[|T```] [^R```] [PXHHH] [XO```] [_````] [PPPPP]
 ###..   ####.   #....   ##...   #####   #....
 #.#..   #..#.   ##...   .####   .....   #....
 .....   .....   .#...   .....   .....   #....
 .....   .....   .#...   .....   .....   #....
 .....   .....   .#...   .....   .....   #....

[XX```]
 ##...
 ##...
 .....
 .....
 .....

Sau khi các đa giác này được loại bỏ, chúng tôi phân loại các đa giác còn lại thành các loại có liên quan. Điều đáng chú ý là trong hầu hết các trường hợp, người ta chỉ có thể tìm thấy các đa giác còn lại (chúng có thể gập lại trên các hình khối) và chỉ cần tìm kiếm tổng số sáu. Có hai trường hợp ngoại lệ:

  • Một tromino góc và một tromino đường thẳng không thể tạo thành một khối
  • Một tetromino dòng và domino không thể tạo thành một khối

Để có thể đáp ứng hạn chế này, chúng tôi tạo thành 8 loại, từ AH: A cho monominoes (gạch đơn), B cho domino, C cho trominoes góc, D cho trominoes dòng, E cho tetrominoes dòng, F cho tetrominoes khác, G cho pentominoes, và H cho hexominoes. Bất cứ điều gì không thuộc một trong những loại này chỉ là bỏ qua. Đếm các đa giác rơi vào mỗi loại đủ.

Cuối cùng, chúng tôi chỉ trả lại sự trung thực hoặc giả dối dựa trên một phương trình khổng lồ và các bảng này.

Phản đối với ý kiến

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
      ;
}

Điều này sẽ không làm việc. Câu hỏi cho biết một số phần có thể không được sử dụng
John Dvorak

@JanDvorak Cảm ơn bạn đã chỉ ra điều đó!
H Walters

Đối với tôi có vẻ kỳ lạ khi bạn đánh vần là tromino thay vì triomino , nhưng cả hai đều là cách viết hợp lệ, có vẻ như vậy.
mbomb007
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.