Cấu trúc gạch có ổn định không?


24

Chúng ta hãy đại diện cho một viên gạch tiêu chuẩn[__](và bỏ qua thực tế là đỉnh được mở). Khi các viên gạch này được xếp chồng lên nhau, mọi lớp khác được bù lại bằng một nửa viên gạch, như thường lệ trong xây dựng gạch:

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

Do đó, mỗi viên gạch có nhiều nhất là sáu hàng xóm và hai viên gạch không thể xếp hàng trực tiếp theo chiều dọc.

Điểm mấu chốt là sự sắp xếp của những viên gạch này không bị phá hủy , mà chỉ được giữ bằng trọng lực. Vì vậy, điều quan trọng là mỗi viên gạch trong cấu trúc phải ổn định, nếu không thì toàn bộ cấu trúc không ổn định.

Có ba cách một viên gạch riêng lẻ có thể ổn định:

  1. Bất kỳ gạch trên mặt đất (dòng gạch thấp nhất) là ổn định.
  2. Bất kỳ viên gạch nào có hai viên gạch trực tiếp bên dưới đều ổn định:

      [__]   <- this brick is stable
    [__][__] <- because these bricks hold it up
    
  3. Bất kỳ viên gạch nào có một viên gạch cả trên và dưới nó trên cùng một mặt đều ổn định:

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

Từ những quy tắc này, chúng ta có thể thấy, ví dụ, sự sắp xếp

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

là không ổn định bởi vì gạch bên phải trên không ổn định, đó là tất cả những gì nó cần.

Một cấu trúc gạch chỉ ổn định nếu tất cả các viên gạch của nó ổn định.

Thử thách

Nhiệm vụ của bạn là viết một hàm lấy chuỗi cấu trúc gạch và trả về giá trị trung thực nếu cấu trúc ổn định và giá trị giả nếu không ổn định. ( định nghĩa trung thực / giả )

Chuỗi đầu vào có thể lớn tùy ý nhưng nó sẽ luôn là một lưới các ký tự hình chữ nhật, với các khoảng trống lấp đầy các khoảng trống của các viên gạch. Chiều rộng lưới ký tự sẽ chia hết cho 4 nhưng chiều cao có thể là số lẻ hoặc số chẵn.

Lưới gạch luôn mở rộng ở trên và bên phải của vị trí gạch dưới bên trái:

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

Tùy thuộc vào cấu trúc, mỗi cái BRK?đại diện cho một viên gạch ( [__]) hoặc khoảng trống (4 khoảng trắng).

Lưu ý rằng các hốc nửa gạch được lấp đầy các khoảng trống để đảm bảo lưới ký tự là hình chữ nhật.

Chấm điểm

Mã ngắn nhất tính bằng byte thắng.

Ghi chú

  • Nếu muốn bạn có thể sử dụng . thay vì khoảng trắng làm ký tự khoảng trống.
  • Chuỗi rỗng được coi là ổn định.
  • Nếu ngôn ngữ của bạn không có chức năng, bạn có thể sử dụng biến chuỗi được đặt tên làm đầu vào và gán kết quả cho biến khác.
  • Nếu ngôn ngữ của bạn không có chuỗi, bạn có thể làm bất cứ điều gì có vẻ phù hợp cho đầu vào.

Các trường hợp thử nghiệm

Các trường hợp thử nghiệm khác nhau, cách nhau bởi các dòng trống. Để rõ ràng .được sử dụng thay vì không gian cho không gian trống.

Ổn định:

[__]

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

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

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

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

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

Không ổn định:

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

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

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

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

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

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

7
Tôi khá chắc chắn rằng định nghĩa về sự ổn định của bạn không phù hợp với thực tế ;-)
John Dvorak

14
@JanDvorak Tôi biết nhưng ai muốn chơi cả một cỗ máy vật lý: P
Sở thích của Calvin

........[__].... ......[__][__].. ....[__][__].... ..[__][__]...... [__][__]........ ..[__]........... , mà không cần một động cơ vật lý, nếu bạn cảm thấy thích nó.)
Nathaniel

2
Tuy nhiên, tính xác thực trong vật lý là một con giun khổng lồ. Người ta có thể đưa ra nhiều trường hợp đơn giản trong đó độ ổn định phụ thuộc vào hệ số ma sát và / hoặc trọng lượng của các viên gạch trên đầu.
COTO

10
"Ổn" " he heh
wchargein

Câu trả lời:


12

Mã máy 80386, 98

Mật mã:

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

Mã này quét nghệ thuật ASCII từ đầu đến cuối, nhảy 2 ký tự cùng một lúc. Điều này thực hiện hai lần kiểm tra cần thiết (nó sẽ đủ để nhảy 4 ký tự), nhưng đơn giản hóa logic.

Việc kiểm tra bắt đầu ở hàng ký tự tiếp theo (không cần kiểm tra dòng cuối cùng). Ở mỗi dòng, nó bắt đầu 3 ký tự từ bên phải (không cần kiểm tra quá xa bên phải). Đối với mỗi ký tự, nó kiểm tra 4 ký tự xung quanh:

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

