¿Es estable la estructura de ladrillo?

24

Representemos un ladrillo de mampostería estándar como [__](e ignoremos el hecho de que la parte superior está abierta). Cuando se apilan estos ladrillos, cada otra capa se compensa con medio ladrillo, como es habitual en la construcción de ladrillos:

  [__][__][__][__]
[__][__][__][__]  
  [__][__][__][__]
[__][__][__][__]  

Por lo tanto, cada ladrillo tiene como máximo seis vecinos y es imposible que dos ladrillos se alineen directamente verticalmente.

El punto clave es que los arreglos de estos ladrillos no se mueven , sino que simplemente se mantienen unidos por gravedad. Por lo tanto, es importante que cada ladrillo en la estructura sea estable, de lo contrario, toda la estructura es inestable.

Hay tres formas en que un ladrillo individual puede ser estable:

  1. Cualquier ladrillo en el suelo (la línea más baja de ladrillos) es estable.
  2. Cualquier ladrillo que tenga dos ladrillos directamente debajo es estable:

      [__]   <- this brick is stable
    [__][__] <- because these bricks hold it up
    
  3. Cualquier ladrillo que tenga un ladrillo encima y debajo del mismo lado es estable:

      [__]  [__]
    [__]      [__] <- these middle bricks are stable
      [__]  [__]      because the upper and lower bricks clamp them in
    
    [__]          [__]
      [__]      [__]   <- these middle bricks are NOT stable
        [__]  [__]
    

De estas reglas podemos ver, por ejemplo, la disposición

  [__][__][__][__]
[__][__][__][__]  
  [__][__][__][__]
[__][__][__][__]  

es inestable porque el ladrillo superior derecho es inestable, que es todo lo que se necesita.

Una estructura de ladrillos solo es estable si todos sus ladrillos son estables.

Reto

Su tarea es escribir una función que tome una cadena de estructura de ladrillo y devuelva un valor verdadero si la estructura es estable, y un valor falso si es inestable. ( verdad / falsa definición )

La cadena de entrada puede ser arbitrariamente grande, pero siempre será una cuadrícula rectangular de caracteres, con espacios que llenan áreas sin ladrillos. El ancho de la cuadrícula de caracteres será divisible por 4, pero la altura puede ser impar o par.

La cuadrícula de ladrillo siempre se extiende por encima y a la derecha de la posición inferior izquierda del ladrillo:

         .
         .
         .
  BRK?BRK?BRK?BRK?  
BRK?BRK?BRK?BRK?BRK?
  BRK?BRK?BRK?BRK?  
BRK?BRK?BRK?BRK?BRK? . . .
  BRK?BRK?BRK?BRK?  
BRK?BRK?BRK?BRK?BRK?

Dependiendo de la estructura, cada BRK?uno representa un ladrillo ( [__]) o un espacio vacío (4 espacios).

Observe que las cavidades de medio ladrillo se rellenan con espacios para garantizar que la cuadrícula de caracteres sea rectangular.

Tanteo

El código más corto en bytes gana.

Notas

  • Si lo desea, puede usar . lugar de espacio como el carácter de espacio vacío.
  • La cadena vacía se considera estable.
  • Si su idioma no tiene funciones, puede usar una variable de cadena con nombre como entrada y asignar el resultado a otra variable.
  • Si su idioma no tiene cadenas, puede hacer lo que parezca apropiado para la entrada.

Casos de prueba

Varios casos de prueba, separados por líneas vacías. Para mayor claridad .se utiliza en lugar de espacio para espacios vacíos.

Estable:

[__]

..[__]..
[__][__]

........[__]........
......[__][__]......
........[__]........

..[__][__]..
[__][__][__]
..[__][__]..
[__]....[__]

............[__]..
..[__][__][__][__]
[__][__][__][__]..
..[__][__][__][__]
[__][__][__][__]..

..[__]........[__]..
[__][__][__][__][__]
..[__][__][__][__]..
....[__][__][__]....
......[__][__]......
........[__]........

Inestable:

..[__]..
........

..[__]..
[__]....

