Риболовля на кубикові сітки


30

Кубики можуть бути виготовлені з шести квадратів як сторони. Але ви також можете скласти три прямокутники 2х1 навпіл і склеїти їх між собою, щоб утворити кубик. Тепер у цьому виклику ви отримуєте набір шматочків, кожен з яких зроблений з квадратів, і ви повинні визначити, чи можете ви вибирати шматочки для формування одиничного куба. Не всі шматки повинні бути використані, їх може залишитися.

Деталі

Елементи подаються у вигляді рядка з двох різних символів або чорно-білого зображення або будь-якого зручного 2D растрового формату. Далі я припускаю, що пікселі, які утворюють фрагменти, чорні, а фон - білий.

Два пікселі, які мають спільну сторону, вважаються належними до одного фрагмента. Шматки можна скласти лише уздовж сітки, що розділяють пікселі, і їх не можна розрізати. Кожна сторона куба має розмір одного пікселя, і кожна сторона куба може бути виконана лише з одного шару.

Вихід повинен мати значення " truthy" або " falsey" .

Тестові шафи

Далі пробіли є фоном, а хеш-символи #представляють шматки.

(ще потрібно додати)

Дійсний

##  
 ## 
  ##

 #  
####
 #  

# # # # # # #

# ##
## #

Недійсний

###
###

#  #
####

### ## ####

Виконайте наступний фрагмент для отримання більше тестів.

PS: Це узагальнення цього виклику


Чому фрагмент коду JS просто друкує додаткові тверді коди? Чому б просто не поставити їх на посаду ха-ха?
Чарівний восьминога Урна

1
@carusocomputing Це був лише захід, щоб запобігти забиттю посади.
flawr

Чи завжди буде шість пікселів?
Пшеничний майстер

Ні, там може бути більше чи менше.
недолік

1
@ Blue Ах ні, аналіз вхідних даних є частиною завдання. Цей вклад спростить це зовсім небагато, тому я не допустив би цього. Дякую за питання!
недолік

Відповіді:


7

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

Примітка. Включає виправлення помилок (попередній запис помилково визначав тромiно та два доміно як куб). У коді драйвера TIO є більше тестових випадків, і тепер існує трекер пропуску / відмови; Тести на тести гексоміно були оновлені з очікуваним значенням пропуску / відмови в етикетці.

Спробуйте в Інтернеті!

... і перш ніж це детально пояснити, варто переглянути високий рівень.

Основний огляд

Цей алгоритм застосовує відповідний шаблон для класифікації кожного поліоміно, який він знайде, із заданим шаблоном як його підмножина. Коли поліоміно підбираються, вони є "немаркованими", виключаючи їх з повторного узгодження шаблону. Початкова класифікація, дана матчером, - це просто підрахунок кількості плиток у поліоміно.

Матчер застосовують спочатку, щоб викреслити всі поліоміно, які неможливо скласти на кубик; класифікацію цих поліоміно відкидають. Матч проходить успішно, якщо ці поліоміни з'являються в межах вищого рівня; отже, ми дбаємо лише про найменший підмножина «нерозбірних» для кожного класу. Тут показано разом із набивними кодуваннями всі такі поліоміно (за винятком їх вертикальних відбитків). Кодування використовує біти 4-0 кожного символу для представлення квадратів у кожному рядку:

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

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

Після того, як ці поліомініоми будуть викреслені, ми класифікуємо решта полиоминосов у відповідні категорії. Варто зазначити, що майже у всіх випадках можна просто знайти поліоміно, які залишилися (ті, що складаються на кубики), і просто шукати суми з шести. Є два винятки:

  • Кутове тромiно та лiнiя тромiно не можуть утворювати куб
  • Рядок тетроміно і доміно не може утворювати кубик

Для того, щоб мати змогу прийняти це обмеження, ми формуємо 8 категорій: з AH: A для мономінів (одинокі плитки), B для доміно, C для кутових тромінів, D для лінійних троміно, E для лінійних тетроміно, F для інших тетроміно, G для пентоміно, а 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
      ;
}

Це не спрацює. Питання каже, що деякі фрагменти можуть бути невикористані
Джон Дворак

@JanDvorak Дякую за вказівку на це!
H Walters

Мені здається дивним, що ви пишете це tromino замість triomino , але вони обидва дійсні написання, здається.
mbomb007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.