Giải quyết một phần vấn đề tạm dừng cho brainf ***


9

Để giải quyết vấn đề dừng, bạn được cung cấp một mô tả về chương trình và phải xác định liệu nó có bao giờ kết thúc hay không. Bạn không bao giờ có thể làm điều này cho tất cả các chương trình. Tuy nhiên, đối với các chương trình như (trong brainf *** ):

>

Nó rõ ràng sẽ dừng lại, và cho các chương trình như:

+[]

Nó rõ ràng sẽ không. Thách thức của bạn là "giải quyết" vấn đề tạm dừng cho càng nhiều chương trình càng tốt. Các chương trình này sẽ không sử dụng .hoặc ,, và sẽ không có đầu vào hoặc đầu ra. Bạn sẽ được cung cấp một mô tả về chương trình và phải xuất ra "Dừng", "Không dừng lại" hoặc "Không biết". Khi chương trình của bạn xuất ra "Dừng" hoặc "Không dừng lại", bạn đã giải quyết chương trình nhập. Dưới đây là một số yêu cầu.

  1. Nó phải giải quyết ít nhất một lượng chương trình vô hạn.
  2. Đối với mỗi chương trình nó giải quyết, giải pháp của nó phải chính xác.
  3. Bạn chỉ có thể xuất 1 trong 3 lựa chọn trên.
  4. Bạn có thể cho rằng máy tính đang chạy có thời gian và bộ nhớ vô hạn, vì vậy XKCD 1266 sẽ không hoạt động (băng không giới hạn).
  5. Không có nguồn lực bên ngoài.
  6. Bạn không thể sử dụng ngôn ngữ lập trình thực sự có thể giải quyết vấn đề tạm dừng .

Bạn có thể có một chương trình bên không có mã, lấy một chuỗi là một chương trình và tạo ra một số loại cú pháp trừu tượng của nó nếu bạn muốn. Lưu ý, đó không thực sự là điểm mỗi se, nhưng làm thế nào để xác định xem một chương trình có đánh bại chương trình khác không.

  1. Nếu chương trình A giải quyết vô số chương trình mà B không có, nhưng B chỉ giải quyết hữu hạn hoặc không có chương trình nào mà A giải quyết, A sẽ tự động thắng.
  2. Nếu không, chương trình có ít nhân vật nhất sẽ thắng. Không tính khoảng trắng hoặc bình luận, vì vậy đừng làm xáo trộn mã của bạn.

Mẹo: Bộ hẹn giờ sẽ không hoạt động. Bạn thấy, đối với bất kỳ lúc nào T và máy đã cho, đều có N, sao cho tất cả các chương trình dài hơn thời gian đó phải mất nhiều hơn thời gian T. Điều này có nghĩa là bộ hẹn giờ chỉ có thể đạt được giải pháp về số lượng chương trình hữu hạn và, như bạn có thể thấy ở trên, việc giải quyết số lượng chương trình hữu hạn không giúp ích được gì.


3
Tôi không nghĩ hệ thống tính điểm sẽ hoạt động. Đưa ra bất kỳ giải pháp nào, thật dễ dàng để xây dựng một giải pháp tốt hơn như sau: Tìm bất kỳ chương trình P nào mà giải pháp S đưa ra "Không xác định", tạo một giải pháp mới đưa ra câu trả lời đúng trên đầu vào P, cùng một câu trả lời trên P với bất kỳ số nào của >s được thêm vào cuối (vì các lệnh dừng này dừng lại) và đưa ra câu trả lời của S trên tất cả các đầu vào khác. Đây mới phá được giải pháp vấn đề vô cùng hơn S.
cardboard_box

Những điều này được thực hiện không thêm bất kỳ giải pháp mặc dù. Ví dụ, P ban đầu chỉ có thể nói "nếu điều cuối cùng là >, bỏ qua nó." Sau đó, điều của bạn sẽ là dư thừa.
PyRulez

Đúng vậy, trước tiên hãy tạo một giải pháp S 'trả lời giống như S nhưng bỏ qua >s sau khi kết thúc chương trình, sau đó tìm chương trình P trên đó S' trả lời "Không xác định", sau đó tạo một giải pháp mới trả lời đúng trên P với >s nối thêm và đưa ra câu trả lời của S 'nếu không. Vì S 'bỏ qua >s nên P với bất kỳ số >s được nối nào cũng sẽ không được S' giải quyết.
cardboard_box

