Là băng tròn thú vị?


32

Một dẫn xuất Brainfuck

Hãy xác định một ngôn ngữ lập trình giống như Brainfuck . Nó có một băng hai chiều của các ô và mỗi ô giữ một bit. Tất cả các bit ban đầu là 0. Có một đầu di chuyển trên băng, ban đầu ở vị trí 0. Một chương trình là một chuỗi trên các ký tự <>01!, được thực hiện từ trái sang phải, với các ngữ nghĩa sau:

  • < di chuyển đầu một bước sang trái.
  • > di chuyển đầu một bước sang phải.
  • 0 đặt 0 trong ô hiện tại.
  • 1 đặt 1 trong ô hiện tại.
  • ! lật các tế bào hiện tại.

Không có vòng lặp, vì vậy một chương trình gồm n ký tự kết thúc sau n bước chính xác . Một chương trình thật nhàm chán nếu tất cả các ô chứa 0 khi kết thúc thực thi và thú vị nếu có ít nhất một 1. Lưu ý rằng kích thước của băng không được chỉ định, do đó tùy thuộc vào việc triển khai, nó có thể là vô hạn hai chiều hoặc thông tư.

Một chương trình ví dụ

Hãy xem xét chương trình 1>>>!<<<<0>!>>>!. Trên một băng vô hạn, việc thực hiện được tiến hành như sau:

     v
00000000000000  Put 1
     v
00000100000000  Move by >>>
        v
00000100000000  Flip
        v
00000100100000  Move by <<<<
    v
00000100100000  Put 0
    v
00000100100000  Move by >
     v
00000100100000  Flip
     v
00000000100000  Move by >>>
        v
00000000100000  Flip
        v
00000000000000

Cuối cùng, tất cả các ô đều bằng 0, vì vậy chương trình này thật nhàm chán. Bây giờ, hãy chạy cùng một chương trình trên một băng tròn dài 4.

v
0000  Put 1
v
1000  Move by >>>
   v
1000  Flip
   v
1001  Move by <<<< (wrapping around at the edge)
   v
1001  Put 0
   v
1000  Move by > (wrapping back)
v
1000  Flip
v
0000  Move by >>>
   v
0000  Flip
   v
0001

Lần này, có một ô có giá trị 1, vì vậy chương trình rất thú vị! Chúng tôi thấy rằng một chương trình nhàm chán hay thú vị phụ thuộc vào kích thước của băng.

Nhiệm vụ

Đầu vào của bạn là một chuỗi không trống <>01!để biểu thị một chương trình bằng ngôn ngữ lập trình ở trên. Một mảng các ký tự cũng là một định dạng đầu vào chấp nhận được. Chương trình được đảm bảo là nhàm chán khi chạy trên một băng vô hạn. Đầu ra của bạn sẽ là danh sách các độ dài băng mà chương trình thú vị. Lưu ý rằng bạn chỉ cần kiểm tra chương trình trên các băng ngắn hơn thời lượng chương trình.

Giải pháp có số byte thấp nhất trong mỗi ngôn ngữ là người chiến thắng. Luật tiêu chuẩn được áp dụng.

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

> : []
110 : []
1>0<! : [1]
0>>1>0<<>! : [1]
1>>>!<<<<0>!>>>! : [2, 4]
!<!<><<0>!>!<><1!>>0 : [2]
>>!>><>001>0<1!<<!>< : [1, 2, 3]
1!><<!<<<!!100><>>>! : [1, 3]
!!1>!>11!1>>0<1!0<!<1><!0<!<0> : [3, 4]
<><<>>!<!!<<<!0!!!><<>0>>>>!>> : [1, 2, 4]
0>>><!<1><<<0>!>>!<<!!00>!<>!0 : [3]
0000!!!!><1<><>>0<1><<><<>>!<< : []
!>!>!>!>!>1>!>0<!<!<!<0<!<0<!<!<!<1>!>0<<! : [1, 2, 5, 7]
<!!>!!><<1<>>>!0>>>0!<!>1!<1!!><<>><0<<!>><<!<<!>< : [1, 2, 4, 5]
!>1<<11<1>!>!1!>>>0!!>!><!!00<><<<0<<>0<<!<<<>>!!> : [1, 2, 3, 5, 6]

1
Chúng ta có thể chọn bất kỳ nhân vật riêng biệt và nhất quán thay vì <>01!?
Ông Xcoder

1
Là một mảng các hướng dẫn là một đầu vào chấp nhận được?
Arnauld

@ Mr.Xcoder Không, bạn nên sử dụng các ký tự chính xác này.
Zgarb

