Máy Foo này có dừng lại không?


43

Xác định xem một máy Turing tạm dừng có được biết là không thể giải quyết được không, nhưng điều đó không nhất thiết đúng với các máy đơn giản hơn.

Máy Foo là máy có băng từ hữu hạn, trong đó mỗi ô trên băng có số nguyên hoặc ký hiệu dừng h, ví dụ:

2 h 1 -1

Con trỏ lệnh bắt đầu bằng cách chỉ vào ô đầu tiên:

2 h 1 -1
^

Ở mỗi bước, con trỏ lệnh di chuyển về phía trước theo số mà nó trỏ tới, sau đó phủ định số đó. Vì vậy, sau một bước, nó sẽ di chuyển về phía trước 2các ô và biến 2thành -2:

-2 h 1 -1
     ^

Máy Foo tiếp tục làm điều này cho đến khi con trỏ lệnh trỏ đến biểu tượng tạm dừng ( h). Vì vậy, đây là thực hiện đầy đủ của chương trình này:

2 h 1 -1
^

-2 h 1 -1
     ^

-2 h -1 -1
         ^

-2 h -1 1
      ^

-2 h 1 1
   ^

Băng cũng là hình tròn, vì vậy nếu con trỏ lệnh di chuyển khỏi một mặt của băng, nó sẽ chuyển sang phía bên kia, ví dụ:

3 h 1 3
^
-3 h 1 3
       ^
-3 h 1 -3
     ^
-3 h -1 -3
         ^
-3 h -1 3
 ^
3 h -1 3
  ^

Một điều thú vị về các máy Foo này là một số không dừng lại, ví dụ:

1 2 h 2
^
-1 2 h 2
   ^
-1 -2 h 2
        ^
-1 -2 h -2
    ^
-1 2 h -2
        ^
-1 2 h 2
   ^

Chương trình này sẽ tiếp tục lặp trong bốn trạng thái cuối cùng mãi mãi.

Vì vậy, hãy viết một chương trình xác định xem máy Foo có dừng hay không! Bạn có thể sử dụng bất kỳ định dạng đầu vào (hợp lý) nào bạn thích cho các máy Foo và bạn có thể chọn sử dụng0 làm biểu tượng tạm dừng. Bạn có thể sử dụng bất kỳ hai đầu ra riêng biệt nào cho trường hợp nó dừng lại và trường hợp không có. Tất nhiên, chương trình của bạn phải đưa ra câu trả lời trong một khoảng thời gian hữu hạn cho tất cả các đầu vào hợp lệ.

Đây là , vì vậy hãy cố gắng làm cho chương trình của bạn ngắn nhất có thể!

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

2 h 1 -1
Halts
3 h 1 3
Halts
h
Halts
1 1 1 1 h
Halts
2 1 3 2 1 2 h
Halts
3 2 1 1 4 h
Halts
1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36
Halts

2 h
Does not halt
1 2 h 2
Does not halt
8 1 2 3 3 4 8 4 3 2 h
Does not halt
1 2 4 3 h 2 4 5 3
Does not halt
3 1 h 3 1 1
Does not halt
1 2 h 42
Does not halt

5
Chỉ để tôi chắc chắn, về thuật toán để giải quyết điều này. Tôi không phải là một bậc thầy về thuật toán nên tôi thích hỏi trước khi đi sai hướng. Một máy Foo không tạm dừng sẽ luôn trở lại trạng thái ban đầu chính xác của nó? Hoặc có những cỗ máy không dừng "hỗn loạn"?
V. Courtois

5
@ V.Courtois Tất cả các máy Foo không tạm dừng sẽ kết thúc trong một vòng các trạng thái, bởi vì chỉ có nhiều trạng thái có thể có của một máy Foo (có thể có thể đặt con trỏ lệnh và 2 ^ n cấu hình băng). Mỗi tiểu bang có một và chỉ một "trạng thái tiếp theo". Vì vậy, nếu một máy Foo kết thúc ở trạng thái đã hoạt động, nó sẽ tiếp tục lặp. Bởi vì chỉ có nhiều tiểu bang, nên nó không thể nhảy lộn xộn giữa các tiểu bang vì cuối cùng nó sẽ đến một nơi mà nó đã ở.
Leo Tenenbaum