..[__]..
....[__]

..[__][__]..
[__]....[__]
..[__][__]..
[__]....[__]

..[__][__][__][__]
[__][__][__][__]..
..[__][__][__][__]
[__][__][__][__]..

[__][__][__][__][__]
..[__][__][__][__]..
....[__][__][__]....
......[__][__]......
........[__]........
Pasatiempos de Calvin
fuente
77
Estoy bastante seguro de que su definición de estabilidad no coincide con la realidad ;-)
John Dvorak
14
@ JanDvorak Lo sé, pero quién querría jugar al golf con un motor de física completo: P
Calvin's Hobbies
........[__].... ......[__][__].. ....[__][__].... ..[__][__]...... [__][__]........ ..[__]..........(tendrá que apilar mentalmente esas líneas una encima de la otra. El punto es que sus reglas permiten estructuras cuyo centro de gravedad está muy alejado de su punto de contacto con el suelo. Debería ser posible apretarlas para evitar esto , sin necesidad de un motor de física, si te apetece.)
Nathaniel
2
Sin embargo, la verosimilitud en la física es una gran lata de gusanos. Se pueden encontrar muchos casos simples en los que la estabilidad depende del coeficiente de fricción y / o del peso de los ladrillos en la parte superior.
COTO
10
"estable" ... je
wchargin

Respuestas:

12

80386 código máquina, 98

El código:

60 8b f1 8b f9 b0 0a f2 ae 8b ef 2b ee b0 00 f2
ae 2b fe 83 ef 02 2b fd 72 41 03 f7 2b f5 33 c9
8a 7c 6e fc 8a 1c 6e b1 02 33 d2 8b c7 f7 f5 83
fa 02 75 03 b7 00 41 8a 66 fc 8a 06 3b fd 7d 02
33 c0 23 c3 0a c4 22 df 0b c3 f6 44 2e fe 01 74
04 d1 e8 73 06 2b f1 2b f9 73 c5 61 d1 d0 83 e0
01 c3

El código escanea el arte ASCII desde el final hasta el principio, saltando 2 caracteres a la vez. Esto hace el doble de las comprobaciones necesarias (sería suficiente para saltar 4 caracteres), pero simplifica la lógica.

La verificación comienza en la penúltima fila de caracteres (no es necesario verificar la última línea). En cada línea, comienza 3 caracteres desde la derecha (no es necesario verificar demasiado a la derecha). Para cada personaje, verifica 4 personajes circundantes:

A...B
..X..
C...D

Hay un montón de condiciones lógicas para verificar:

  • Si A y C son caracteres de ladrillo, X es compatible
  • Si B y D son caracteres de ladrillo, X es compatible
  • Si C y D son caracteres de ladrillo, X es compatible
  • Si X es un personaje de ladrillo, debe ser compatible; de lo contrario la estructura es inestable

Es una coincidencia afortunada que todos los personajes de ladrillo [_]tengan su conjunto LSB; todos los demás personajes lo .\ntienen claro. Además, el conjunto de instrucciones 80386 tiene estos prácticos registros "alto" y "bajo" ( ah,al , etc), lo que ayuda paralelizar los controles un poco. Entonces, todas las cuentas de cheques equivalen a un poco de violín oscuro.

Empecé con el siguiente código C:

int check(const char* ptr)
{
    int width, result = 0, pos;

    width = strchr(ptr, '\n') - ptr + 1;
    pos = strlen(ptr) - 1 - width; // pos points to the B character
    ptr += pos - width;

    while (pos >= 0)
    {
        int a = ptr[-4];
        int c = ptr[-4 + 2 * width];
        int b = ptr[0];
        int d = ptr[0 + 2 * width];
        int ab = a << 8 | b;
        int cd = c << 8 | d;
        if (pos < width)
            ab = 0; // A and B don't exist; set them to 0
        int jump = 2; // distance to next brick
        if (pos % width == 2) // leftmost brick?
        {
            cd &= 0xff; // C doesn't exist; set it to 0
            ++jump;
        }
        int support_v = ab & cd;
        support_v = support_v | support_v >> 8; // data in LSB
        int support_h = cd & cd >> 8; // data in LSB
        int support = (support_v | support_h) & 1;
        if (!support & ptr[-2 + width])
            goto UNSTABLE;
        ptr -= jump;
        pos -= jump;
    }
    return 1;
UNSTABLE:
    return 0;
}