3
"Ít nhất là một số lượng vô hạn của các chương trình"? Có một phần thưởng cho việc giải quyết nhiều hơn? ;-)
Jonathan Van Matre

1
Vì rõ ràng bạn không tuân theo triển khai tham chiếu, nên có lẽ bạn nên làm rõ tất cả các khác biệt triển khai khác: kích thước ô, hành vi trên dòng chảy tràn và tràn, cho dù băng là vô hạn theo cả hai hướng hay chỉ một, và nếu chỉ có một điều xảy ra khi bạn cố gắng di chuyển qua nó Đây không phải là ngôn ngữ được chỉ định chặt chẽ nhất ...
Peter Taylor

Câu trả lời:


8

Python, mã spaghetti vô danh

Trời ơi.

def will_it_halt(instructions):
    tape_length = 1
    LOOP_BOUND = 1000
    registry = [0] * tape_length
    pos = 0

    jumpbacks = []
    reached_states = set()

    pos_instructions = 0
    while True:
        letter = instructions[pos_instructions]
        if letter == "+":
            registry[pos] = (registry[pos] + 1) % 256
        elif letter == "-":
            registry[pos] = (registry[pos] - 1) % 256
        elif letter == ">":
            pos += 1
            if pos >= tape_length:
                registry += [0]*tape_length
                tape_length = len(registry)
        elif letter == "<":
            pos -= 1
            if pos <= 0:
                registry = [0]*tape_length+registry
                tape_length = len(registry)
                pos += tape_length
        elif letter == "[":
            if registry[pos] == 0:
                nests = 1
                while nests:
                    pos_instructions += 1
                    if instructions[pos_instructions] == "[": nests += 1
                    elif instructions[pos_instructions] == "]": nests -= 1

                if jumpbacks == []:
                    reached_states.clear()

            else:
                jumpbacks.append(pos_instructions-1)

        elif letter == "]":
            stripped_registry = [str(x) for x in registry if x != 0]
            translated_pos = pos - (len(registry) - len(stripped_registry))
            state = (translated_pos, pos_instructions, ".".join(stripped_registry))
            if state in reached_states: return "Does not halt"
            elif len(reached_states) > LOOP_BOUND: return "Unknown"
            else:
                reached_states.add(state)
                pos_instructions = jumpbacks.pop()
        pos_instructions += 1
        if pos_instructions >= len(instructions): break
    return "Halts"

Giải pháp khá mạnh mẽ cho vấn đề: chỉ cần chạy mã bf. Chúng tôi giả sử chiều dài băng dài tùy ý và các ô riêng lẻ bọc ở 256. Vào cuối mỗi vòng lặp, chúng tôi lưu trữ trạng thái của băng với một bộ. Các trạng thái có dạng (vị trí của chúng tôi trên băng, vị trí của chúng tôi trên các hướng dẫn, băng trông như thế nào khi bị tước 0).

Nếu chúng ta lưu trữ cùng một trạng thái hai lần, thì chúng ta sẽ ở đâu đó trong một vòng lặp vô hạn, vì vậy chương trình không dừng lại. Nếu chúng tôi lưu trữ hơn 1.000 tiểu bang, sau đó cắt lỗ và trả lại không xác định. Khi chúng tôi rời khỏi một vòng lặp, chúng tôi sẽ kiểm tra xem liệu chúng tôi không có bất kỳ vòng lặp lớn hơn nào không. Nếu không, chúng ta sẽ không bao giờ thấy bất kỳ trạng thái nào trước đó nữa (ít nhất, vị trí hướng dẫn sẽ luôn khác nhau!) Để chúng ta có thể xóa tập hợp các trạng thái.

Điều này sẽ xác định chính xác bất kỳ chương trình BF nào mà các vòng lặp không dài hơn 1.000 lần lặp, cũng như nhiều chương trình lặp lại trạng thái trước 1.000 lần lặp trong một vòng lặp. Tuy nhiên, không phải tất cả trong số chúng: một cái gì đó như "{1 triệu + ở đây} [-]> + [+ -]" cuối cùng lặp lại một trạng thái, nhưng vòng lặp [-] vượt qua 1.000 lần lặp đầu tiên.

Vài ví dụ:

>+>->+>-

Không có vòng lặp, vì vậy nó đạt đến cuối và dừng lại.

