Чи стабільна цегляна структура?


24

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

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

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

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

Існує три способи, коли окрема цегла може бути стійкою:

  1. Будь-яка цегла на землі (найнижча лінія цегли) є стійкою.
  2. Будь-яка цегла, яка має дві цегли прямо під нею, є стійкою:

      [__]   <- this brick is stable
    [__][__] <- because these bricks hold it up
    
  3. Будь-яка цегла, яка має цеглу як над, так і під нею з одного боку, є стійкою:

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

З цих правил ми бачимо, наприклад, розташування

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

нестабільна, оскільки цегла правого верхнього цегли нестабільна, і це все, що потрібно.

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

Виклик

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

Вхідний рядок може бути довільно великим, але це завжди буде прямокутна сітка символів, з пробілами, заповненими просторами, цегли. Ширина сітки символів ділиться на 4, але висота може бути непарною або парною.

Цегляна сітка завжди простягається вгорі та праворуч від нижнього лівого положення цегли:

         .
         .
         .
  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?

Залежно від структури кожен BRK?або являє собою цеглу ( [__]) або порожній простір (4 місця).

Зауважте, що порожнини напівцеглини заповнені пробілами, щоб сітка символів була прямокутною.

Оцінка балів

Виграє найкоротший код у байтах .

Примітки

  • За бажанням ви можете скористатися . замість місця пробіл як символ порожнього простору.
  • Порожній рядок вважається стабільним.
  • Якщо у вашій мові немає функцій, ви можете використовувати названу рядову змінну в якості введення та призначити результат іншій змінній.
  • Якщо у вашій мові немає рядків, ви можете робити все, що здається підходящим для введення.

Випробування

Різні тестові випадки, розділені порожніми рядками. Для наочності .використовується замість місця для порожніх пробілів.

Стабільний:

[__]

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

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

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

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

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

Нестабільний:

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

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

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

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

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

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

7
Я майже впевнений, що ваше визначення стабільності не відповідає дійсності ;-)
Джон Дворак

14
@JanDvorak Я знаю, але хто хотів би пограти в цілий двигун фізики: P
Захоплення Кальвіна

........[__].... ......[__][__].. ....[__][__].... ..[__][__]...... [__][__]........ ..[__]..........(вам доведеться подумки складати ці лінії один на одного. Справа в тому, що ваші правила дозволяють структурам, центр ваги яких далеко віднесений від точки їх контакту із землею. Щоб уникнути цього, слід затягнути їх. , не потребуючи фізичного двигуна, якщо вам це здалося.)
Натаніель

2
Однак правдивість у фізиці - це величезна банка глистів. Можна придумати безліч простих випадків, коли стійкість залежить від коефіцієнта тертя та / або від ваги цегли зверху.
COTO

10
"стабільний"… хе
вівчар

Відповіді:


12

Код машини 80386, 98

Кодекс:

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

Код сканує зображення ASCII від кінця до початку, стрибуючи по 2 символи за один раз. Це робить двічі необхідні перевірки (досить було б перестрибнути 4 символи), але спрощує логіку.

Перевірка починається з наступного до останнього рядка символів (не потрібно перевіряти останній рядок). У кожному рядку він починається з 3 символів справа (не потрібно перевіряти занадто далеко праворуч). Для кожного символу він перевіряє 4 навколишніх символи:

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

Існує купа логічних умов для перевірки:

  • Якщо A і C є цегляними символами, X підтримується
  • Якщо B і D є цегляними символами, підтримується X
  • Якщо C і D є цегляними символами, підтримується X
  • Якщо X - цегляний символ, його потрібно підтримувати; інакше структура нестабільна

Щасливий збіг випадків, що всі цегельні персонажі [_]мають свій набір LSB; всі інші символи .\nмають це зрозуміло. Крім того, набір інструкцій 80386 має такі зручні регістри "високого" та "низького" ( ah,al і т.д.), які допомагають распараллелить перевіряє небагато. Таким чином, вся перевірка становить деяке незрозуміле біт.

Я почав із наступного коду С:

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

Я перевів код на мову складання (він здебільшого один на один), включаючи реалізацію strchrі strlen. Наступний вихідний код переведений MS Visual Studio на машинний код у верхній частині мого повідомлення.

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

7

MATLAB - 119 байт

Мінімізовано:

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

Розширено:

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

Використання зразка:

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

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

S4: 1

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

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

U4: 0

Деталі

Підпрограма додає рядок .до верхньої частини вхідної матриці, а потім перетворюється на числову матрицю, додаючи 3 до коду символів ASCII. Враховуючи це перетворення, 2D згортання з ядром

 2  0
-1 -1
 0  2

отримує матрицю з 0місцями, де символьний візерунок

 . *
 _ _
 * .

присутній, *представляючи "будь-який персонаж". Через конструкцію ядра, це єдиний дійсний шаблон символів, який дасть a 0.

Ідентична згортання виконується з ліво-правою перевернутою версією ядра для виявлення

 * .
 _ _
 . *

Вхід стабільний, якщо або i ) він порожній, або ii ) в жодній згортці не з'являються нулі.

Два розчарування є

  1. Згортання за замовчуванням MATLAB проходить повз крайок матриці операндів, створюючи помилкові 0s в протилежних кутах для обох згортків, вимагаючи ,'valid'додавання (8 байт) для conv2виклику, щоб обмежити вихід на область, де згортання дійсне.

  2. Обробка порожнього рядка рядка додає 12 байт.


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)

Тест в консолі 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)))

Вихідні дані

    [__]
true

  [__]  
[__][__]
true

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

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

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

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

  [__]  
false

  [__]  
[__]    
false

  [__]  
    [__]
false

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

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

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

Безумовно

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] != '.'
    )  
  )
)

Що [...a]робити, якщо ви не заперечуєте проти мого запитання? Я знаю, що ES6 дозволяє ...argв якості останнього аргументу функції фіксувати варіанти, але я ніколи не бачив, щоб він використовувався таким чином.
COTO

@COTO codegolf.stackexchange.com/a/37723/21348 , використовуйте випадок 2 (це дуже часто, я використовую його, можливо, 80% моїх відповідей)
edc65

Сунофагун. Так само, як {:}у MATLAB. Це буде дуже корисно. Спасибі. :)
COTO

1

Пітон 279

Я думаю, що я дуже поганий у проблемах з кодом для гольфу, і, можливо, я використовую неправильні мови для цього: D Але я люблю код, який можна легко прочитати :) До речі, я хотів би бачити код python, який використовує менше байтів!

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

Можливі приклади:

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

B = "..[__]........[__]..\n\
[__][__][__][__][__]\n\
..[__][__][__][__]..\n\
....[__][__][__]....\n\
......[__][__]......\n\
........[__]........"
print t(B) #True

Я не використовую точки всередині мого коду, на самому ділі ваш вхід може використовує будь-який символ , але не _та [
Wikunia

1
Як правило, замість використання <>ви б використовували !=.
Етан Бірлен

@EthanBierlein не був впевнений, але так !=- бажаний спосіб
Wikunia

1

JavaScript 2 (ES6) - 148 151 байт

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

Очікує рядок цегляних рядків, розділених новою лінією (зауважте: якщо ми могли використати інший символ розділення типу "|" для розділення рядків, це може бути на 1 байт коротшим).

Тест в консолі Firefox за допомогою:

F('..[__]......\n[__][__][__]\n..[__][__]..\n[__]....[__]'); // false
F('..[__][__]..\n[__][__][__]\n..[__][__]..\n[__]....[__]'); // true

0

Пітон, 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=="["])

Тести:

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]

Вихід:

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