Traduje el código al lenguaje ensamblador (es principalmente uno a uno), incluida una implementación de golf strchry strlen. El siguiente código fuente es traducido por MS Visual Studio al código de máquina en la parte superior de mi publicación.

__declspec(naked) int __fastcall check(const char* ptr) // MS Visual Studio syntax
{
    _asm
    {
        pushad;

        // ecx = ptr
        mov esi, ecx; // esi = ptr
        mov edi, ecx
        mov al, 10;
        repne scasb;
        mov ebp, edi;
        sub ebp, esi; // ebp = width

        mov al, 0;
        repne scasb;
        sub edi, esi;
        sub edi, 2;
        sub edi, ebp; // edi = pos
        jc DONE;

        add esi, edi;
        sub esi, ebp;

        xor ecx, ecx; // ecx = jump

    LOOP1:
        mov bh, [esi - 4 + 2 * ebp]; // bh = C
        mov bl, [esi + 2 * ebp]; // bl = D
        // bx = CD
        mov cl, 2;
        xor edx, edx
        mov eax, edi
        div ebp;
        cmp edx, 2;
        jne LABEL2;
        mov bh, 0
        inc ecx;
    LABEL2:

        mov ah, [esi - 4]; // ah = A
        mov al, [esi]; // al = B
        // ax = AB
        cmp edi, ebp;
        jge LABEL3;
        xor eax, eax;
    LABEL3:

        and eax, ebx; // ax = support_v
        or al, ah; // al = support_v
        and bl, bh; // bl = support_h
        or eax, ebx; // eax = support
        test byte ptr[esi - 2 + ebp], 1;
        jz LABEL4; // not a brick character - nothing to check
        shr eax, 1; // shift the LSB into the carry flag
        jnc DONE;
    LABEL4:
        sub esi, ecx;
        sub edi, ecx;
        jnc LOOP1;

    DONE:
        // here, the result is in the carry flag; copy it to eax
        popad;
        rcl eax, 1;
        and eax, 1;
        ret;
    }
}
anatolyg
fuente
7

MATLAB - 119 bytes

Minified:

function c=S(B),f=@(m)conv2([(0&B(1,:))+46;B]+3,m,'valid');M=[2 0;-1 -1;0 2];c=isempty(B)||all(all(f(M)&f(fliplr(M))));

Expandido:

function c = isstable( B )

f = @(m) conv2( [(0&B(1,:))+46; B] + 3, m, 'valid' );
M = [2 0;-1 -1;0 2];
c = isempty( B ) || all(all( f( M ) & f(fliplr( M )) ));

Uso de muestra:

S4 = [  '..[__][__]..'; ...
        '[__][__][__]'; ...
        '..[__][__]..'; ...
        '[__]....[__]'];

fprintf( 'S4: %d\n', isstable( S4 ) );

S4: 1

U4 = [  '..[__][__]..'; ...
        '[__]....[__]'; ...
        '..[__][__]..'; ...
        '[__]....[__]'];

fprintf( 'U4: %d\n', isstable( U4 ) );

U4: 0

Detalles

La rutina agrega una fila .a la parte superior de la matriz de entrada, luego se convierte en una matriz numérica agregando 3 a los códigos de caracteres ASCII. Dada esta conversión, una convolución 2D con el núcleo

 2  0
-1 -1
 0  2

produce una matriz 0en ubicaciones donde el patrón de caracteres

 . *
 _ _
 * .

está presente, con la *representación de "cualquier personaje". Debido a la construcción del núcleo, este es el único patrón de caracteres válido que producirá a 0.

Se realiza una convolución idéntica con la versión volteada izquierda-derecha del núcleo para detectar

 * .
 _ _
 . *

