Pescando per le reti del cubo


30

I cubi possono essere costituiti da sei quadrati come lati. Ma potresti anche piegare tre rettangoli 2x1 a metà e incollarli insieme per formare un cubo. Ora, in questa sfida, ottieni una serie di pezzi composti ciascuno da quadrati e devi determinare se puoi scegliere pezzi per formare un cubo unità. Non tutti i pezzi devono essere usati, alcuni potrebbero essere rimasti.

Dettagli

I pezzi sono dati come una stringa di due diversi personaggi o un'immagine in bianco e nero o qualsiasi comodo formato raster 2D. Nel seguito presumo che i pixel che formano i pezzi siano neri e lo sfondo sia bianco.

Due pixel che condividono un lato sono considerati appartenenti allo stesso pezzo. I pezzi possono essere piegati solo lungo le linee della griglia che separano i pixel e non possono essere tagliati. Ogni lato del cubo ha le dimensioni di un pixel e ogni lato del cubo può essere costituito solo da un singolo strato.

L'output deve essere un valore di verità o falsità .

Casi test

Di seguito, gli spazi sono di sfondo e i simboli di hash #rappresentano i pezzi.

(altro da aggiungere)

Valido

##  
 ## 
  ##

 #  
####
 #  

# # # # # # #

# ##
## #

Non valido

###
###

#  #
####

### ## ####

Esegui il frammento seguente per ulteriori test.

PS: questa è una generalizzazione di questa sfida


Perché lo snippet di codice JS sta solo stampando ulteriori testcoded? Perché non metterli semplicemente nel post haha?
Magic Octopus Urn

1
@carusocomputing Questa era solo una misura per evitare che il post fosse ingombra.
Flawr

Ci saranno sempre sei pixel attivi?
Wheat Wizard il

No, potrebbe esserci di più o di meno su.
flawr

1
@Blue Ah no, l'analisi dell'input per i pezzi fa parte della sfida. Questo input lo semplificherebbe un po ', quindi non lo permetterei. Grazie per avermelo chiesto!
Flawr

Risposte:


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

Nota: include una correzione di bug (la voce precedente identificava erroneamente un tromino e due domino come formare un cubo). Nel codice del driver TIO, ci sono più casi di test e ora c'è un tracker pass / fail; i casi di test hexomino sono stati aggiornati con il valore di superamento / fallimento previsto nell'etichetta.

Provalo online!

... e prima di spiegarlo in dettaglio, vale una panoramica di alto livello.

Panoramica di base

Questo algoritmo applica un pattern matcher per classificare ogni poliomino che trova con un determinato pattern come suo sottoinsieme. Man mano che i poliomino vengono accoppiati, vengono "non contrassegnati", escludendoli nuovamente dalla corrispondenza dei motivi. La classificazione iniziale fornita dal matcher è semplicemente un conteggio del numero di tessere nel poliomino.

Il matcher viene applicato per primo per eliminare tutti i poliomino che non possono essere ripiegati su un cubo; la classificazione di questi polominomi viene scartata. La partita ha successo se questi poliomino compaiono all'interno di quelli di livello superiore; pertanto, ci preoccupiamo solo del sottoinsieme più piccolo di "spiegabile" per ogni classe. Qui vengono mostrati insieme a codifiche imbottite tutti questi poliomino (esclusi i loro riflessi verticali). La codifica utilizza i bit 4-0 di ciascun carattere per rappresentare i quadrati su ogni riga:

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

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

Una volta che questi poliomino vengono abbattuti, classifichiamo i rimanenti poliomino in categorie pertinenti. Vale la pena notare che in quasi tutti i casi, si possono semplicemente trovare i poliomino che rimangono (quelli pieghevoli su cubi) e cercare semplicemente somme di sei. Esistono due eccezioni:

  • Un tromino d'angolo e un tromino di linea non possono formare un cubo
  • Un tetromino di linea e un domino non possono formare un cubo

Per poter soddisfare questa restrizione formiamo 8 categorie, da AH: A per monomino (tessere solitarie), B per domino, C per tromino d'angolo, D per tromino di linea, E per tetromino di linea, F per altri tetromini, G per pentomino e H per esomino. Tutto ciò che non rientra in una di queste categorie viene semplicemente ignorato. È sufficiente il conteggio dei poliomino che rientrano in ciascuna categoria.

Alla fine, restituiamo semplicemente la verità o la falsità basate su un'equazione gigante e queste tabulazioni.

Non rigato di commenti

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

Questo non funzionerà. La domanda dice che alcuni pezzi potrebbero essere inutilizzati
John Dvorak,

@JanDvorak Grazie per averlo sottolineato!
H Walters,

A me sembra strano che tu lo scriva tromino anziché triomino , ma sono entrambi ortografia validi, a quanto pare.
mbomb007,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.