Liệt kê các chương trình Brainf ** k hợp lệ


41

Golunar / Unary là một cách để mã hóa tất cả các chương trình Brainfuck hợp lệ , nhưng nó không phải là một phép liệt kê, vì hầu hết các số tự nhiên không tương ứng với một chương trình hợp lệ.

Đối với mục đích của thử thách này, giả sử một cuộn băng vô hạn gấp đôi và không có nhận xét nào, tức là, chương trình Brainfuck là hợp lệ khi và chỉ khi nó chỉ bao gồm các ký tự <>+-.,[]và tất cả các dấu ngoặc trái và phải khớp.

Ví dụ, chương trình trống ,[+][-]., [>+<[--].]+[+[+][+[+]+]+]+.là chương trình Brainfuck hợp lệ, trong khi ][, và a[]không.

Bài tập, nhiệm vụ

Viết chương trình hoặc hàm chấp nhận chương trình Brainfuck hợp lệ làm đầu vào và trả về số tự nhiên ( 1 , 2 , 3 , khắc), với các ràng buộc sau:

  • Đầu ra được tạo phải khác nhau đối với tất cả các chương trình Brainfuck hợp lệ.

  • Đối với mỗi số tự nhiên n , phải có chương trình Brainfuck hợp lệ, khi được cung cấp làm đầu vào, sẽ tạo ra đầu ra n .

Quy tắc bổ sung

  • Đưa ra một chương trình Brainfuck từ 100 byte trở xuống, chương trình hoặc chức năng của bạn phải hoàn thành trong vòng một phút.

    Điều này có nghĩa là bạn không thể lặp lại tất cả các chương trình Brainfuck hợp lệ cho đến khi bạn khớp với đầu vào.

  • Luật tiêu chuẩn được áp dụng.


3
Tôi đã suy nghĩ chỉ mã hóa nó thành bát phân nhưng các dấu ngoặc phù hợp đang làm cho điều này trở nên khó khăn.
DankMeme

Chương trình trống có phải là chương trình Brainfuck hợp lệ không? Nó phải được ánh xạ đến một số nguyên tự nhiên?
orlp

9
Tại sao bỏ phiếu chặt chẽ? Đây là một câu hỏi hấp dẫn vấn đề xảy ra là có kích thước và sự đa dạng cho một sân golf tuyệt vời.
trichoplax

1
@orlp Có, chương trình trống thỏa mãn định nghĩa trên
Dennis

3
Vẫn đang chờ xem câu trả lời được viết bằng Brainfuck ...
Michael Hampton

Câu trả lời:


16

Python 3, 443 158 155 154 134 131 128 124 117 116 115 byte

c=d=C=D=0
for e in input():v='[<>,.-+]'.find(e);d=d*8+v;c+=c<0<6<v;c-=d>1>v;C,D=(c,C+1,d,D)[v>6::2]
print(-~D*8**C)

Một số byte nhờ Sp3000 và Mitch Schwartz: D

Cách thức hoạt động:

Điều này ánh xạ tất cả các chương trình BF hợp lệ vào tất cả các chương trình BF có thể, hợp lệ hoặc không hợp lệ, không bắt đầu bằng [tỷ lệ một đối một. Sau đó, chương trình mới được chuyển đổi đơn giản thành bát phân.

Đây là công thức ánh xạ:

  1. Tách một chương trình BF thành 3 phần. Phần đầu tiên là tiền tố lớn nhất chỉ bao gồm các [ký tự. Phần thứ ba là hậu tố lớn nhất chỉ bao gồm các ]ký tự. Phần thứ hai là phần giữa.
  2. Vứt bỏ phần đầu tiên. Đây có thể được tính toán lại sau.
  3. Xóa tất cả ]dấu ngoặc trong phần thứ ba khớp với [dấu ngoặc trong phần thứ hai. Đây cũng có thể được tính toán lại sau.
  4. Nối các phần thứ hai và thứ ba với nhau.

Nếu bạn không hiểu lời giải thích này, bạn có thể tìm thấy lời giải thích mở rộng trong trò chuyện bắt đầu từ đây .

Để tham khảo, đây là 20 chương trình đầu tiên:

1 : 
2 : <
3 : >
4 : ,
5 : .
6 : -
7 : +
8 : []
9 : <[]
10 : <<
11 : <>
12 : <,
13 : <.
14 : <-
15 : <+
16 : [<]
17 : >[]
18 : ><
19 : >>
20 : >,

Đây là 1000 chương trình đầu tiên: http://pastebin.com/qykBWhmD
Đây là chương trình tôi đã sử dụng để tạo chúng: http://ideone.com/e8oTVl

Đây là Hello, World!:

>>> ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
457711481836430915510337664562435564418569135809989841510260388418118348571803953323858180392373

Phân minh nhỏ: Bạn không thể ánh xạ chương trình thành 0 .
Dennis

@Dennis Một chương trình trống có được tính là một chương trình không?
Beta Decay


@Dennis Tôi sẽ sửa nó khi tôi chơi nó.
TheNumberOne

3
Điều này thật tài tình
tự hào

13

Python 2, 157 byte

def f(s,o=0,d=0,D={}):T=s,o,d;x=D[T]=D[T]if T in D else~o and 0**o+sum(f(s[1:],cmp(c,"[")%-3-~o,d or cmp(c,s[0]))for c in"+,-.<>[]")if s else~d<0==o;return+x

Vẫn trông khá golf, nhưng bây giờ tôi đang đăng bài này. Nó sử dụng đệ quy với một chút bộ nhớ đệm. Khó chịu, D.getkhông bị đoản mạch cho bộ nhớ đệm, vì vậy tôi không thể lưu 9 byte theo cách đó ...

Ánh xạ ưu tiên độ dài trước, sau đó là thứ tự từ điển so với thứ tự "][><.-,+"(xem ví dụ đầu ra bên dưới). Ý tưởng chính là so sánh các tiền tố.

Biến otheo dõi số lượng [dấu ngoặc vẫn mở cho tiền tố hiện tại, trong khi biến dcó một trong ba giá trị cho biết:

  • d = 1: Tiền tố hiện tại sớm hơn về mặt từ vựng s. Thêm tất cả các chương trình với tiền tố và độ dài này <= s,
  • d = -1: Tiền tố hiện tại muộn hơn về mặt từ vựng s. Thêm tất cả các chương trình với tiền tố và độ dài này < s.
  • d = 0: Tiền tố hiện tại là tiền tố của s, vì vậy chúng tôi có thể thay đổi dthành 1 hoặc -1 sau đó.

Ví dụ: nếu chúng ta có s = "[-]"và tiền tố hiện tại của chúng ta là p = "+", vì pmuộn hơn svề mặt từ vựng, chúng ta chỉ biết để thêm các chương trình bắt đầu với pthời gian ngắn hơn s.

Để đưa ra một ví dụ chi tiết hơn, giả sử chúng ta có một chương trình đầu vào s = "-[]". Bản mở rộng đệ quy đầu tiên thực hiện điều này:

  (o == 0)               # Adds a program shorter than s if it's valid
                         # For the first expansion, this is 1 for the empty program
+ f(s[1:], o=-1, d=1)    # ']', o goes down by one due to closing bracket
+ f(s[1:], o=1, d=1)     # '[', o goes up by one due to opening bracket
+ f(s[1:], o=0, d=1)     # '>'
+ f(s[1:], o=0, d=1)     # '<'
+ f(s[1:], o=0, d=1)     # '.', d is set to 1 for this and the previous branches
                         # since they are lexicographically earlier than s's first char
+ f(s[1:], o=0, d=0)     # '-', d is still 0 since this is equal to s's first char
+ f(s[1:], o=0, d=-1)    # ',', d is set to -1 for this and the later branches
                         # since they are lexicographically later than s's first char
+ f(s[1:], o=0, d=-1)    # '+'

Lưu ý cách chúng tôi không thực sự sử dụng các tiền tố trong đệ quy - tất cả chúng ta quan tâm đến họ được chụp thông qua các biến d, ovà các chương trình đầu vào bị thu hẹp s. Bạn sẽ nhận thấy rất nhiều sự lặp lại ở trên - đây là nơi bộ nhớ đệm xuất hiện, cho phép chúng tôi xử lý tốt các chương trình 100 char trong thời gian giới hạn.

Khi strống, chúng tôi xem xét (d>=0 and o==0), quyết định xem có trả về 1 hay không (tính chương trình này vì nó sớm về mặt từ vựng / bằng và chương trình hợp lệ) hoặc 0 (không tính chương trình này).

Bất kỳ tình huống nào có o < 0trả về ngay lập tức 0, vì bất kỳ chương trình nào có tiền tố này có nhiều ]s hơn [và do đó không hợp lệ.


20 đầu ra đầu tiên là:

 1
> 2
< 3
. 4
- 5
, 6
+ 7
[] 8
>> 9
>< 10
>. 11
>- 12
>, 13
>+ 14
<> 15
<< 16
<. 17
<- 18
<, 19
<+ 20

Sử dụng ví dụ Hello World tương tự như câu trả lời của @ TheNumberOne:

>>> f("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.")
3465145076881283052460228065290888888678172704871007535700516169748342312215139431629577335423L

4

Python 2, 505 (không chơi gôn)

Tôi rất thích phát triển phương pháp này, nhưng tôi có thể không bận tâm đến việc chơi golf vì nó không cạnh tranh so với các phương pháp khác. Tôi đang đăng nó vì sự đa dạng và lợi ích thẩm mỹ có thể có. Nó liên quan đến đệ quy và một chút toán học.

F={0:1}

def f(n):
    if n not in F:
        F[n]=6*f(n-1) + sum(f(i)*f(n-2-i) for i in range(n-1))

    return F[n]

def h(x):
    if x=='': return 0

    if len(x)==1: return '+-<>,.'.find(x)

    if x[0]!='[':
        return h(x[0]) * f(len(x)-1) + h(x[1:])

    d=i=1
    while d:
        if x[i]==']': d-=1
        elif x[i]=='[': d+=1
        i+=1

    a=i-2
    b=len(x)-i

    return 6*f(a+b+1) + sum(f(i)*f(a+b-i) for i in range(a)) + h(x[1:i-1]) * f(b) + h(x[i:])

def g(x):
    return sum(f(i) for i in range(len(x))) + h(x) + 1

print g(raw_input())

Hàm này f(n)đếm số lượng chương trình brainfuck hợp lệ có độ dài n. h(x)ánh xạ các chương trình có độ dài nđến [0..f(n)-1]g(x)là hàm xếp hạng phỏng đoán trong câu hỏi.

Ý tưởng chính là một chương trình không trống có thể bắt đầu bằng [hoặc với một trong 6 []ký tự không . Trong trường hợp trước, chúng ta có thể lặp lại các vị trí có thể có của khớp ]và lặp lại trên phần kèm theo và trên đuôi (trong đó đuôi có nghĩa là chuỗi con theo sau ]). Trong trường hợp sau, chúng ta có thể lặp lại trên đuôi (trong đó đuôi có nghĩa là thả ký tự đầu tiên). Lý do này có thể được sử dụng cả để đếm và xếp hạng máy tính.

Các chương trình ngắn hơn sẽ luôn có thứ hạng thấp hơn các chương trình dài hơn và mẫu khung là yếu tố quyết định thứ yếu. Các []ký tự không được sắp xếp theo "+ - <>," (đó là tùy ý).

Ví dụ với n=4chúng tôi có những trường hợp sau:

zxxx
[]xx
[x]x
[xx]

trong đó zviết tắt của từ không phải []ký tự và xlà viết tắt của bất kỳ ký tự nào, theo giới hạn là ]phải khớp với chữ cái đầu [. Các chương trình được xếp hạng theo thứ tự đó và đệ quy trên các xphần phụ, với phần bên trái được ưu tiên hơn phần bên phải trong các trường hợp sau. Tính toán xếp hạng tương tự như các hệ thống số hỗn hợp, và frất quan trọng để tính toán "cơ số" hiện tại.


4

Câu trả lời này là bằng chứng chính thức cho câu trả lời của TheNumberOne , liệt kê các chương trình Brainf ** k hợp lệ , trong đó có thể hơi khó hiểu các điểm tốt tại sao phép liệt kê là chính xác. Không cần thiết để hiểu tại sao không có một chương trình không hợp lệ nào ánh xạ tới một số không được bao phủ bởi một chương trình hợp lệ.

Trong suốt câu trả lời này, thủ đô được sử dụng để biểu thị các chương trình và các biến chữ thường được sử dụng cho các hàm và số nguyên. ~ là toán tử ghép.

Dự luật 1:

Đặt hàm f là chương trình được mô tả trong câu trả lời đó. Sau đó, với mỗi chương trình U tồn tại một chương trình V hợp lệ sao cho f (U) = f (V)

Định nghĩa 1:

Đặt g (X) là số [xuất hiện trong chương trình X và gọi h (X) là số ]xuất hiện.

Định nghĩa 2:

Xác định P (x) là hàm này:

P(x) = "" (the empty program) when x <= 0
P(x) = "]" when x = 1
P(x) = "]]" when x = 2
etcetera

Định nghĩa 3:

Cho một chương trình X, biểu thị X1 là tiền tố lớn nhất của các [ký tự, X2 là trung tâm của nó và X3 là hậu tố lớn nhất của các ]ký tự.

Bằng chứng về mệnh đề 1:

Nếu g (U) = h (U) thì U là chương trình hợp lệ và chúng ta có thể lấy V = U. (trường hợp tầm thường).

Nếu g (U) <h (U) thì chúng ta có thể tạo V bằng cách thêm các ký hiệu n = h (U) - g (U) [. Rõ ràng f (V) = f (U) khi tất cả các [ký hiệu trong tiền tố được loại bỏ.

Bây giờ hãy xem xét g (U)> h (U). Xác định T = U2 ~ U3. nếu g (T) <= h (T), thì chúng ta có thể xây dựng V bằng cách loại bỏ các ký hiệu n = g (U) - h (U) [.

Vì vậy, chúng ta có thể giả sử rằng h (T) <g (T). Xây dựng V = T ~ P (g (T) - h (T)).

Chúng tôi cần ba sự thật nhỏ để tiến hành:

Yêu cầu 1: g (U2) = g (T)

U3 không chứa bất kỳ [ký hiệu nào theo định nghĩa của nó. Vì T = U2 ~ U3, các [ký hiệu của nó đều nằm trong phần đầu tiên.

Yêu cầu 2: h (U3) <g (T)

Điều này xuất phát từ việc lưu ý rằng h (T) <g (T) và h (U3) <h (U3 ~ U2) = h (T).

Yêu cầu 3: h (V3) = g (U2) - h (U2)

h(V3) = h(U3) + g(T) - h(T)                           using the construction of V
h(V3) = h(U3) + g(U2) + g(U3) - h(U2) - h(U3)         apply the definition of T
h(V3) = g(U2) - h(U2) *one term cancels, g(U3)        is always zero, as U3 contains only `]` symbols*

Bây giờ chúng tôi chỉ ra rằng f (V) = f (U).

f(U) = U2 ~ P(h(U3) - g(U2)) = U2                     claim 2, definition of P

f(V) = U2 ~ P(h(V3) - g(V2))
     = U2 ~ P(h(V3) - g(U2))
     = U2 ~ P(g(U2) - h(U2) - g(U2))                  claim 3
     = U2 ~ P(-h(U2))
     = U2                                             definition P

Điều này hoàn thành bằng chứng. QED

Chúng ta hãy làm duy nhất là tốt.

Dự luật 2:

Đặt U, V là hai chương trình khác nhau, hợp lệ. Sau đó f (U)! = F (V)

Điều này khá đơn giản so với các đề xuất trước đây.

Giả sử rằng U2 = V2. Nhưng sau đó, cách duy nhất U và V có thể khác nhau là bằng cách thêm hoặc xóa n []ký hiệu tương ứng với U1 và U3. Tuy nhiên, điều này thay đổi đầu ra của f, vì f sẽ đếm số lượng các ]ký hiệu chưa từng có trong hậu tố.

Do đó U2! = V2.

Rõ ràng, điều này dẫn đến một mâu thuẫn. Vì U2 và V2 được chứa theo nghĩa đen trong đầu ra của f (U) và f (V), chúng không thể khác nhau, ngoại trừ ở 'cạnh', nơi U2 được nối với U3. Nhưng các ký hiệu đầu tiên và cuối cùng của U2 và V2 không thể [hoặc ]theo định nghĩa, trong khi đó là các ký hiệu duy nhất được phép trong U1, U3, V1, V3 tương ứng và một lần nữa. Do đó ta được U2 = V2. QED

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.