Una entrada es estable si i ) está vacía o ii ) no aparecen ceros en ninguna de las convoluciones.

Dos frustraciones son

  1. La convolución predeterminada de MATLAB pasa los bordes de la matriz de operandos, produciendo 0s erróneos en las esquinas opuestas para ambas convoluciones, lo que requiere ,'valid'que se agreguen (8 bytes) a la conv2llamada para limitar la salida al área donde la convolución es válida.

  2. El manejo de la caja de cadena vacía agrega 12 bytes.

COTO
fuente
6

JavaScript (E6) 131 261

F=a=>
  [...a].every((e,p)=>
    !(d={']':-3,'[':3}[e])
     |a[p-r]=='_'&(x=a[p+r]!=' ')
     |a[p-r+d]=='_'&(y=a[p+r+d]!=' ')
     |x&y
  ,r=a.search(/\n/)+1)

Prueba en la consola FireFox / FireBug

;['[__]', '  [__]  \n[__][__]', '        [__]        \n      [__][__]      \n        [__]        ',
 '  [__][__]  \n[__][__][__]\n  [__][__]  \n[__]    [__]',
 '            [__]  \n  [__][__][__][__]\n[__][__][__][__]  \n  [__][__][__][__]\n[__][__][__][__]  ',
 '  [__]        [__]  \n[__][__][__][__][__]\n  [__][__][__][__]  \n    [__][__][__]    \n      [__][__]      \n        [__]        ']
.forEach(x => console.log(x+'\n'+F(x)))

;['  [__]  \n        ', '  [__]  \n[__]    ' ,'  [__]  \n    [__]',
 '  [__][__]  \n[__]    [__]\n  [__][__]  \n[__]    [__]',
 '  [__][__][__][__]\n[__][__][__][__]  \n  [__][__][__][__]\n[__][__][__][__]  ',
 '[__][__][__][__][__]\n  [__][__][__][__]  \n    [__][__][__]    \n      [__][__]      \n        [__]        ']
.forEach(x => console.log(x+'\n'+F(x)))

Salida

    [__]
true

  [__]  
[__][__]
true

        [__]        
      [__][__]      
        [__]        
true

  [__][__]  
[__][__][__]
  [__][__]  
[__]    [__]
true

            [__]  
  [__][__][__][__]
[__][__][__][__]  
  [__][__][__][__]
[__][__][__][__]  
true

  [__]        [__]  
[__][__][__][__][__]
  [__][__][__][__]  
    [__][__][__]    
      [__][__]      
        [__]        
true

  [__]  
false

  [__]  
[__]    
false

  [__]  
    [__]
false

  [__][__]  
[__]    [__]
  [__][__]  
[__]    [__]
false

  [__][__][__][__]
[__][__][__][__]  
  [__][__][__][__]
[__][__][__][__]  
false

[__][__][__][__][__]
  [__][__][__][__]  
    [__][__][__]    
      [__][__]      
        [__]        
false

Sin golf

F=a=>(
  a=a.replace(/__/g,'').replace(/  /g,'.'),
  r=a.search(/\n/)+1,
  [...a].every((e,p)=>
    e < '0' ||
    (e ==']'
    ? // stable right side
     a[p-r]=='[' & a[p+r]!='.' 
     |
     a[p-r-1]==']' & a[p+r-1]!='.' 
     |
     a[p+r]!='.' & a[p+r-1] != '.'
    : // stable left side
     a[p-r]==']' & a[p+r]!='.' 
     |
     a[p-r+1]=='[' & a[p+r+1]!='.' 
     |
     a[p+r]!='.' & a[p+r+1] != '.'
    )  
  )
)
edc65
fuente
¿Qué hace [...a], si no te importa que te pregunte? Sé que ES6 permite ...argcomo último argumento de una función capturar variables, pero nunca he visto que se use de esta manera.
COTO
@COTO codegolf.stackexchange.com/a/37723/21348 , use el caso 2 (es muy común, lo uso en quizás el 80% de mis respuestas)
edc65
Sol de un arma. Como {:}en MATLAB. Eso va a ser muy útil. Gracias. :)
COTO
1