Có một loạt các điều kiện hợp lý để kiểm tra:

  • Nếu A và C là ký tự gạch, X được hỗ trợ
  • Nếu B và D là ký tự gạch, X được hỗ trợ
  • Nếu C và D là ký tự gạch, X được hỗ trợ
  • Nếu X là một ký tự gạch, nó phải được hỗ trợ; mặt khác cấu trúc không ổn định

Thật là một sự trùng hợp may mắn khi tất cả các nhân vật cục gạch [_]đều có bộ LSB của họ; tất cả các nhân vật khác .\ncó nó rõ ràng. Ngoài ra, tập lệnh 80386 có các thanh ghi "cao" và "thấp" tiện dụng này (ah ,al , vv), mà giúp đỡ parallelize kiểm tra một chút. Vì vậy, tất cả các số tiền kiểm tra một số khó hiểu bit fiddling.

Tôi bắt đầu từ mã C sau:

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

Tôi đã dịch mã sang ngôn ngữ lắp ráp (chủ yếu là một-một), bao gồm cả việc triển khai strchrstrlen. Mã nguồn sau đây được dịch bởi MS Visual Studio sang mã máy ở đầu bài của tôi.

__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 byte

Giảm thiểu:

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

Mở rộng:

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

Sử dụng mẫu:

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

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

S4: 1

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

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

U4: 0

Chi tiết

Thường trình nối thêm một hàng .vào đầu ma trận đầu vào, sau đó chuyển đổi thành ma trận số bằng cách thêm 3 vào mã ký tự ASCII. Với sự chuyển đổi này, một tích chập 2D với kernel

 2  0
-1 -1
 0  2

mang lại một ma trận 0tại các vị trí có mẫu ký tự

 . *
 _ _
 * .

có mặt, với *đại diện cho "bất kỳ nhân vật". Do cấu trúc của kernel, đây là mẫu ký tự hợp lệ duy nhất sẽ mang lại a 0.

Một phép chập giống hệt được thực hiện với phiên bản lật trái phải của hạt nhân để phát hiện

 * .
 _ _
 . *

Một đầu vào ổn định nếu i ) nó trống hoặc ii ) không có số 0 nào xuất hiện trong cả hai tích chập.

Hai sự thất vọng là

  1. Tích chập mặc định của MATLAB chạy qua các cạnh của ma trận toán hạng, tạo ra các lỗi sai 0ở các góc đối diện cho cả hai cấu trúc, yêu cầu ,'valid'(8 byte) được thêm vào để conv2gọi để giới hạn đầu ra ở khu vực có tích chập hợp lệ.

  2. Xử lý trường hợp chuỗi rỗng thêm 12 byte.


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)

Thử nghiệm trong bảng điều khiển 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)))

Đầu ra

    [__]
true

  [__]  
[__][__]
true

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

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

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

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

  [__]  
false

  [__]  
[__]    
false

  [__]  
    [__]
false

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

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

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

Bị đánh cắp

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

Làm gì [...a], nếu bạn không phiền tôi hỏi? Tôi biết ES6 cho phép ...argnhư là đối số cuối cùng của một chức năng để nắm bắt các từ khóa, nhưng tôi chưa bao giờ thấy nó được sử dụng theo cách này.
COTO

@COTO codegolf.stackexchange.com/a/37723/21348 , sử dụng trường hợp 2 (nó rất phổ biến, tôi sử dụng nó trong khoảng 80% câu trả lời của tôi)
edc65

Sunofagun. Giống như {:}trong MATLAB. Điều đó sẽ rất hữu ích. Cảm ơn. :)
COTO

1

Con trăn 279

Tôi nghĩ rằng tôi khá tệ trong các thử thách chơi gôn và có thể tôi sử dụng sai ngôn ngữ cho điều đó: D Nhưng tôi thích mã có thể dễ đọc :) Btw Tôi muốn thấy một mã python sử dụng ít byte hơn!

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

Ví dụ có thể:

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

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

Tôi không sử dụng các dấu chấm bên trong mã của mình, thực ra đầu vào của bạn có thể sử dụng bất kỳ ký tự nào nhưng không _[
Wikunia

1
Nói chung thay vì sử dụng <>, bạn sẽ sử dụng !=.
Ethan Bierlein

@EthanBierlein không chắc chắn nhưng vâng, đó !=là cách ưa thích
Wikunia

1

JavaScript 2 (ES6) - 148 151 byte

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

Loại bỏ một chuỗi các hàng gạch được phân tách dòng mới (lưu ý: nếu chúng ta có thể sử dụng một ký tự phân tách khác như "|" để phân tách các hàng này thì có thể rút ngắn hơn 1 byte).

Kiểm tra trong bảng điều khiển Firefox với:

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

0

Con tră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=="["])

Các xét nghiệm:

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]

Đầu ra:

[True, True, True, True, True, True, False, False, False, False, False, False]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.