砖结构稳定吗?


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
我很确定您对稳定性的定义与现实不符;-)
John Dvorak 2014年

14
@JanDvorak我知道,但谁愿意高尔夫整个物理引擎:P
卡尔文的爱好

........[__].... ......[__][__].. ....[__][__].... ..[__][__]...... [__][__]........ ..[__]..........(您必须在头脑上将这些线叠放在一起。要注意的是,您的规则允许重心偏离与地面的接触点的结构。应有可能将其拧紧以避免这种情况,而不需要物理引擎,如果您愿意的话。)
Nathaniel 2014年

2
然而,物理上的普遍性是蠕虫的一大罐。可以提出许多简单的情况,其中稳定性取决于摩擦系数和/或顶部砖的重量。
COTO 2014年

10
“稳定” ......
wchargin

Answers:


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是一个积木字符,则必须支持它;否则结构不稳定

幸运的巧合是,所有积木字符[_]都有其最低有效位。所有其他字符.\n都清楚。此外,80386的指令集有这些方便的“高”和“低”寄存器(ahal,等),这有助于并行的检查了一下。因此,所有检查都有些模糊。

我从以下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;
}

我将代码翻译为汇编语言(通常是一对一的语言),包括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

细节

该例程.在输入矩阵的顶部追加一行,然后通过在ASCII字符代码上加3转换为数字矩阵。进行此转换后,将与内核进行2D卷积

 2  0
-1 -1
 0  2

产生一个矩阵,该矩阵0的字符模式位于

 . *
 _ _
 * .

存在,*代表“任何字符”。由于内核的构造,这是唯一会产生a的有效字符模式0

使用内核的左右翻转版本执行相同的卷积以检测

 * .
 _ _
 . *

如果i)为空,或者ii)任一卷积中都没有零,则输入是稳定的。

两个挫败感是

  1. MATLAB的默认卷积经过操作数矩阵的边缘,0对于两个卷积,在相对的角上都产生错误的s,要求添加,'valid'(8个字节)以conv2调用以将输出限制到卷积有效的区域。

  2. 处理空字符串的情况将增加12个字节。


6

JavaScript(E6)131261

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 2014年

@COTO codegolf.stackexchange.com/a/37723/21348,用例2(这很常见,我可能在80%的答案中使用它)
edc65 2014年

舒诺发 就像{:}在MATLAB中一样。这将非常有用。谢谢。:)
COTO 2014年

1

Python 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不确定,但是是!=tge的首选方式
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]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.