+[+]

Vòng lặp kết thúc sau 256 lần lặp, do đó, nó kết thúc và dừng lại.

+[+-]

Cuối cùng lặp lại trạng thái (0,5, "1"), vì vậy nó không dừng lại.

+[->+]

Điều này không lặp lại bất kỳ trạng thái nào nhưng vòng lặp không bao giờ kết thúc, vì vậy nó sẽ in "không xác định". Nhưng các loại chương trình gian lận ở đây. Thay vì lưu trữ vị trí trên băng, nó thêm phần bù giữa sổ đăng ký gốc và bản bị tước. Nếu tất cả các vòng lặp thực hiện dịch băng theo một số khoảng trắng, thì nó sẽ tiếp tục dịch nó vô thời hạn (như tàu lượn cuộc sống), vì vậy chúng ta có thể nói nó không dừng lại.

+[>+]

Không dịch, không lặp lại bất kỳ trạng thái, in không rõ.

+++++++++++[-]

Điều này sẽ dừng lại, nhưng nó sẽ in "không xác định" nếu LOOP_BOUND là 10.

Có một vài cách để làm cho điều này thông minh hơn. Rõ ràng bạn có thể tăng LOOP_BOUND để giảm số lượng ẩn số. Bạn có thể xử lý thông minh hơn các vòng lặp lồng nhau. Bạn có thể có thể làm một cái gì đó lạ mắt với số BB và kích thước của các vòng lặp để phát hiện tốt hơn nếu có thứ gì đó nên dừng lại, nhưng tôi không đủ giỏi về CS cũng như Python để có thể làm điều đó.


2

GolfScript (23 ký tự, câu trả lời đúng vô hạn)

'[]'&!
# 0 if there are brackets, so Unknown
# 1 if there are no brackets, so no looping, so definitely halts
'UnknownHalts'7/=

1
Nói câu trả lời đúng vô hạn là không cần thiết, vì đó là một yêu cầu.
PyRulez

2
Lạm dụng quy tắc ... Lol
Isiah Meadows

1

Awk

Một phần mở rộng nhỏ trong sức mạnh từ hai ví dụ. Nếu một chương trình không có vòng lặp nào cả, do đó không có quyết định, rõ ràng nó vẫn được xác định để dừng lại. Vì chúng tôi giả định tính hợp lệ của chương trình, chúng tôi cũng cho rằng các dấu ngoặc là cân bằng và do đó chỉ cần tìm kiếm một hoặc một trong các dấu ngoặc.

BEGIN{RS=""}
!/\[/{print "Halts"; exit}
END{print "Unknown"}

Đối với lần thứ hai, nó phải kiểm tra trước nếu vòng lặp chạy hoàn toàn, vì vậy chúng ta phải mô phỏng mã đường thẳng trước vòng lặp. Sau đó, nếu vòng lặp trở về cùng một ô (tức là số >s bằng với số <s trong vòng lặp) và nó không thực hiện incs hoặc decs tại ô này (ví dụ: đối với bất kỳ tiền tố cân bằng vị trí nào của số dư thân vòng lặp, không có trường hợp nào +hoặc -trước ô tiếp theo <hoặc >sau đó ô không được sửa đổi). Thực hiện phần này có thể làm tôi mất nhiều thời gian hơn. Ôi, đợi đã, đối với phần đầu tiên của việc kiểm tra xem vòng lặp có chạy hay không, chúng ta có thể lấy ý tưởng tương tự này và tìm kiếm chương trình vòng lặp trước cho các hậu tố cân bằng và nhấn mạnh rằng có một +hoặc -(không cân bằng).


0

Haskell

Dưới đây là một câu trả lời thực sự đơn giản. Vui lòng đưa nó vào câu trả lời của bạn (vì bạn bao gồm nhiều bài kiểm tra trong một câu trả lời là một ý tưởng hay.)

main=do
    p<-getLine
    if take 3 p == "+[]"
        then putStr "Does not halt"
        else putStr "Unknown"

Về cơ bản nó nhìn thấy nếu có một vòng lặp trong đầu. Nếu vòng lặp chính xác đó không xảy ra lúc đầu, nó sẽ bỏ cuộc. Nó thậm chí không hoạt động ++[]. Nó giải quyết được vô số chương trình, và nó luôn luôn đúng khi giải quyết nó.

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.