Чи зупинена ця машина Foo?


43

Визначення того, чи зупиняється машина Тюрінга, невідомо, але це не обов’язково для простих машин.

Foo машина являє собою машину з кінцевої стрічкою, де кожна клітинка на стрічці має ціле число або символ HALT h, наприклад ,

2 h 1 -1

Покажчик інструкцій починається з вказівки на першу комірку:

2 h 1 -1
^

На кожному кроці вказівник інструкції рухається вперед на число, на яке вказує, а потім відміняє це число. Отже, після одного кроку, він переміститься вперед 2клітинками і перетвориться 2на -2:

-2 h 1 -1
     ^

Машина Foo продовжує робити це, поки покажчик інструкції не вказує на символ зупинки ( h). Отже, ось повне виконання цієї програми:

2 h 1 -1
^

-2 h 1 -1
     ^

-2 h -1 -1
         ^

-2 h -1 1
      ^

-2 h 1 1
   ^

Стрічка також кругла, тому якщо вказівник інструкції відсувається від однієї сторони стрічки, вона переходить на іншу сторону, наприклад:

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

Цікавою річчю цих машин Foo є те, що деякі не зупиняються, наприклад:

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

Ця програма буде тривати циклічно в цих останніх чотирьох штатах назавжди.

Отже, напишіть програму, яка визначає, зупиняється чи ні машина Foo! Ви можете використовувати будь-який (розумний) формат введення, який вам подобається для машин Foo, і ви можете використовувати 0як символ зупинки. Ви можете використовувати будь-які два різних виходи для випадку, коли він зупиняється, і для випадку, коли він не працює. Звичайно, Ваша програма повинна виводити відповідь за певну кількість часу на всі дійсні дані.

Це , тому постарайтеся зробити свою програму якомога коротшою!

Тестові справи

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
Просто я впевнений, щодо алгоритму вирішення цього питання. Я не з майстра алгоритму, тому я вважаю за краще питати, перш ніж піти в неправильному напрямку. Чи завжди машина Foo, що зупиняється, завжди повернеться до свого первинного стану? Або є "хаотично поведінки" машини без зупинки?
В. Куртуа

5
@ V.Courtois Усі машини Foo, що не зупиняються, опиняться в циклі станів, тому що існує лише кінцево багато можливих станів, в яких може знаходитися машина Foo (є n можливих місць, де може бути вказівник інструкції, і 2 ^ n можливо конфігурації стрічки). Кожна держава має один і єдиний "наступний стан". Отже, якщо машина Foo закінчиться в стані, в якому вона вже була, вона просто продовжуватиме циклічно. Оскільки існує лише кінцево багато штатів, він не може продовжувати хаотично стрибати між державами, оскільки в кінцевому підсумку перейде до того, у якому вже був.
Лев Тененбаум,

3
Пропонований тестовий випадок: 1 2 h 42(не зупиняється)
Арнольд

6
Схожий тест: 3 2 1 1 4 h. Це зупиняється, але вимагає більше ітерацій, ніж удвічі більше елементів.
Арнольд

10
Запропонований екстра довгий тест:, 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який зупиняється після 786430 кроків.
Магма

Відповіді:


11

C # (Visual C # Interactive Compiler) , 71 байт

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

Спробуйте в Інтернеті!

Я не знаю, чи є дійсним наступне, оскільки для цього потрібен спеціальний делегат з підписом unsafe delegate System.Action<int> D(int* a); та має бути загорнутий у unsafeблок для використання, але тут все одно:

C # (.NET Core) , 64 байти

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

Спробуйте в Інтернеті!

Ця функція бере int * і повертає дію; Іншими словами, це кривава функція. Єдина причина, по якій я використовую покажчики, - через codegolf.meta.stackexchange.com/a/13262/84206, який дозволяє мені зберігати байти, маючи вже змінну, яка вже визначена з довжиною масиву.

Збережено 9 байт завдяки @someone


Поповнив свій код двома байтами: tio.run/…
IQuick 143,

@ IQuick143 Приємний улов, спасибі
Втілення Незнання

Я не впевнений , якщо є якісь -то крайні випадки , для яких він не буде працювати, але не порушуючи будь-який з існуючих тестових випадків можна замінити 1<<fз , 2*fщоб зберегти байти.
Кевін Круїссен

1
77 байт із жахливою магією LINQ та виправленням Арнаульда . Я поняття не маю, як працює це рішення, тому я, можливо, його зламав.
хтось

1
63 байти за допомогою нормального 1-байтного гольфу та зміни IO на помилку / без помилки. Посилання на посилання
хтось

7

Python 3 , 63 89 байт

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

Спробуйте в Інтернеті!

