Чи круглі стрічки захоплюючі?


32

Похідне Brainfuck

Давайте визначимо просту мову програмування Brainfuck . Він має двонаправлену стрічку комірок, і кожна комірка вміщує один біт. Усі біти спочатку 0. На стрічці є рухома голова, спочатку в положенні 0. Програма - це рядок над символами <>01!, виконаний зліва направо, з наступною семантикою:

  • < рухає головою на один крок вліво.
  • > рухає головою на один крок вправо.
  • 0 ставить 0 у поточній комірці.
  • 1 ставить 1 у поточну комірку.
  • ! перевертає поточну комірку.

Немає циклів, тому програма з n символів закінчується після рівно n кроків. Програма нудна, якщо всі комірки містять 0 в кінці виконання, і захоплююча, якщо є щонайменше одна. кругової.

Приклад програми

Розгляньте програму 1>>>!<<<<0>!>>>!. На нескінченній стрічці виконання відбувається наступним чином:

     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

Зрештою, всі комірки дорівнюють 0, тому ця програма нудна. Тепер запустимо ту саму програму на круговій стрічці довжиною 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

Цього разу є клітинка зі значенням 1, тому програма захоплююча! Ми бачимо, що нудна програма чи захоплююча залежить від розміру стрічки.

Завдання

Ваш вхід - це не порожній рядок, <>01!який представляє програму на наведеній вище мові програмування. Масив символів - це також прийнятний формат введення. Програма гарантовано буде нудною при запуску на нескінченній стрічці. Ваш вихід повинен бути переліком довжин стрічок, на яких програма захоплююча. Зауважте, що вам потрібно протестувати програму лише на стрічках, коротших за довжину програми.

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

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

> : []
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
Чи можемо ми вибрати будь-яких чітких і послідовних символів замість них <>01!?
Містер Xcoder

1
Чи прийнятний масив інструкцій?
Арнольд

@ Mr.Xcoder Ні, ви повинні використовувати ці точні символи.
Згарб

@Arnauld Масив символів досить близький до рядка, я дозволю це.
Згарб

Відповіді:


6

Haskell, 119 байт

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]

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

Функція #- інтерпретатор для однієї команди c. Вся програма pуправляє foldING #зі стартовою стрічкою в p. fвиконується pдля кожної стрічки і зберігає ті, де сума комірок становить щонайменше 1.


n<-[1..length p] ... 0<$[1..n]здається досить довгим, повинен бути коротший шлях.
німі

Я не бачу коротшого шляху. Я бачу проблему в тому, що вам насправді потрібне значення nяк результат, тож якщо ви побудували 0<$[1..n]інший спосіб (скажімо, з scanr(:)), вам потрібно буде взяти lengthйого. (Я також спробував використовувати 1(для заміни lengthз sum) або False(використовувати orдля тесту) замість 0, але він не вийшов коротше.)
Ørjan Йохансен

@ ØrjanJohansen: так, я спробував, n<-init$scanr(:)[]$0<$p ... nщо на 2 байти коротше, але він повертає список стартових стрічок замість їх довжини, наприклад [[0],[0,0,0]]. Зігнути трохи правила, так що стрічки можна побачити як одинарні номери, тому, можливо, це нормально.
німі

init$можна замінити, поставивши [0]як початковий список, але він все ще не став досить коротким. Я думаю, що унарний дозволений лише для мов без більш природного представлення числа .
Ørjan Johansen

4

Стакса , 56 54 43 38 35 байт CP437

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

42 байти при розпакуванні,

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

Запуск та налагодження в Інтернеті!

-2 байти за коментар від @recursive

Пояснення

Я буду використовувати версію з префіксом i(тобто i%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a), щоб пояснити, і я поясню, чому iможна видалити

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

Код запуску програми:

{|(}                                 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
Я додав тестовий випадок усіх цифр, щоб підтвердити ваш iчек.
Згарб

0]*можна замінити на z(. Крім того , якщо ви зміните рядок «<>!», То 0і 1дасть індекс -1, так що шлях ваш список блоку потрібно тільки 4 блоків, замість 5. Це буде працювати , так як 0і 1обробників ідентичні в будь-якому випадку.
рекурсивний

@recursive Добре прийнято.
Вейджун Чжоу




2

Червоний , 243 байти

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]]]

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