@Arnauld Một mảng các ký tự đủ gần với một chuỗi, tôi sẽ cho phép nó.
Zgarb

Câu trả lời:


6

Haskell, 119 byte

t#'<'=last t:init t
(h:t)#c|c<'#'=1-h:t|c>'='=t++[h]|1<2=read[c]:t
f p=[n|n<-[1..length p],sum(foldl(#)(0<$[1..n])p)>0]

Hãy thử trực tuyến!

Hàm #là trình thông dịch cho một lệnh duy nhất c. Toàn bộ chương trình pđược chạy bằng folding #với băng bắt đầu vào p. fthực thi pcho mọi băng và giữ cho những nơi có tổng các ô ít nhất là 1.


n<-[1..length p] ... 0<$[1..n]Có vẻ khá dài, phải có một cách ngắn hơn.
nimi

Tôi không thể thấy một cách ngắn hơn. Vấn đề tôi thấy là bạn thực sự cần giá trị của nkết quả, vì vậy nếu bạn xây dựng 0<$[1..n]một cách khác (nói với scanr(:)), bạn cần phải lấy lengthnó. (Tôi cũng đã thử sử dụng 1(để thay thế lengthbằng sum) hoặc False(để sử dụng orcho thử nghiệm) thay vì 0, nhưng nó không xuất hiện ngắn hơn.)
Ørjan Johansen

@ RjanJohansen: vâng, tôi đã thử n<-init$scanr(:)[]$0<$p ... nngắn hơn 2 byte, nhưng nó trả về một danh sách các băng bắt đầu thay vì độ dài của chúng, vd [[0],[0,0,0]]. Với một chút uốn cong quy tắc để có thể xem các băng là số đơn nguyên, vì vậy có lẽ nó ổn.
nimi

init$có thể được thay thế bằng cách đặt một [0]danh sách ban đầu, nhưng nó vẫn không đủ ngắn. Tôi nghĩ rằng unary chỉ được phép cho các ngôn ngữ mà không có đại diện số tự nhiên hơn .
Ørjan Johansen

4

Stax , 56 54 43 38 35 byte CP437

è¥%►BΣ░ÜY⌂y(â&.═ªê►V½▲y▌)▀♫♂╣ª?√»!#

42 byte khi giải nén,

%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a

Chạy và gỡ lỗi trực tuyến!

-2 byte cho mỗi bình luận bởi @recursive

Giải trình

Tôi sẽ sử dụng phiên bản có tiền tố i(nghĩa là i%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a) để giải thích và tôi sẽ giải thích lý do tại sao icó thể xóa

i               Suppress implicit eval
                    This prevents the test case "110" from being interpreted as a number
                    However, this can be removed because a program containing only numbers cannot be exciting and the output will be empty anyway.
                    This is based on the fact that the program is boring on non-circular tapes
 %f             Filter range [1..n] with the rest of this program
                    Where n is the length of the input
                    Implicit output the array after filtering, one element per line
   z(           Initialize the tape
     y{  F      Run the program
          |a    Any cell is non-zero

Mã để chạy chương trình:

{|(}                                 Block to rotate left by one element
    {|)}                             Block to rotate right by one element
        {B!s+}                       Block to perform logical not on the element at index 0
              {0_]e&}                Block to obtain current instruction,
                                         Convert it to a number
                                         And assign to element at index 0

                     4l              Pack the 4 blocks in an array
                       s"<>! "I      Find the index of current instruction in string, if not found, the index will be -1
                                         And when indexed with -1, it wraps around to the 4th element.

                               @!    And execute the corresponding block.

1
Tôi đã thêm một trường hợp thử nghiệm của tất cả các chữ số để xác nhận iséc của bạn .
Zgarb

0]*có thể được thay thế bằng z(. Ngoài ra, nếu bạn thay đổi chuỗi thành "<>!", Thì 01sẽ đưa ra chỉ số -1, do đó, danh sách khối của bạn chỉ cần 4 khối, thay vì 5. Điều này sẽ hoạt động vì dù sao 01trình xử lý giống hệt nhau.
đệ quy

@recursive Điểm tốt thực hiện.
Weijun Zhou




2

Màu đỏ , 243 byte

func[p][repeat n length? p[b: copy[]insert/dup b 0 n i: 1
parse p[any["<"(i: i - 1 if i < 1[i: n])|">"(i: i + 1 if i > n[i: 1])|"0"(b/(i): 0)|"1"(b/(i): 1)|"!"(b/(i): either b/(i) = 0[1][0])|
skip]]s: 0 foreach c b[s: s + c]if s > 0[print n]]]

Hãy thử trực tuyến!

Prety verbose và thực hiện đơn giản. Lập chỉ mục 1 của Red không cho phép tôi giảm số byte bằng cách sử dụng số học mô-đun để lặp qua các băng tròn.

Ung dung

f: func[p][ 
    repeat n length? p[
        b: [] 
        insert/dup b 0 n
        i: 1
        parse p[
            some [
                 "<" (i: i - 1 if i < 1[i: n])
               | ">" (i: i + 1 if i > n[i: 1])
               | "0" (b/(i): 0)
               | "1" (b/(i): 1)
               | "!" (b/(i): either b/(i) = 0 [1][0])
               | skip 
            ]
        ]
        s: 0
        foreach c b[s: s + c]
        if s > 0 [print n]
    ]
]


2

Võng mạc , 121 byte

.+
$.&*0¶$&
\G0
0$`¶
{ms`^.(?=.*¶¶(0|1))
$1
"¶¶!"&mT`d`10`^.
"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶
)`¶¶.
¶¶
G`1
%`.

Hãy thử trực tuyến! Giải trình:

.+
$.&*0¶$&
\G0
0$`¶

Tạo một mảng băng có độ dài cho đến chiều dài của chương trình đầu vào.

{

Lặp lại cho đến khi chương trình được tiêu thụ.

ms`^.(?=.*¶¶(0|1))
$1

Nếu ký tự tiếp theo trong chương trình là 0 hoặc 1, hãy thay đổi ký tự đầu tiên trên mỗi dòng thành ký tự đó.

"¶¶!"&mT`d`10`^.

Nếu đó là một !thì hãy chuyển ký tự đầu tiên trên mỗi dòng.

"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶

Nếu nó là một >hoặc <sau đó xoay dòng. (Dễ dàng hơn di chuyển đầu.)

)`¶¶.
¶¶

Xóa hướng dẫn và kết thúc vòng lặp.

G`1

Chỉ giữ lại những dòng thú vị.

%`.

Đếm độ dài của mỗi dòng.


2

JavaScript (ES6), 126 118 byte

Đã lưu 3 byte nhờ @ user71546

Lấy đầu vào là một chuỗi các chuỗi 1 ký tự.

f=(s,l=0,p=0,t=[])=>s[l++]?s.map(c=>1/c?t[p%l]=+c:c>'='?p++:c>';'?p+=l-1:t[p%l]^=1)&&+t.join``?[l,...f(s,l)]:f(s,l):[]

Hãy thử trực tuyến!


Thay thế t.some(x=>x)?bằng cách +t.join``?kiểm tra thay vì kiểm tra mảng dưới dạng chữ số (và 0 chỉ ra một băng hoàn toàn bằng 0), nhưng ít hơn 3 byte.
Shieru Asakoto

2

APL (Dyalog Unicode) , 79 64 54 byte ( SBCS của Adám )

⍸⊂{∨/⍎⍕(↓',',⍨5 3'0@11@1~@1 1⌽¯1⌽')['01!<'⍳⌽⍺]⍵}¨0=,\

Hãy thử trực tuyến!

-15 cảm ơn Adám (quên về đơn nguyên ).
-10 cảm ơn ngn .



@ Adám H'm, có vẻ như điều đó không tối ưu (ví dụ bạn không cần ). Tôi sẽ xem xét và cập nhật. :)
Erik the Outgolfer

Nhưng nếu bạn loại bỏ bạn sẽ cần một ;, không?
Adám

@ Adám không , tại sao bạn?
Erik the Outgolfer


1

MATL , 46 39 byte

f"@:~G"@59>?@61-YS}@33=?t1)~}@U]1(]]a?@

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp thử nghiệm .