Також працює для Python 2; байт можна зберегти в Python 2, замінивши return на друк і функцію print над stdout замість повернення. R повороти Trueдля зупинки іFalse для не зупинки.

Дякуємо @Neil та @Arnauld за те, що зауважив, що мені потрібно перевірити більше часу на зупинку. Дякуємо @Jitse, що вказав на проблему [2,0]. Завдяки @mypetlion за те, що зазначає, що абсолютна величина стрічки може перевищувати довжину стрічки.


5
Гаразд, я кусаю: як ти знаєш x+x, що достатньо?
Ніл

4
@Neil Це насправді недостатньо. Контрприклад - [ 3, 2, 1, 1, 4, 0 ]це зупинка більш ніж 12 ітерацій.
Арнольд

1
@Jitse len(x)*xне працював. Наприклад, [8,7,6,5,7,4,0,3,6]зупинки з більш ніж ітераціями. 92
Арнольд

2
Хіба 2**len(x)ще не вистачає максимуму? Я обчислюю кількість станів як n*(2**n)n=len(x)-1).
OOBalance

1
@OOBalance Я бачу, що ви маєте на увазі, оскільки кожен стан може мати вказівник у кожній клітині ... однак, я відчуваю, що є якась інша межа, застосована тим, що кожна клітина може лише перейти до двох інших комірок. В якості примітки: ніщо в виклик не говорить , що повинен бути стан зупинки на вході
Джо Кінг

6

Желе , 15 11 байт

N1¦ṙ⁸ḢƊÐLḢẸ

Спробуйте в Інтернеті!

Монадічне посилання, яке сприймає вхід як список цілих чисел, використовуючи 0 для позначення зупинки. Повертає 0 для зупинки входів і 1 для тих, хто не зупиняється.

Уникає питання про необхідність розробити кількість ітерацій через використання ÐL яких буде циклічно, поки не буде показано нового результату.

Дякуємо @JonathanAllan за збереження байта!

Пояснення

      ƊÐ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

Збережіть байт, обертаючись усіма записами, а потім просто зберігаючи перший результат:N1¦ṙ⁸ḢƊÐLḢẸ
Джонатан Аллан

5

Python 3 , 91 байт

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

Спробуйте в Інтернеті!

-40 байт завдяки JoKing та Jitse


@JoKing 109 байт , виконуючи призначення змінних у першому рядку.
Jitse

92 байти , змінивши перетворення кортежу на розширення зірочок, не починаючи з порожнього набору та перефразовуючи whileумову.
Jitse

@JoKing Чорт, я ніколи не вчуся: с. 93 байти тоді.
Jitse


@JoKing дякую!
HyperNeutrino

5

Perl 6 , 46 43 36 байт

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

Спробуйте в Інтернеті!

Представляє зупинку 0і повертає значення true, якщо машина зупиняється. Це повторює логічні 2**(length n)часи, коли, якщо вказівник опиниться на осередку зупинки, він залишається там, інакше буде на осередку, що не зупиняється. Це працює, тому що існують лише 2**nможливі стани (ігнорування осередків зупинки) для роботи машини Foo, оскільки кожна клітина, що не зупиняється, має лише два стани.Гаразд, так, є держави, ніж це, але через обмежений можливий перехід між покажчиками (і, отже, станами) буде менше 2 ** $ _ станів ... Я думаю

Пояснення

{                                  }  # 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
Стан машини Foo також включає розташування вказівника, а не лише знаків кожної комірки.
Магма

1
Ескіз доказу для машини Foo із стрічкою a_1 ... a_n 0. Розглянемо n-кубик знаків кожної комірки із спрямованими ребрами (= ітерація Foo) між вершинами (= станами), відвідування однієї вершини через будь-яку петлю ребер призведе до того, що IP буде в тому самому положенні, з якого він почав . Доведення: У циклі IP-адреса пересувається у кожному вимірі парним числом разів, тобто IP змінюється на k × (a_j + (-a_j))% n ≡ 0 для кожного виміру, отже, він завжди повертається у те саме положення, тільки коли-небудь бачити 1 стан із n станів для кожної вершини, тобто загальний макс 2 ^ n станів (= кількість вершин куба).
Kritixi Lithos

n2n.log(n)/n

3

05AB1E , 14 13 байт

goFć©(š®._}®_

Спробуйте в Інтернеті!

Приймає вхід як список цілих чисел з 0 як інструкцію зупинки. Повертає 1 для зупинки та 0 для не зупинки.

Дякуємо @KevinCruijssen за збереження 2 байтів!


О, приємно, так це робить твоя відповідь на желе! Велике використання обертання і ć! Я чекав пояснення, сподіваючись перемогти мою відповідь, але ти побив мене, ха-ха. ; Р -1 байт, роблячи те ж гольф , як моя відповідь , хоча: g·Fдо «v( Спробуйте його в Інтернеті. )
Кевін Cruijssen