Python 279

Creo que soy bastante malo en los desafíos de golf de código y tal vez uso los idiomas incorrectos para eso: D Pero me encanta el código que se puede leer fácilmente :) Por cierto, ¡me gustaría ver un código de Python que use menos bytes!

def t(b):
    r=b.split()
    l=len(r[0])
    r=['.'*l]+r
    for i in range(len(r)-2,0,-1):
        r[i]+='...'
        for j in range(l):
            if(r[i][j]=='['):
                if(r[i+1][j]<>'_'or(r[i+1][j+3]<>'_'and r[i-1][j]<>'_'))and(r[i+1][j+3]<>'_'or r[i-1][j+3]<>'_'):
                    return False
    return True

Posibles ejemplos:

A = "..[__][__][__][__]\n\
[__][__][__][__]..\n\
..[__][__][__][__]\n\
[__][__][__][__].."
print t(A) #False

B = "..[__]........[__]..\n\
[__][__][__][__][__]\n\
..[__][__][__][__]..\n\
....[__][__][__]....\n\
......[__][__]......\n\
........[__]........"
print t(B) #True
Wikunia
fuente
No uso los puntos dentro de mi código, en realidad su entrada puede usar cualquier carácter pero no _y [
Wikunia
1
Generalmente, en lugar de usar <>, usaría !=.
Ethan Bierlein
@EthanBierlein no estaba seguro, pero sí, !=es la forma preferida
Wikunia
1

JavaScript 2 (ES6) - 148151 bytes

F=s=>s.split(/\n/).every((b,i,a)=>(r=1,b.replace(/]/g,(m,o)=>(T=z=>(a[i-1+(z&2)]||[])[o-z%2*3]=='_',r&=i>a.length-2?1:T(2)?T(3)|T(0):T(3)&T(1))),r))

Espera una cadena de filas de ladrillo separadas por una nueva línea (nota: si pudiéramos usar un carácter separador diferente como "|" para separar las filas, esto podría hacerse 1 byte más corto).

Prueba en la consola de Firefox con:

F('..[__]......\n[__][__][__]\n..[__][__]..\n[__]....[__]'); // false
F('..[__][__]..\n[__][__][__]\n..[__][__]..\n[__]....[__]'); // true
mi gato y yo
fuente
0

Pitón, 209

def s(b):
 c=b.split("\n");s="".join(c);l=len(c[0]);t=" "*l+s+"]]"*l;a=lambda x,y,z:t[x+l*y+z]=="]"
 return all([(a(i,1,1)&a(i,1,5))or(a(i,-1,1)&a(i,1,1))or(a(i,-1,5)&a(i,1,5))for i,x in enumerate(t)if x=="["])

Pruebas:

towers=(
"[__]",

"..[__]..\n"
"[__][__]",

"........[__]........\n"
"......[__][__]......\n"
"........[__]........",

"..[__][__]..\n"
"[__][__][__]\n"
"..[__][__]..\n"
"[__]....[__]",

"............[__]..\n"
"..[__][__][__][__]\n"
"[__][__][__][__]..\n"
"..[__][__][__][__]\n"
"[__][__][__][__]..",

"..[__]........[__]..\n"
"[__][__][__][__][__]\n"
"..[__][__][__][__]..\n"
"....[__][__][__]....\n"
"......[__][__]......\n"
"........[__]........",

"..[__]..\n"
"........",

"..[__]..\n"
"[__]....",

"..[__]..\n"
"....[__]",

"..[__][__]..\n"
"[__]....[__]\n"
"..[__][__]..\n"
"[__]....[__]",

"..[__][__][__][__]\n"
"[__][__][__][__]..\n"
"..[__][__][__][__]\n"
"[__][__][__][__]..",

"[__][__][__][__][__]\n"
"..[__][__][__][__]..\n"
"....[__][__][__]....\n"
"......[__][__]......\n"
"........[__]........",
)
[s(x) for x in towers]

Salida:

[True, True, True, True, True, True, False, False, False, False, False, False]
legionixtiwo
fuente