Is the brick structure stable?
80386 machine code, 98

The code:

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


The code scans the ASCII art from the end to the beginning, jumping 2 characters at a time. This does twice the needed checks (it would be enough to jump 4 characters), but simplifies the logic.

Checking starts at the next-to-last row of characters (no need to check the last line). At each line, it starts 3 characters from the right (no need to check too far to the right). For each character, it checks 4 surrounding characters:

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


There is a bunch of logical conditions to check:


If A and C are brick characters, X is supported
If B and D are brick characters, X is supported
If C and D are brick characters, X is supported
If X is a brick character, it has to be supported; otherwise the structure is unstable


It's a lucky coincidence that all brick characters [_] have their LSB set; all other characters .\n have it clear. In addition, the 80386 instruction set has these handy "high" and "low" registers (ah, al, etc), which help parallelize the checks a bit. So all the checking amounts to some obscure bit fiddling.

I started from the following C code:

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 &gt;= 0)
    {
        int a = ptr[-4];
        int c = ptr[-4 + 2 * width];
        int b = ptr[0];
        int d = ptr[0 + 2 * width];
        int ab = a &lt;&lt; 8 | b;
        int cd = c &lt;&lt; 8 | d;
        if (pos &lt; 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 &amp;= 0xff; // C doesn't exist; set it to 0
            ++jump;
        }
        int support_v = ab &amp; cd;
        support_v = support_v | support_v &gt;&gt; 8; // data in LSB
        int support_h = cd &amp; cd &gt;&gt; 8; // data in LSB
        int support = (support_v | support_h) &amp; 1;
        if (!support &amp; ptr[-2 + width])
            goto UNSTABLE;
        ptr -= jump;
        pos -= jump;
    }
    return 1;
UNSTABLE:
    return 0;
}


I translated the code to assembly language (it's mostly one-to-one), including a golfed implementation of strchr and strlen. The following source code is translated by MS Visual Studio to the machine code at the top of my post.

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