Küp Ağlar İçin Balık Tutma


30

Küpler kenar olarak altı kareden yapılabilir. Ancak ayrıca 2 adet 2x1 dikdörtgeni ikiye katlayabilir ve bir küp oluşturmak için bunları birbirine yapıştırabilirsiniz. Şimdi bu zorlu görevde, her biri karelerden yapılmış bir dizi parça alıyorsunuz ve bir birim küp oluşturmak için parçaları seçip seçemeyeceğinizi belirlemelisiniz. Tüm parçaların kullanılması gerekmiyor, bir kısmı kalmış olabilir.

ayrıntılar

Parçalar iki farklı karakter dizisi veya siyah beyaz görüntü veya uygun herhangi bir 2D raster formatı olarak verilir. Aşağıda, parçaları oluşturan piksellerin siyah ve arka planın beyaz olduğunu varsayıyorum.

Bir tarafı paylaşan iki piksel aynı parçaya ait olarak kabul edilir. Parçalar yalnızca pikselleri ayıran ızgara çizgileri boyunca katlanabilir ve kesilemezler. Küpün her bir tarafı bir piksel büyüklüğüne sahiptir ve küpün her bir tarafı yalnızca tek bir katmandan yapılabilir.

Çıkış olmalıdır truthy veya Falsey değer.

testcases

Aşağıda, boşluklar arka plandır ve karma sembolleri #parçaları temsil eder.

(eklenecek daha fazlası)

Geçerli

##  
 ## 
  ##

 #  
####
 #  

# # # # # # #

# ##
## #

Geçersiz

###
###

#  #
####

### ## ####

Daha fazla test çantası için aşağıdaki pasajı çalıştırın.

Not: Bu, bu zorluğun bir genellemesi


JS kod pasajı neden yalnızca ek kodlanmış test kodları yazdırıyor? Neden onları sadece haha ​​postuna koymuyorsun?
Magic Octopus Urn,

1
@carusocomputing Bu, direklerin dağılmasını önlemek için sadece bir önlemdi.
kusur

Her zaman altı piksel olacak mı?
Buğday Sihirbazı,

Hayır, az ya da çok olabilir.
kusur

1
@Mavi Ah hayır, parçalar için girdiyi analiz etmek zorluğun bir parçası. Bu girdi bunu biraz basitleştirir, bu yüzden buna izin vermem. Sorduğun için teşekkürler!
kusur,

Yanıtlar:


7

C, 824 803 bayt

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

Not: Bir hata düzeltmesi içerir (önceki giriş yanlışlıkla bir tromino ve bir küp oluşturmak için iki domino tanımladı). TIO sürücü kodunda daha fazla test durumu var ve artık bir başarılı / başarısız izleyicisi var; hexomino test durumları, etiketinde beklenen başarılı / başarısız değeriyle güncellendi.

Çevrimiçi deneyin!

... ve bunu detaylı olarak açıklamadan önce, yüksek düzeyde bir genel bakış değerinde.

Temel Genel Bakış

Bu algoritma, bulduğu her bir polominoyu, belirli bir desenle alt küme olarak sınıflandırmak için bir desen eşleştirici uygular. Polyominolar eşleştikçe, tekrar desen eşleşmeleri dışında, "işaretsiz" dir. Eşleştirici tarafından verilen ilk sınıflandırma sadece polyominodaki kiremit sayısının bir sayısıdır.

Eşleştirici ilk önce bir küp üzerine katlanamayan tüm poliominoları çıkarmak için uygulanır; Bu poliominoların sınıflandırılması atılır. Maç, eğer bu polyominolar daha yüksek seviyelerde görünürse başarılı olur; bu nedenle, her sınıf için sadece "katlanamaz" en küçük alt kümesini önemsiyoruz. Burada yastıklı kodlamalar ile birlikte gösterilenler tüm polominolardır (dikey yansımaları hariç). Kodlama, her satırdaki kareleri temsil etmek için her karakterin 4-0 bitini kullanır:

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

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

Bu polyominolar temizlendikten sonra, kalan polyominoları ilgili kategorilere ayırırız. İçinde belirterek It yetmeyecek neredeyse tüm durumlarda, tek sadece (küp üzerine bu katlanabilir) kalır ve sadece altı toplamları aramak Polyominoes bulabilirsiniz. İki istisna vardır:

  • Köşe tromino ve çizgi tromino küp oluşturamaz
  • Bir çizgi tetromino ve bir domino küp oluşturamaz

Bu kısıtlamayı yerine getirebilmek için AH, monominolar (yalnız fayanslar) için A, dominolar için B, köşe trominolar için C, çizgi trominolar için D, diğer tetrominolar için F, 8 kategoriden oluşur. pentominolar için ve heksominolar için H'dir. Bu kategorilerden birine girmeyen her şey sadece göz ardı edilir. Her kategoriye giren polomino sayımı yeterlidir.

Sonunda dev bir denkleme ve bu tablolara dayanarak doğruluk ya da yanlışlık veririz.

Yorumlarla Ungolfed

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

Bu işe yaramaz. Soru, bazı parçaların kullanılmayabileceğini söylüyor
John Dvorak

@JanDvorak Buna işaret ettiğiniz için teşekkür ederiz!
H Walters,

Bana göre, triomino yerine tromino yazdığınız için garip görünüyor , ama ikisi de geçerli yazımlar gibi görünüyor.
mbomb007
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.