Досить багатослівне та прямолінійне виконання. 1-індексація Red не дозволяє мені зменшити кількість байтів, використовуючи модульну арифметику для циклічного циклу через кругові стрічки.

Безумовно

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

Сітківка , 121 байт

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

Спробуйте в Інтернеті! Пояснення:

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

Створіть масив стрічок кожної довжини до довжини програми введення.

{

Цикл, поки програма не буде використана.

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

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

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

Якщо це !тоді, перемкніть перший символ у кожному рядку.

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

Якщо це >або, <то поверніть лінію. (Легше, ніж рухати головою.)

)`¶¶.
¶¶

Видаліть інструкцію і закінчіть цикл.

G`1

Тримайте лише захоплюючі лінії.

%`.

Порахуйте довжину кожного рядка.


2

JavaScript (ES6), 126 118 байт

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

Приймає введення як масив 1-символьних рядків.

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):[]

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


Заміна з t.some(x=>x)?допомогою +t.join``?замість того, щоб перевірити масив в якості цифр (і 0 вказує на нульову все-стрічку), але 3 байта менше.
Шиеру Асакото

2

APL (Dyalog Unicode) , 79 64 54 байт ( SBCS Адама )

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

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

-15 завдяки Адаму (забув про монадію ).
-10 завдяки ngn .



@ Adám Гм, схоже, це не оптимально (наприклад, вам це не потрібно ). Я перегляну його і оновлю. :)
Ерік Аутгольфер

Але якщо ви виймете, вам знадобиться ;, ні?
Адам

@ Adám ні , навіщо ти?
Ерік Аутгольфер


1

MATL , 46 39 байт

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

Спробуйте в Інтернеті! Або перевірити всі тестові випадки .

Як це працює

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 байт

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

Спробуйте в Інтернеті! (неплоский результат)

Спробуйте в Інтернеті! (сплюснуто)

Через деякий час, що провів головою об стіну, я вирішив зробити Tradfn замість Dfn. Це результат. Розумніші люди, ніж я, можуть зіграти з цього виду.

Сюрприз, сюрприз, хто - то розумніші , ніж я зробив гольф рис з цього. Дякую Адаму за 114 байт.

Він сказав:

Зауважте, що це ваша точна програма, за винятком використання індексації замість внутрішньої: Ifs і згортання: For-loops to {_} ¨, надаючи лівий аргумент на заміну глобальному.

Функція передбачає ⎕IO←0.


Як?

(У цьому поясненні використовується версія "без вольфу" для полегшення читання)

⊂{                                   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
Зберегти один байт, роблячи t←l⍴0бути t←l⍴i←0, і видалення рядка над нею. Ви також можете зберегти інший, змінивши t[i|⍨≢t]←1-t[i|⍨≢t]на t[i|⍨≢t]←~t[i|⍨≢t].
Zacharý

2
@ Zacharý направо, а потім збережіть додаткові 112 байт . Точно той самий код, просто гольф трохи.
Адам

Так, це просто "трохи". Вам не потрібні s?
Zacharý

@ Zacharý Що з? Це негласна функція.
Адама

@ Zacharý Я вважав би це гарним Адамом, чи не так?
J. Sallé


0

C (стук) , 171 байт

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);}

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

Довелося використовувати clang, оскільки використання char*p,t[l=strlen(S)]в якості виразу ініціалізації чомусь змушує GCC думати, що я хочу заявити, strlenа не викликати його.

Досить прямо вперед: Запускає програму на кругових стрічках зменшення довжини, виводячи будь-яку довжину, в результаті якої 1 десь на стрічці.

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


Запропонуйте i=0,bzero(t,l)замість цього memset(t,i=0,l)і *p-62?t[i]=*p^33?*p-48:t[i]^1:(i=~i+l?i+1:0)замість нього*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1)
roofcat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.