3
Trường hợp thử nghiệm được đề xuất: 1 2 h 42(không dừng lại)
Arnauld

6
Trường hợp thử nghiệm đề xuất : 3 2 1 1 4 h. Điều này dừng lại nhưng yêu cầu số lần lặp nhiều hơn hai lần số phần tử.
Arnauld

10
Trường hợp thử nghiệm cực dài được đề xuất : 1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36, dừng lại sau 786430 bước.
Magma

Câu trả lời:


11

C # (Trình biên dịch tương tác Visual C #) , 71 byte

x=>{for(int i=0,k=0,f=x.Count;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;i/=x[k];}

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

Tôi không biết những điều sau đây có hợp lệ không, vì nó yêu cầu một đại biểu tùy chỉnh có chữ ký unsafe delegate System.Action<int> D(int* a); và phải được bọc trong một unsafekhối để sử dụng, nhưng đây là cách nào:

C # (.NET Core) , 64 byte

x=>f=>{for(int i=0,k=0;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;k/=x[k];}

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

Hàm này nhận một int * và trả về một Action; nói cách khác, nó là một chức năng curried. Lý do duy nhất tôi sử dụng con trỏ là vì codegolf.meta.stackexchange.com/a/13262/84206, cho phép tôi lưu byte bằng cách đã có một biến đã được xác định với độ dài của mảng.

Đã lưu 9 byte nhờ @someone



@ IQuick143 Bắt tốt, cảm ơn
Hiện thân của sự thiếu hiểu biết

Tôi không chắc chắn nếu có bất kỳ trường hợp cạnh mà nó sẽ không làm việc, nhưng mà không vi phạm bất kỳ trường hợp thử nghiệm hiện tại bạn có thể thay thế 1<<fvới 2*flưu một byte.
Kevin Cruijssen

1
77 byte với phép thuật LINQ khủng khiếp và bản sửa lỗi của Arnauld . Tôi không biết làm thế nào để giải pháp này hoạt động, vì vậy tôi có thể đã phá vỡ nó.
ai đó

1
63 byte thông qua một golf 1 byte thông thường và thay đổi IO thành lỗi / không có lỗi. Liên kết đến liên kết
ai đó

7

Python 3 , 63 89 byte

def f(x):
 for i in range(2**len(x)):a=x[0];x[0]=-a;b=a%len(x);x=x[b:]+x[:b]
 return a==0

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

Cũng hoạt động cho Python 2; một byte có thể được lưu trong Python 2 bằng cách thay thế return bằng print và có chức năng in thành stdout thay vì trả về. R quay lại Trueđể tạm dừng vàFalse không dừng lại.

Cảm ơn @Neil và @Arnauld vì đã lưu ý rằng tôi cần kiểm tra lâu hơn để tạm dừng. Cảm ơn @Jitse đã chỉ ra một vấn đề với [2,0]. Cảm ơn @mypetlion đã lưu ý rằng giá trị tuyệt đối của các giá trị băng có thể vượt quá độ dài băng.


5
OK, tôi sẽ cắn: làm thế nào để bạn biết x+xlà đủ?
Neil

4
@Neil Nó thực sự không đủ. Một ví dụ ngược lại là [ 3, 2, 1, 1, 4, 0 ], nó dừng lại trong hơn 12 lần lặp.
Arnauld

1
len(x)*x[8,7,6,5,7,4,0,3,6]92

2
Vẫn không thiếu 2**len(x)một chút về mức tối đa? Tôi tính số lượng trạng thái là n*(2**n)(với n=len(x)-1).
OOBalance

1
@OOBalance Tôi hiểu ý của bạn, vì mỗi trạng thái có thể có một con trỏ trong mỗi ô ... tuy nhiên, tôi cảm thấy thích có một giới hạn khác được áp dụng bởi thực tế là mỗi ô chỉ có thể chuyển sang hai ô khác. Là một mặt lưu ý: không có gì trong những thách thức nói rằng là một trạng thái ngập ngừng trong đầu vào
Jo Vua

6

Thạch , 15 11 byte

N1¦ṙ⁸ḢƊÐLḢẸ

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

Một liên kết đơn âm lấy đầu vào làm danh sách các số nguyên sử dụng 0 để tạm dừng. Trả về 0 khi tạm dừng đầu vào và 1 cho những đầu vào không dừng lại.

Tránh vấn đề cần phải tính toán số lần lặp vì sử dụng ÐL sẽ lặp cho đến khi không thấy kết quả mới.

Cảm ơn @Jonathan ALLan vì đã tiết kiệm một byte!

Giải trình

      ƊÐL   | Loop the following as a monad until the result has been seen before:
N1¦         | - Negate the first element
   ṙ⁸       | - Rotate left by each of the elements
     Ḣ      | - Take just the result of rotating by the first element
         Ḣ  | Finally take the first element
          Ẹ | And check if non-zero

Lưu một byte bằng cách xoay theo tất cả các mục và sau đó chỉ giữ kết quả đầu tiên:N1¦ṙ⁸ḢƊÐLḢẸ
Jonathan Allan

5

Python 3 , 91 byte

def f(a):
	s={0,};i=0
	while{(*a,)}-s:s|={(*a,)};a[i]*=-1;i-=a[i];i%=len(a)
	return a[i]==0

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

-40 byte nhờ JoKing và Jitse


@JoKing 109 byte bằng cách thực hiện các phép gán biến trong dòng đầu tiên.
Jitse

92 byte bằng cách thay đổi chuyển đổi tuple sang mở rộng có gắn dấu sao, không bắt đầu bằng một tập hợp trống và định lại whileđiều kiện.
Jitse

@JoKing Chết tiệt, tôi không bao giờ học: p. 93 byte rồi.
Jitse


@JoKing cảm ơn!
HyperNeutrino

5

Perl 6 , 46 43 36 byte

{$_.=rotate(.[0]*=-1)xx 2**$_;!.[0]}

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

Đại diện dừng lại 0và trả về true nếu máy dừng. Điều này lặp lại logic2**(length n) thời gian , trong đó nếu con trỏ kết thúc trên ô tạm dừng, nó sẽ ở đó, nếu không nó sẽ nằm trên một ô không dừng. Điều này hoạt động vì chỉ 2**ncó các trạng thái có thể (bỏ qua các ô tạm dừng) cho máy Foo ở trong, vì mỗi ô không dừng chỉ có hai trạng thái.Được rồi, có nhiều trạng thái hơn thế, nhưng do sự chuyển đổi có thể có hạn giữa các con trỏ (và do đó là các trạng thái) sẽ có ít hơn 2 ** $ _ trạng thái ... Tôi nghĩ

Giải trình

{                                  }  # Anonymous codeblock
                     xx 2**$_         # Repeat 2**len(n) times
            .[0]*=-1                  # Negate the first element
 $_.=rotate(        )                 # Rotate the list by that value
                             ;!.[0]   # Return if the first element is 0

2
Trạng thái của máy Foo cũng bao gồm vị trí của con trỏ, không chỉ là dấu hiệu của từng ô.
Magma

1
Phác thảo bằng chứng cho máy Foo bằng băng a_1 ... a_n 0. Hãy xem xét một khối n của các dấu hiệu của mỗi ô có các cạnh được định hướng (= một lần lặp của Foo) giữa các đỉnh (= trạng thái), truy cập cùng một đỉnh qua bất kỳ vòng cạnh nào sẽ dẫn đến IP ở cùng vị trí mà nó bắt đầu . Chứng minh: Trong một vòng lặp, IP di chuyển theo từng chiều một số chẵn, tức là IP thay đổi theo k × (a_j + (-a_j))% n 0 cho mỗi thứ nguyên, do đó, nó luôn trở về cùng một vị trí, do đó, nó luôn trở về cùng một vị trí, chỉ nhìn thấy 1 trạng thái trong số n trạng thái cho mỗi đỉnh, tức là tổng tối đa là 2 ^ n trạng thái (= số đỉnh của khối lập phương).
Kritixi Lithos

viết sai rồi2viết sai rồi.tôiog(viết sai rồi)/viết sai rồi

3

05AB1E , 14 13 byte

goFć©(š®._}®_

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

Lấy đầu vào là một danh sách các số nguyên với 0 làm lệnh tạm dừng. Trả về 1 cho tạm dừng và 0 cho không dừng lại.

Cảm ơn @KevinCruijssen vì đã tiết kiệm 2 byte!


Ồ, thật tuyệt, đó là những gì Jelly trả lời của bạn! Công dụng tuyệt vời của xoay và ć! Tôi đang chờ đợi một lời giải thích với hy vọng đánh golf câu trả lời của tôi, nhưng bạn đã đánh bại tôi, haha. ; p -1 byte bằng cách chơi golf giống như câu trả lời của tôi: g·Fto «v( Thử trực tuyến. )
Kevin Cruijssen

Và thêm -1 bằng cách sử dụng ©®thay vì DŠs: «vć©(š®._}®_( Dùng thử trực tuyến. )
Kevin Cruijssen

Như Arnauld đã lưu ý về câu trả lời Python của bạn, việc lặp hai lần độ dài là không đủ. Vì vậy, bạn có thể thay đổi «vthành goF.
Kevin Cruijssen

@KevinCruijssen cảm ơn
Nick Kennedy

3

Java 8, 78 79 73 byte

a->{int k=0,l=a.length,i=0;for(;i++<1<<l;k%=l)k-=(a[k]*=-1)%l-l;k/=a[k];}

Cổng chuyển tiếp thẳng của câu trả lời C # .NET của @EmbodimentOfIgnorance , vì vậy hãy đảm bảo nâng cấp anh ấy!
Cảm ơn @Arnauld vì đã tìm thấy hai lỗi (cũng áp dụng cho một số câu trả lời khác).

Kết quả là một java.lang.ArithmeticException: / by zerolỗi khi nó có thể dừng lại, hoặc không có lỗi nếu không.

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

Giải trình:

a->{                   // Method with integer-array as parameter and no return-type
  int k=0,             //  Index integer, starting at 0
      l=a.length,      //  The length `l` of the input-array
  i=0;for(;i++<1<<l;   //  Loop 2^length amount of times:
          k%=l)        //    After every iteration: take mod `l` of `k`
    k-=                //   Decrease `k` by:
       (a[k]*=-1)      //    Negate the value at index `k` first
                 %l    //    Then take modulo `l` of this
                   -l; //    And then subtract `l` from it
                       //  (NOTE: the modulo `l` and minus `l` are used for wrapping
                       //  and/or converting negative indices to positive ones
  k/=a[k];}            //  After the loop: divide `k` by the `k`'th value,
                       //  which will result in an division by 0 error if are halting

2
Chỉ cần tự hỏi, bạn có được phép lấy độ dài làm đối số bổ sung không? Giá trị mặc định cho IO bài đăng trên meta không nói như vậy, và lý do duy nhất câu trả lời thứ hai của tôi phải mất một thời gian là bởi vì nó mất trong một int*(từ codegolf.meta.stackexchange.com/a/13262/84206 )
Embodiment of Ignorance

@EmbodimentofIgnorance Ah, khi tôi thấy câu trả lời của bạn, tôi cho rằng có một loại quy tắc meta cho phép độ dài được lấy làm đầu vào bổ sung, nhưng chỉ áp dụng cho con trỏ. Cảm ơn vì đã cho tôi biết. Tôi đã xóa tham số độ dài (nhưng vẫn sử dụng lỗi / không có lỗi để xác định kết quả).
Kevin Cruijssen

3

Haskell , 79 byte

s x|m<-length x,let g(n:p)=(drop<>take)(mod n m)(-n:p)=iterate g x!!(2^m)!!0==0

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

Trả về Truecho máy tạm dừng, và Falsenếu không. Đầu vào ở dạng danh sách, với 0biểu thị trạng thái tạm dừng.

Giả sử một phiên bản GHC lớn hơn 8.4 (phát hành tháng 2 năm 2018).


2

JavaScript (Node.js) , 71 67 byte

x=>{for(p=l=x.length,i=2**l;i--;)p+=l-(x[p%l]*=-1)%l;return!x[p%l]}

Về cơ bản giống như câu trả lời C # .NET của @EmbodimentOfIgnorance

Tiết kiệm 4 byte nhờ @Arnaud

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

JavaScript (Node.js) , 61 byte

x=>{for(p=l=x.length,i=2**l;i--;p+=l-(x[p%l]*=-1)%l)x[p%l].f}

Phiên bản này sử dụng undefined làm biểu tượng tạm dừng và ném TypeError: Cannot read property 'f' of undefinedkhi máy dừng lại và chấm dứt lặng lẽ khi máy không dừng lại.

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


1

Scala , 156 byte

Vẫn là IMO có thể chơi gôn, nhưng bây giờ tôi ổn với nó. Trả về s 0không dừng Foovà s 1dừng Foo. Đưa đầu vào vào anhư một Array[Int], vì vậy hđược lấy là 0.

var u=Seq[Array[Int]]()//Keep track of all states
var i=0//Index
while(u.forall(_.deep!=a.deep)){if(a(i)==0)return 1//Check if we are in a previously encountered step ; Halt
u:+=a.clone//Add current state in the tracker
var k=i//Stock temp index
i=(a(i)+i)%a.length//Move index to next step
if(i<0)i+=a.length//Modulus operator in Scala can return a negative value...
a(k)*=(-1)}//Change sign of last seen index
0//Returns 0 if we met a previous step

Nó khá dài để chạy (khoảng 4 giây cho tất cả các trường hợp thử nghiệm) vì nhiều lần tra cứu toàn bộ mảng tôi đã làm, cộng với việc .deeptạo các bản sao ... Nhưng bạn vẫn có thể thử trực tuyến.



1

Tùy viên , 40 byte

Not@&N@Periodic[{On[0,`-,_]&Rotate!_@0}]

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

Giải trình

{On[0,`-,_]&Rotate!_@0}

Điều này thực hiện một lần lặp duy nhất của máy Foo; nó phủ định thành viên đầu tiên, sau đó xoay mảng bằng phần tử đầu tiên (ban đầu, không phủ định) của mảng.

Periodicsẽ áp dụng chức năng này cho đến khi kết quả trùng lặp được tích lũy. Một cỗ máy dừng lại hoặc đi vào một vòng lặp vô hạn tầm thường. Nếu nó dừng lại, phần tử đầu tiên sẽ là 0. Nếu không, nó sẽ khác không.

&Nlà một cách chơi golf để có được phần tử đầu tiên của một mảng số. Sau đó, Nottrả về true0 (máy tạm dừng) và falsecho bất cứ thứ gì khác (máy không tạm dừng).


1

Than , 28 byte

≔⁰ηFX²L諧≔θ籧θη≧⁻§θη绬§θη

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Các đầu ra sử dụng đầu ra Boolean mặc định của Char than, là -đúng và không có gì là sai. Giải trình:

≔⁰η

Khởi tạo con trỏ lệnh.

FX²Lθ«

Vòng lặp nhiều lần như có trạng thái lý thuyết có thể.

§≔θ籧θη

Phủ định giá trị tại con trỏ lệnh.

≧⁻§θηη

Trừ giá trị mới từ con trỏ lệnh. Truy cập mảng của than là theo chu kỳ để điều này tự động mô phỏng băng tròn của Foo.

»¬§θη

Vào cuối vòng lặp, xuất ra liệu chương trình có dừng lại không.


0

Stax , 11 byte

Ç₧┬òE▐tµ|⌡1

Chạy và gỡ lỗi nó

Nó nhận đầu vào dưới dạng một mảng số nguyên, với 0 đại diện cho dừng lại.

Nó xuất ra 1để tạm dừng và 0cho một máy không dừng.


0

Bình thường , 12 byte

!hu.<+_hGtGh

Bộ thử nghiệm!

Sử dụng phương pháp tiếp cận thẳng. Lặp lại cho đến khi chúng ta thấy danh sách hai lần trong một trạng thái giống hệt nhau. Đối với các chương trình tạm dừng, danh sách cuối cùng sẽ dẫn đầu 0vì đó là nơi đệ quy dừng lại. Đối với các chương trình không dừng lại, danh sách sẽ không bắt đầu bằng 0, mà là ở trạng thái mà quá trình sẽ diễn ra theo định kỳ và do đó máy Foo sẽ không dừng lại.

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.