Làm thế nào nó hoạt động

f             % Push indices of nonzero chars of (implicit) input string: gives
              % [1 2 ... n] where n is input length
"             % For each k in [1 2 ... n]. These are the possible tape lengths
  @:~         %   Push array of k zeros. This is the tape, in its initial state
  G           %   Push input string
  "           %   For each char in the input string
    @59>?     %     If code point of current char exceeds 59 (so it is '<' or '>')
      @61-    %       Push code point minus 61: gives -1 for '<', or 1 for '>'
      YS      %       Circularly shift the tape by that amount. Instead of moving
              %       the head, we shift the tape and keep the head at entry 1
    }         %     Else
      @33=?   %       If code point of current char is 33 (so it is '!')
        t1)   %         Duplicate the array representing the tape, and get its
              %         first entry
        ~     %         Logical negate
      }       %       Else
        @U    %         Push current char (it is '0' or '1') converted to number
      ]       %       End
      1(      %       Write (either 0, 1 or old value negated) at entry 1
    ]         %     End
  ]           %   End
  a?          %   If the tape contains at least a nonzero value
    @         %     Push tape length, k
              %   End (implicit)
              % End (implicit)
              % Display (implicit)

1

APL (Dyalog Unicode) , 192 78 byte

⊂{t/⍵⊣⍵{t[m]←('01!'⍳⍵)⊃0 1,e,⍨~et[m←⍺|ii+←¯1 1 0⊃⍨'<>'⍳⍵]}¨⍺⊣i←⊃t←⍬⍳⍺}¨1+⍳∘≢