І ще один -1, використовуючи ©®замість DŠs: «vć©(š®._}®_( Спробуйте це в Інтернеті. )
Кевін Круїйсен

Як зауважив Арнаулд у вашій відповіді Python, довжина петлі в два рази не є достатньою. Таким чином, ви можете змінити «vна goF.
Кевін Кройсейсен

@KevinCruijssen дякую
Нік Кеннеді

3

Java 8, 78 79 73 байт

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

Прямий порт відповіді @EmbodimentOfIgnorance 's C # .NET , тому не забудьте підтримати його!
Дякуємо @Arnauld за те, що знайшов дві помилки (що стосується також деяких інших відповідей).

Приводить до java.lang.ArithmeticException: / by zeroпомилки, коли вона може зупинитися, або немає помилки, якщо ні.

Спробуйте в Інтернеті.

Пояснення:

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
Цікаво, чи дозволено вам взяти цю довжину як додатковий аргумент? За замовчуванням для публікації вводу- виводу в мета не говориться так, і єдина причина, по якій моя друга відповідь займає тривалість, це тому, що вона бере в собі int*(від codegolf.meta.stackexchange.com/a/13262/84206 )
Втілення

@EmbodimentofIgnorance Ага, коли я побачив вашу відповідь, я припустив, що існує якесь мета-правило, яке дозволяє визначити довжину як додатковий ввід, але це стосується лише покажчиків. Дякую, що повідомив. Я видалив параметр довжини (але все ж використовую помилку / без помилки, щоб визначити результат).
Кевін Круїссен

3

Хаскелл , 79 байт

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

Спробуйте в Інтернеті!

Повернення Trueдля зупинок машин та Falseін. Введіть у вигляді списку із 0поданням стану зупинки.

Передбачає версію GHC більше 8,4 (випущена лютого 2018 року).


2

JavaScript (Node.js) , 71 67 байт

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

В основному те саме, що відповідь C # .NET @EmbodimentOfIgnorance

4 байт зберегти завдяки @Arnaud

Спробуйте в Інтернеті!

JavaScript (Node.js) , 61 байт

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

Ця версія використовується undefinedяк символ зупинки і кидає, TypeError: Cannot read property 'f' of undefinedколи машина зупиняється і тихо припиняється, коли машина не зупиняється.

Спробуйте в Інтернеті!


1

Скала , 156 байт

І все-таки гольфуючий ІМО, але я з цим зараз добре. Повернення 0для не зупиняючих Fooі 1для зупинок Foos. Приймає вхід у aякості Array[Int], тому hприймається як 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

Пробіг досить довгий (близько 4 секунд для всіх тестових випадків) через кілька перетворень, які я зробив у повному масиві, а також .deepстворення копій ... Але ви все одно можете спробувати це в Інтернеті.



1

Attache , 40 байт

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

Спробуйте в Інтернеті!

Пояснення

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

Це виконує одну ітерацію машини Foo; він заперечує перший член, потім обертає масив (оригінальним, не запереченим) першим елементом масиву.

Periodicбуде застосовувати цю функцію, поки не накопичується дублікат результату. Машина або зупиняється, або переходить у тривіальну нескінченну петлю. Якщо він зупиниться, перший елемент буде дорівнює 0. В іншому випадку він буде не нульовим.

&N- гофрований спосіб отримання першого елемента числового масиву. Потім, Notповертається trueза 0 (машини для зупинки) та falseдля чого-небудь іншого (машини, що не зупиняються).


1

Вугілля деревне , 28 байт

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

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Виводи з використанням бульового виводу за замовчуванням для вугілля "Charcoal", що відповідає -істині та нічого невірно. Пояснення:

≔⁰η

Ініціалізуйте вказівник інструкції.

FX²Lθ«

Цикла стільки разів, скільки є теоретично можливих станів.

§≔θ籧θη

Відкиньте значення вказівника інструкції.

≧⁻§θηη

Віднімайте нове значення з вказівника інструкції. Доступ до масиву деревного вугілля циклічний, тому це автоматично імітує кругову стрічку Фоо.

»¬§θη

В кінці циклу виведіть, чи зупинилась програма.



0

Pyth , 12 байт

!hu.<+_hGtGh

Тестовий набір!

Використовується прямий підхід. Рекурсуйте, поки ми не побачимо список двічі в однаковому стані. Для програм, які зупиняються, список з часом матиме провідне місце, 0оскільки там зупиняється рекурсія. Для програм, які не зупиняються, список не починатиметься з 0, а скоріше знаходиться в стані, з якого процес буде періодичним, і тому машина Foo не зупиниться.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.