Hãy thử trực tuyến! (kết quả không làm phẳng)

Hãy thử trực tuyến! (dẹt)

Sau một thời gian đập đầu vào tường, tôi quyết định làm Tradfn thay vì Dfn. Đây là kết quả. Những người thông minh hơn tôi có thể đánh golf ra khỏi đây.

Bất ngờ, ngạc nhiên, một người thông minh hơn tôi đã chơi golf từ cái này. Cảm ơn bạn Adám cho 114 byte.

Anh nói:

Lưu ý rằng đó là chương trình chính xác của bạn, ngoại trừ sử dụng lập chỉ mục thay vì bên trong: Ifs và sụp đổ: Vòng lặp cho {_} ¨ trong khi đưa ra một đối số bên trái để thay thế toàn cục.

Hàm giả định ⎕IO←0.


Làm sao?

(Giải thích này sử dụng phiên bản "không có ý thức" để thuận tiện cho việc đọc)

⊂{                                   Enclose
      i←⊃t←⍬⍳⍺                       Assign a vector of 0s to t (the tape), then assign the first 0 to i.
      t/⍵⊣⍵{                         Use  as left argument for the nested function, then compress the result into t. If there is a 1 anywhere in t, the result will be a vector of the result. If not, the result is an empty vector.
          i+←¯1 1 0⊃⍨'<>'⍳⍵          Map the string '<>' to the argument (which is the BF program). That yields 0 for <, 1 for >, and 2 for anything else.
                                     The resulting vector will then be used as the argument for  to add -1 (index 0), 1 (index 1) or 0 (index 2) to the variable i.
          et[m←⍺|i]                 Assign i mod  (left arg) to m, and use it to index t. Then, assign the value to e.
          t[m]←('01!'⍳⍵)⊃0 1,e,⍨~e   Map the string '01!' to ⍵. As before, this yields 0 for 0, 1 for 1, 2 for ! and 3 for anything else.
                                     Then, concatenate (not e) with e, then concatenate that with the vector 0 1. This is used as argument to be picked from, and it is assigned to t[m].
      }¨⍺                            Do that for each argument
  1+⍳∘≢                            And do that for each possible tape length from 1 to the length of the input.

1
Lưu một byte bằng cách làm cho t←l⍴0được t←l⍴i←0, và loại bỏ các dòng ở trên nó. Bạn cũng có thể lưu cái khác bằng cách thay đổi t[i|⍨≢t]←1-t[i|⍨≢t]thành t[i|⍨≢t]←~t[i|⍨≢t].
Zacharý

2
@ Zacharý đúng, và tiếp tục lưu thêm 112 byte . Chính xác mã giống nhau, chỉ cần chơi golf một chút.
Adám

Vâng, nó chỉ là "một chút". Bạn không cần s?
Zacharý

@ Zacharý là gì? Đây là một chức năng ngầm.
Adám

@ Zacharý Tôi sẽ xem xét một Adám'd xinh đẹp này, phải không?
J. Sallé


0

C (tiếng kêu) , 171 byte

l,i;f(S){for(char*p,t[l=strlen(S)];l;memchr(t,1,l)&&printf("%d ",l),l--)for(memset(t,i=0,l),p=S;*p;p++)*p==60?i=i?i-1:l-1:*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1);}

Hãy thử trực tuyến!

Phải sử dụng tiếng kêu, vì sử dụng char*p,t[l=strlen(S)]làm biểu thức khởi tạo vì một số lý do khiến GCC nghĩ rằng tôi muốn khai báo strlenthay vì gọi nó.

Khá đơn giản: Chạy chương trình trên các băng tròn có chiều dài giảm dần, xuất ra bất kỳ độ dài nào dẫn đến 1 ở đâu đó trên băng.

Đã thử rút ngắn mớ rối của các nhà khai thác ternary, nhưng cuối cùng cần nhiều dấu ngoặc đơn hơn là khỏe mạnh.


Đề xuất i=0,bzero(t,l)thay vì memset(t,i=0,l)*p-62?t[i]=*p^33?*p-48:t[i]^1:(i=~i+l?i+1:0)thay vì*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1)
trần mèo
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.