Створіть мову програмування, яка видається лише непридатною


85

Тут є нитка викликів грабіжників .

Завдання поліцейських: спроектуйте мову програмування, яка видається непридатною для програмування, але допускає обчислення (або принаймні виконання завдання) за допомогою якогось не очевидного механізму.

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

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

  • Точне пояснення семантики вашої мови
  • Написання читаного коду

Наступні тактики сильно не рекомендують:

  • Використання шифрування, хешей чи інших криптографічних методів. Якщо ви бачите мову, яка використовує шифрування RSA, або відмовляється виконувати програму, якщо її хеш SHA-3 не дорівнює 0x1936206392306, будь ласка, не соромтесь подати заявку.

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

Цей відносно простий. Для того, щоб зламати відповідь копа, потрібно створити програму, яка виконує завдання під час запуску в його інтерпретаторі. Коли ви зламаєте відповідь, опублікуйте коментар із написом "Зламаний" на відповідь поліцейського, який посилається на вашу публікацію. Хто зламає найбільше копів, той виграє нитку розбійників.

Правила вводу / виводу

  • Інтерпретатори повинні приймати ім'я файлу в командному рядку програми та використовувати стандартне введення та вихід під час його запуску.
  • Введення буде надано унітарно і складається лише з символів 0та 1(48 та 49 в ASCII). Число N кодується як N, 1s а за ним a 0. 0Перед закінченням файлу є додатковий . Приклад: Для послідовності (3, 3, 1, 14) вхід є 11101110101111111111111100.
  • Гарантовано, що вхід матиме не менше 3 цифр. Усі числа є натуральними числами.
  • Вихід буде оцінюватися за кількістю 1надрукованих s до зупинки програми. Інші символи ігноруються.

У наступних прикладах перший рядок - це вхід у десятковому форматі; другий - фактичний вхід програми; третій - вибірка вибірки.

1, 1, 3
101011100
1

15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u

247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>

Правила нудної відповіді на поліцейських:

  • Щоб запобігти безпеці через незрозумілість, перекладач повинен бути написаний мовою у першій 100 цього індексу TIOBE і мати вільно доступний компілятор / перекладач.
  • Перекладач не повинен тлумачити мову, опубліковану до цього виклику.
  • Перекладач повинен вписуватися у вашу посаду, а не розміщуватися зовні.
  • Перекладач повинен бути детермінованим
  • Перекладач повинен бути переносним і відповідати стандарту власної мови; не використовуйте невизначене поведінку або помилки
  • Якщо програма рішення занадто довга, щоб відповідати відповіді, ви повинні розмістити програму, яка її генерує.
  • Програма рішення повинна складатися лише з друкованих ASCII та нових рядків.
  • Ви повинні виконати свою програму рішення менше ніж за 1 годину на власному комп’ютері для кожного з наведених вище прикладів.
  • Програма повинна працювати для будь-яких цілих чисел, менших ніж 10 6 , і будь-якої кількості цілих чисел, менших ніж 10 6 (не обов'язково за годину), за умови, що загальна довжина вводу менше 10 9 .
  • Щоб стати безпечним, поліцейський повинен відредагувати програму рішення у відповідь через 8 днів.

Оцінка балів

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


Ви цього прямо не заявляєте, але я правий, якщо припустити, що поліцейський насправді повинен написати та розмістити перекладача у своїй відповіді?
Блакитний

@muddyfish Так, перекладач повинен містити відповідь поліцейського.
feersum

1
@ kirbyfan64sos Висновок буде оцінюватися по кількості одиниць, надрукованих до зупинки програми. Інші символи ігноруються.
mbomb007


20
Я обдурив себе цим викликом. Я створив мову програмування, а потім витратив години на програмування, щоб перевірити, чи могла вона навіть працювати лише для того, щоб дізнатися, що вона насправді була непридатною.
Санчіз

Відповіді:


24

Changeling (безпечно)

ShapeScript

ShapeScript - природна мова програмування. Перемикачі форми (або Changelings , як їх вважають за краще називати) можуть перетворитись у набір інструкцій, що дозволяє їм обробляти дані.

ShapeScript - мова на основі стека з відносно простим синтаксисом. Не дивно, що більшість його вбудованих програм стосуються зміни форми струн. Він інтерпретується, символом за символом, таким чином:

  • 'і "почати рядковий літерал.

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

  • 0щоб 9натиснути цілі числа 0 на 9 на стеку. Зауважте, що 10висуває два цілих числа.

  • ! вискакує рядок із стека і намагається оцінити його як ShapeScript.

  • ? спливає ціле число з стека і виштовхує копію елемента стека в цьому індексі.

    Індекс 0 відповідає найвищому елементу стека (LIFO), а індекс -1 - самому нижньому.

  • _ вискакує ітерабельний з стека і відсуває його довжину.

  • @ вискакує два предмети зі стека і штовхає їх у зворотному порядку.

  • $спливає дві струни зі стека і розбиває найнижчу частину, коли зустрічається сама верхня. Отриманий список висувається натомість.

  • &виводить рядок (верхній) та ітерабельний зі стека та приєднується до ітерабельного, використовуючи рядок як роздільник. Отриманий рядок висувається натомість.

  • Якщо ShapeScript використовується на нашій планеті, оскільки пітони є найближчими родичами Змінних на Землі, всі інші символи c вискакують із стека два елементи x та y (найвищі) та намагаються оцінити код Python x c y.

    Наприклад, послідовність символів 23+оцінювала б 2+3, тоді як послідовність символів "one"3*оцінювала б 'one'*3, а послідовність символів 1''Aоцінювала б 1A''.

    В останньому випадку, оскільки результат не є дійсним Python, Changeling скаржиться на те, що його поточна форма є нецільовою (синтаксична помилка), оскільки вона не є дійсною ShapeScript.

Перед виконанням коду інтерпретатор розмістить весь вхід користувача у вигляді рядка на стеку. Після виконання вихідного коду перекладач надрукує всі елементи на стеку. Якщо будь-яка частина між ними не вдається, зміна поскаржиться, що його поточна форма є неадекватною (помилка виконання).

Зміна форми

У своєму природному стані Зміни не приймають форми ShapeScript. Однак деякі з них можуть трансформуватися в один потенційний вихідний код (який не обов'язково корисний або навіть синтаксично допустимий).

Усі придатні зміни мають таку природну форму:

  • Усі рядки повинні мати однакову кількість символів.

  • Усі рядки повинні складатися з друкованих символів ASCII, а потім - один поданий рядком.

  • Кількість рядків має відповідати кількості символів для друку на рядок.

Наприклад, послідовність байтів ab\ncd\nє прийнятним Changeling.

У своїй спробі перейти на ShapeScript, Changeling зазнає такого перетворення:

  • Спочатку не існує вихідного коду.

  • Для кожного рядка відбувається таке:

    • Акумулятор Changeling встановлений на нуль.

    • Для кожного символу c рядка (включаючи кінцевий підводний рядок) кодова точка c є XORed з акумулятором, розділеним на 2, а символ Unicode, що відповідає отриманій кодовій точці, додається до вихідного коду.

      Після цього різниця між кодовою точкою c і кодовою точкою пробілу (32) додається до акумулятора.

Якщо будь-яка частина перерахованого вище не вдається, зміна поскаржиться, що її поточна форма неприємна.

Після обробки всіх рядків перетворення Changeling в (сподіваємось, дійсне) ShapeScript завершено, і отриманий код виконується.

Рішення (ShapeScript)

"0"@"0"$"0"2*&"0"@+0?_'@1?"0"$_8>"1"*+@1?"0"+$""&'*!#

ShapeScript насправді виявився досить придатним для використання; він навіть може провести тестування первинності ( доказ ) і тому задовольняє наше визначення мови програмування.

Я повторно опублікував ShapeScript на GitHub , з трохи зміненим синтаксисом та кращим введенням / виведенням.

Код робить наступне:

"0"@    Push "0" (A) and swap it with the input string (S).
"0"$    Split S at 0's.
"0"2*   Push "00".
&       Join the split S, using "00" as separator.
"0"@+   Prepend "0" to S.
        The input has been transformed into
        "0<run of 1's>000<run of 1's>0...0<run of 1's>0000".
0?_     Push a copy and compute its length (L).
'       Push a string that, when evaluated, does the following:
  @1?     Swap A on top of S, and push a copy of S.
  "0"$    Split the copy of S at 0's.
  _8>     Get the length of the resulting array and compare it with 8.
          If this returns True, there are more than eight chunks, so there are
          more then seven 0's. With two 0's surrounding each run of 1's and
          three extra 0's at the end, this means that there still are three or
          more runs of 1's in the string.
  "1"*    Push "1" if '>' returned True and "" if it returned False.
  +       Append "1" or "" to A.
  @1?     Swap S on top of A, and push a copy of A.
  "0"+    Append "0" to the copy of A.
  $       Split S at occurrences of A+"0".
  ""&     Flatten the resulting array of strings.
'       This removes all occurrences of "010" in the first iteration, all
        occurrences of "0110" in the second, etc., until there are less than
        three runs of 1's left in S. At this point, A is no longer updated,
        and the code inside the string becomes a noop.
*!      Repeat the code string L times and evaluate.
#       Drop S, leaving only A on the stack.

Рішення (зміна)

"1+-.......................
""B1.......................
"" 2)+7....................
"" 2)=<....................
""( $86=...................
""B8=......................
""247......................
""]`b......................
""B1.......................
""%D1=.....................
""%500=....................
""%&74?....................
""%&#.2....................
""%[bdG....................
""%D1=.....................
""%<5?.....................
""%:6>.....................
""%&65?....................
""%&-%7>...................
""%D1=.....................
""%500=....................
""%&74?....................
""%&,)5>...................
""%&%,79...................
"" )$?/=...................
""),-9=....................
""# !......................

Як і всі програми Changeling, цей код має зворотну передачу рядків.

ShapeScript буде помилятися негайно на будь-якому символі, це не зрозуміло, але ми можемо висунути довільні рядки як наповнювачі та вивести їх пізніше. Це дозволяє нам помістити лише невелику кількість коду в кожен рядок (на початку, де акумулятор невеликий) з подальшим відкриттям ". Якщо ми починаємо наступний рядок із "#, закриваємо і виводимо рядок, не впливаючи на фактичний код.

Крім того, ми повинні подолати три незначні перешкоди:

  • Довга рядок у коді ShapeScript - це один маркер, і ми не зможемо розмістити його на рядку.

    Ми висунемо цю струну шматками ( '@', '1?'і т. Д.), Які ми об'єднаємо пізніше.

  • Точка коду _досить висока, і натиснути '_'буде проблематично.

    Однак ми зможемо натиснути '_@'без особливих зусиль, після чого '@'слід відмінити інший .

Код ShapeScript, який створить наш Changeling, виглядає таким чином 1 :

"0""
"#@"
"#"0"$"
"#"0"2"
"#*&"0""
"#@+"
"#0?"
"#_@"
"#@"
"#'@'"
"#'1?'"
"#'"0'"
"#'"$'"
"#'_@'"
"#'@'"
"#'8'"
"#'>'"
"#'"1'"
"#'"*+'"
"#'@'"
"#'1?'"
"#'"0'"
"#'"+$'"
"#'""&'"
"#"+"77"
"#+*!*"
"#!#"

Я знайшов код Changeling, запустивши вищевказаний код ShapeScript через цей конвертер . 2

Перекладач (Python 3)

#!/usr/bin/env python3

import fileinput

def error(code):
  print("This shape is " + ["unpleasant", "unpurposed", "inadequate"][code - 1] + ".")
  exit(code)

def interpret(code):
  global stack
  stringing = 0
  for char in code:
    quote = (char == "'") + 2 * (char == '"')
    if quote or stringing:
      if not stringing:
        string = ""
        stringing = quote
      elif stringing == quote:
        stack.append(string)
        stringing = 0
      else:
        string += char
    elif char in "0123456789":
      stack.append(int(char))
    else:
      x = stack.pop()
      if char == '!':
        interpret(x)
      else:
        if char == '?':
          y = stack[~x]
        elif char == "_":
          y = len(x)
        else:
          y = stack.pop()
          if char == '@':
            stack.append(x)
          elif char == '$':
            y = y.split(x)
          elif char == '&':
            y = x.join(map(str, y))
          else:
            try:
              y = eval(repr(y) + char + repr(x))
            except SyntaxError:
              error(2)
        stack.append(y)

source = ""
lengths = []

for line in fileinput.input():
  if not line or sorted(line)[:2][-1] < " " or max(line) > "~":
    error(1)
  lengths.append(len(line))
  accumulator = 0
  for char in line:
    value = ord(char)
    try:
      source += chr(value ^ (accumulator >> 1))
    except:
      error(1)
    accumulator += value - 32

lengths.append(len(lengths) + 1)

if min(lengths) != max(lengths):
  error(1)

stack = ""

for line in fileinput.input("-"):
  stack += line

stack = [stack]

try:
  interpret(source)
except:
  error(3)

print("".join(map(str, stack)))

1 Кожен рядок залитий випадковим сміттям на кількість рядків, а канали ліній фактично відсутні.
2 Цифри внизу вказують на найнижчу та найвищу точку коду у коді Changeling, яка повинна знаходитись між 32 та 126.


1
-1 для використання xor / перетворень. Перехід на перетворення ShapeScript мені схоже на шифрування.
MegaTom

10
@MegaTom Ви можете голосувати так, як вважаєте за потрібне, але питання нахмурюються при шифруванні, оскільки він займає ключ , постійний, відомий лише поліцейському, який ставить розбійників у значну ваду. Перетворення - це нестримне перетворення.
Денніс

1
ShapeScript, 67 байт: 0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#. Я все-таки відмовився від пошуку зміни для цього. Навіть впереміш із здебільшого непотрібними твердженнями, я не зміг отримати більше 20 байт.
Прим

2
@MegaTom Я насправді досить розчарований даним рішенням. Я очікував щось значно розумніше, ніж 92,9% марний код.
примо

2
@primo Це зайняло трохи більше повороту, але я знайшов цю зміну, яка працює і з Python 2. Я не знаю, наскільки розумна моя відповідь, але мій план розміщення поліцейського з лазівкою, яку треба було знайти, щоб зламати, здається, спрацював.
Денніс

30

Перемішати (написано на C ++), тріщин! автор Мартін

Правка Мартіна тріснула. Щоб побачити його рішення, натисніть посилання. Моє рішення також додано.

Редагувати виправлену print-dкоманду, щоб мати можливість обробляти і регістри, і стеки. Оскільки це команда налагодження, яка не дозволена в рішенні, це не повинно впливати на тих, хто використовує попередню версію інтерпретатора

Я все ще нова в цьому, тому якщо в моїй відповіді чи моєму перекладачі щось не так, будь ласка, повідомте мене. Будь ласка, попросіть роз'яснення, якщо щось не зрозуміло.

Я не уявляю, що це буде надто жахливо, але, сподіваюся, це створить певну проблему. Що робить перетасування досить непридатним, це те, що він друкується лише тоді, коли речі знаходяться в належному місці.

-> Основи:

Є 24 стеки, ми їх називаємо stack1, ... stack24. Ці стеки живуть у списку. На початку будь-якої програми ці стеки мають нульовий показник, і вони починаються у належному місці, тобто стек i в i-й позиції у списку (Зверніть увагу, що ми будемо індексувати, починаючи з 1, на відміну від C ++). Під час програми програма змінить порядок стеків у списку. Це важливо з причин, які будуть пояснені, коли я обговорюю команди.

Для використання доступні 5 регістрів. Вони названі Alberto, Gertrude, Hans, Leopold, ShabbySam. Кожен із них встановлюється на нулі на початку програми.

Отже, на початку будь-якої програми є 24 стеки, кожен з яких має свій номер, що відповідає її індексу в списку стеків. Кожен стек має рівно один нуль зверху. Кожен з п'яти регістрів ініціалізується до нуля.

-> Команди та синтаксис :

Є 13 команд (+1 команда налагодження), які доступні в Shuffle. Вони такі

  • cinpushця команда не бере аргументів. Він чекає на введення командного рядка так, як це описано у питанні (інший вхід призведе до не визначених / невизначених результатів). Потім він розбиває вхідний рядок на цілі числа, наприклад101011100 -> 1,1,3. Для кожного отриманого входу воно виконує наступне: (1) перетворює список стеків на основі значення. Нехай ціле ціле значення називається a . Якщо a менше 10, це робить перестановку u . Якщо a становить від 9 до 30 (невключно), він робить перестановку d . Інакше він робить перестановку r . (2) Потім він штовхає aна стек, який є першим у списку. Зауважте, що я не маю на увазі stack1(хоча це може бути справа, яка stack1є першою у списку). Перестановки визначені нижче. Оскільки cinpushце єдиний спосіб отримати вклад користувача , він повинен з’являтися в будь-якому рішенні.
  • mov value register The movКоманда в основному присвоювання змінної. Він призначає valueна register. valueможе приймати декілька форм: це може бути (1) ціле число, наприклад 47 (2) назва іншого реєстру, наприклад Hans (3) індекс стека, за яким слідує 's', наприклад 4s. Зауважте, що це індекс у списку, а не номер стека. Таким чином, кількість не повинна перевищувати 24.

    Деякі movприклади:

    mov 4s Hans 
    mov Hans ShabbySam
    mov 9999 Gertrude
    
  • movfs index registerЦе означає «переміщення зі стека». Це схоже на movкоманду. Він існує, щоб ви могли отримати доступ до стека, індексованого реєстром. Наприклад, якщо раніше ви встановили Ганса рівним 4 ( mov 4 Hans), тоді ви можете використовувати movfs Hans Gertrudeдля встановлення Гертруди рівну вершині стека 4. Цей тип поведінки недоступний просто використанням mov.

  • inc register збільшує регістрове значення на 1.
  • dec register зменшує значення регістру на 1.
  • compg value value registerЦе означає «порівняти більше». Він встановлює регістр рівним більшому з двох значень. valueможе бути цілим числом, регістром або індексом стека, за яким слідує 's', як зазначено вище.
  • compl value value register "порівняти менше" те саме, що вище, за винятком того, що приймає менше значення.
  • gte value1 value2 registerПеревіряє, якщо value1 >= value2тоді ставиться булеве значення (як 1 або 0) register.
  • POP!! indexспливає верхню частину стека, індексовану indexу списку стеків.
  • jmp label безумовно стрибає на мітку label . Це хороший час, щоб поговорити про етикетки. Мітка - це слово, за яким слідує ':'. Інтерпретатор попередньо розбирає мітки, тож ви можете стрибати вперед як на мітки, так і назад.
  • jz value label стрибає на label якщо valueдорівнює нулю.
  • jnz value label стрибає на label якщо valueце не нульове значення.

    Приклади міток та стрибків:

    this_is_my_label:
         jmp this_is_my_label
    
    mov 10 Hans
    jnz Hans infinite_loop
    
    infinite_loop:
         jmp infinite_loop
    
  • "shuffle" permutationОсь команда перетасування. Це дозволяє перестановити список стеків. Є три дійсні перестановки, які можна використовувати як аргументи l,f , і b.

  • print registerЦе перевіряє, чи всі стеки у своїх початкових положеннях, тобто стек i знаходиться в індексі i у списку стеків. Якщо це так, воно друкує значення at registerуніар. В іншому випадку він друкує неприємну помилку. Як ти бачиш, щоб виводити що завгодно, всі стеки повинні бути в потрібних місцях.
  • done!це вказує програмі вийти без помилок. Якщо програма закінчується безdone! , вона видасть на консоль номер у верхній частині кожного стека, а потім номер стека. Порядок надрукування стеків - це порядок їх відображення у списку стеків. Якщо стек порожній, його буде опущено. Така поведінка призначена для налагодження і не може використовуватися в рішенні.
  • print-d valueце друкує значення заданого стека, регістру чи цілого числа (для доступу до стеку i , passis як аргумент, як пояснено вище). Це інструмент налагодження і не є частиною мови, тому він не дозволений у рішенні.

-> Ось код перекладача

Весь розбір відбувається в головній функції. Тут ви знайдете його для розбору конкретних команд.

#include<fstream>
#include<iostream>
#include<string>
#include<stack>
#include<cmath>

using namespace std;

class superStack: public stack<long> {
    private:
        int m_place;
    public:
        static int s_index;


        superStack() {
            m_place = s_index;
            s_index++;
        }

        int place() {
            return m_place;
        }
};
int superStack::s_index=1;

superStack  stack1,stack2,stack3,stack4,stack5,stack6,stack7,stack8,stack9,stack10,stack11, \
            stack12,stack13,stack14,stack15,stack16,stack17,stack18,stack19,stack20,stack21,stack22,stack23,stack24;


superStack* stackptrs[]=    { \
                        &stack1,&stack2,&stack3,&stack4,&stack5,&stack6,&stack7,&stack8,&stack9,&stack10,&stack11, \
                        &stack12,&stack13,&stack14,&stack15,&stack16,&stack17,&stack18,&stack19,&stack20,&stack21,&stack22,&stack23,&stack24 \
                        };


long Gertrude=0;
long Hans=0;
long Alberto=0;
long ShabbySam=0;
long Leopold=0;


void SWAP( int i, int j) {    // 0 < i,j < 25

    i--;
    j--;


    superStack* tempptr = stackptrs[i];
    stackptrs[i]=stackptrs[j];
    stackptrs[j] = tempptr;



}

void u() {
    int list[3][4] = {
                        {1,9,6,13},
                        {2,10,5,14},
                        {17,19,20,18},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void d() {
    int list[3][4] = {
                        {3,11,8,15},
                        {4,12,7,16},
                        {22,24,23,21},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void r() {
    int list[3][4] = {
                        {2,17,8,24},
                        {4,18,6,23},
                        {9,10,12,11},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void l() {
    int list[3][4] = {
                        {1,19,7,22},
                        {3,20,5,21},
                        {14,13,15,16},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void f() {
    int list[3][4] = {
                        {20,9,24,16},
                        {18,11,22,14},
                        {1,2,4,3},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void b() {
    int list[3][4] = {
                        {19,10,23,15},
                        {17,12,21,13},
                        {5,6,8,7},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}

void splitpush(string input) {
    long value=0;

    for(long i=0;i<input.size();i++) {

        if(input[i]=='1'){
            value++;
        }
        else if(input[i]=='0' && value!=0 ) {
            if(value<10) {
                u();
            }
            else if (value<30) {
                d();

            }
            else {
                r();
            }
            (*stackptrs[0]).push(value);
            value=0;

        }
        else {
            break;
        }

    }

}

long strToInt(string str) { // IF STRING HAS NON DIGITS, YOU WILL GET GARBAGE, BUT NO ERROR
    long j=str.size()-1;
    long value = 0;
    for(long i=0;i<str.size();i++) {
        long x = str[i]-48;

        value+=x*floor( pow(10,j) );
        j--;
    }
    return value;
}

bool isEmpty(superStack stk) {
    if( stk.size()>0){return false; }
    else {return true;}

}    

long getValue(string str) {
    if(str=="ShabbySam") {
        return ShabbySam;
    }
    else if(str=="Hans") {
        return Hans;
    }
    else if(str=="Gertrude") {
        return Gertrude;
    }
    else if(str=="Alberto") {
        return Alberto;
    }   
    else if(str=="Leopold") {
        return Leopold;
    }
    else if(str[ str.size()-1 ]=='s'){
        str.pop_back();

        long index = strToInt(str)-1;

        if( !isEmpty( (*stackptrs[index]) ) ) {
            return (*stackptrs[index]).top();
        }
        else {
            cerr<<"Bad Expression or Empty Stack";


        }   
    }
    else {
        return strToInt(str);
    }

}

void printUnary(long i) {
    while(i>0) {
        cout<<1;
        i--;
    }
}

int main(int argc, char**argv) {

    if(argc<2){std::cerr<<"No input file given"; return 1;}
    ifstream inf(argv[1]);
    if(!inf){std::cerr<<"File open failed";return 1;}

    for(int i=0;i<24;i++) { 
        (*stackptrs[i]).push(0);         // Pre push a zero on every stack
    }

    string labels[20];
    unsigned labelPoints[20];
    int index=0;



    string str;
    while(inf) { //  parse for labels
        inf>>str;
        //cout<<inf.tellg()<<" ";
        if(inf) {
            if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }

        }

    }
    inf.clear();
    inf.seekg(0,inf.beg);

    while(inf) { // parse for other commands 
        inf>>str;

        if(inf) {


            if(str=="cinpush") {
                string input;
                cin>>input;
                splitpush(input);
            }

            else if(str=="mov") {
                inf>>str;
                long value = getValue(str);

                inf>>str;
                if(str=="Gertrude"){Gertrude=value;}
                else if(str=="Hans"){Hans=value;}
                else if(str=="ShabbySam"){ShabbySam=value;}
                else if(str=="Alberto"){Alberto=value;}
                else if(str=="Leopold"){Leopold=value;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="movfs") {
                inf>>str;
                long index = getValue(str);
                if(!isEmpty( *stackptrs[index-1] )) {
                    inf>>str;
                    long value = (*stackptrs[index-1]).top();
                    if(str=="Gertrude"){Gertrude=value;}
                    else if(str=="Hans"){Hans=value;}
                    else if(str=="ShabbySam"){ShabbySam=value;}
                    else if(str=="Alberto"){Alberto=value;}
                    else if(str=="Leopold"){Leopold=value;}
                    else {cerr<<"Bad register name.";}
                }
                else {
                    cerr<<"Empty Stack";
                }



            }

            else if(str=="inc") {
                inf>>str;
                if(str=="Gertrude"){Gertrude++;}
                else if(str=="Hans"){Hans++;}
                else if(str=="ShabbySam"){ShabbySam++;}
                else if(str=="Alberto"){Alberto++;}
                else if(str=="Leopold"){Leopold++;}
                else {cerr<<"Bad register name. ";}
            }
            else if(str=="dec") {
                inf>>str;
                if(str=="Gertrude"){Gertrude--;}
                else if(str=="Hans"){Hans--;}
                else if(str=="ShabbySam"){ShabbySam--;}
                else if(str=="Alberto"){Alberto--;}
                else if(str=="Leopold"){Leopold--;}
                else {cerr<<"Bad register name. ";}
            }


            else if(str=="compg") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger;
                if(value1>value2){larger = value1;}
                else {larger = value2;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }
            else if(str=="compl") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger; //LARGER IS REALLY SMALLER HERE
                if(value1>value2){larger = value2;}
                else {larger = value1;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="gte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 >= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="lte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 <= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="POP!!") {
                inf>>str;
                long index = getValue(str);
                index--; //because we (C++ and this interpreter) index differently
                if(!isEmpty( *stackptrs[index] )) {
                    (*stackptrs[index]).pop();
                }
                else {cerr<<"Can't POP!! from empty stack";}

            }

            else if(str=="push"){cerr<<" You can't. ";}

            /*
            else if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }*/

            else if(str=="jmp") {
                inf>>str;
                for(int i=0;i<index;i++) {
                    if( labels[i]==str) {
                        inf.seekg( labelPoints[i], ios::beg);
                    }
                }
            }
            else if(str=="jz") {
                inf>>str;
                long value = getValue(str);

                if(value==0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str=="jnz") {
                inf>>str;
                long value = getValue(str);

                if(value!=0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str== "\"shuffle\"") {
                inf>>str;
                if(str=="l"){ l(); }
                else if(str=="f"){ f(); }
                else if(str=="b"){ b(); }
                else {cerr<<"Bad shuffle parameter";}

            }

            else if(str=="print") {

                for(int i=0;i<24;i++) {

                    if( (i+1) != (*stackptrs[i]).place() ) {
                        cerr<< "Sorry, your stacks are in the wrong place! You can't print unless you put them back! Exiting. ";
                        return 1;
                    }

                }
                inf>>str;
                if(str=="Gertrude"){printUnary(Gertrude);}
                else if(str=="Hans"){printUnary(Hans);}
                else if(str=="ShabbySam"){printUnary(ShabbySam);}
                else if(str=="Alberto"){printUnary(Alberto);}
                else if(str=="Leopold"){printUnary(Leopold);}
                else {cerr<<"Bad register name. ";}


            }

            else if(str=="done!") {return 0;}

            else if(str=="print-d" ){
                inf>>str;
                long value = getValue(str);
                cout<<str;
              }
        }

    }







    /*for(int i=1;i<25;i++) {
        (*(stackptrs[i-1])).push(i);
    }

    u();d();r();l();f();b();
    */

    cout<<"\n";
    for(int i=1;i<25;i++) {
        if( (*(stackptrs[i-1])).size()>0 ) {
            cout<<(*(stackptrs[i-1])).top()<<" "<<(*(stackptrs[i-1])).place()<<"\n";
            (*(stackptrs[i-1])).pop();
        }
    }
    /*
    for (int i=0;i<index;i++) {
        cout<<labels[i]<<": "<<labelPoints[i]<<"\n";
    }*/

    return 1;
}

-> Перестановки Перестановки перестановляють елементи списку стеків наступним чином:

Де означає

(Вони також відображаються в коді перекладача. Якщо є розбіжність, перекладач правильний.)

-> Простий приклад

Ці дві прості програми друкують числа від 24 до 1 (одинаково) без пробілів.

mov 24 Hans
start:
    print Hans
    dec Hans
    jnz Hans start
done!

або

mov 24 Hans start: print Hans dec Hans jnz Hans start done!

Вони ж програми.

Пояснення та рішення:

Мартін має гарне пояснення в своєму відповіді .

Як зрозумів Мартін, цю мову надихнув кишеньковий куб (він же 2х2 куб Рубіка). 24 стеки - це як 24 окремих квадрата на кубі. Перестановки - це основні дозволені рухи: вгору, вниз, вправо, вліво, спереду, назад.

Основна боротьба тут полягає в тому, що при натисканні значень використовуються лише три рухи: вгору, вниз і вправо. Однак у вас немає доступу до цих ходів, коли "перетасовуєте" стеки. У вас є лише інші три ходи.

Як виявляється, обидва набори з трьох ходів насправді охоплюють всю групу (тобто є генераторами), тому проблема вирішується. Це означає, що ви можете вирішити будь-який куб 2х2 Рубіка лише за допомогою 3 ходів.

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

Після скасування перестановок пошук третього за величиною числа є досить тривіальним.

cinpush
main:
    mov 1s ShabbySam
    POP!! 1
    jmp compare
    continue:
        gte 0 ShabbySam Leopold
        jnz Leopold end
        gte ShabbySam 9 Leopold
        jz Leopold uinverse
        gte ShabbySam 29 Leopold
        jz Leopold dinverse
        jnz Leopold rinverse
compare:
    gte ShabbySam Alberto Leopold
    jz Leopold skip
    mov Gertrude Hans
    mov Alberto Gertrude
    mov ShabbySam Alberto
    jmp continue
    skip:
        gte ShabbySam Gertrude Leopold
        jz Leopold skip_2
        mov Gertrude Hans
        mov ShabbySam Gertrude
        jmp continue
    skip_2:
        gte ShabbySam Hans Leopold
        jz Leopold continue
        mov ShabbySam Hans
        jmp continue
uinverse: 
    "shuffle" f
    "shuffle" f
    "shuffle" f
    "shuffle" l
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" f
    jmp main
dinverse:
    "shuffle" f
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" f
    "shuffle" f
    "shuffle" f
    jmp main
rinverse: 
    "shuffle" b "shuffle" l "shuffle" f "shuffle" l "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f "shuffle" b
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" b "shuffle" b "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" l "shuffle" l "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    jmp main
end:
    print Hans
    done!

2
Тріснув. :) Я дуже вражена мовою!
Мартін Ендер

Нічого собі, це було швидше, ніж я очікував. Дякую, я радий, що було так весело розібратися, як і писати.
Ліам

Мені цікаво, чи було б пристойно важче, якби я змінив назви перестановок на щось менш очевидно про кубики Рубіка?
Ліам

Вони були виразно ключ, але я думаю , що це не зайняло б , що набагато більше , якби вони мали різні імена.
Мартін Ендер

Гей, схоже, що GAP не був особливо розумним щодо зміни трьох вхідних перестановок. ;)
Мартін Ендер

22

Брайан і Чак , потріскані cardboard_box

Мене вже деякий час заінтригує ідея мови програмування, де дві програми взаємодіють між собою (напевно, натхненний ROCB ). Цей виклик був приємним стимулом вирішити цю концепцію нарешті, намагаючись якомога менше зберегти мову. Цілі дизайну полягали в тому, щоб зробити мову Тюрінга завершеною, хоча кожна її частина окремо не є Тюрінг-повною. Крім того, навіть обидва разом не повинні бути повною Тьюрінгом без використання маніпуляцій із вихідним кодом. Я думаю мені це вдалося, але офіційно я ще нічого не підтвердив. Тож без зайвої прихильності я представляю тобі ...

Головні герої

Брайан і Чак - дві програми, схожі на Brainfuck. Лише одна з них виконується в будь-який момент, починаючи з Брайана. Зрозуміло, що стрічка пам'яті Брайана також є вихідним кодом Чака. І стрічка пам'яті Чака - це також вихідний код Брайана. Крім того, головка стрічки Брайана є також вказівкою Чака і навпаки. Стрічки є напівнескінченними (тобто нескінченними праворуч) і можуть містити підписані цілі числа довільної точності, ініціалізовані до нуля (якщо іншим кодом не визначено інше).

Оскільки вихідний код також є стрічкою пам'яті, команди технічно визначаються цілими значеннями, але вони відповідають розумним символам. Існують такі команди:

  • , (44 ): Прочитайте байт зі STDIN в поточну комірку пам'яті. Тільки Брайан може це зробити. Ця команда не є опціоном для Чака.
  • . (46 ): Запишіть поточну комірку пам'яті, модуль 256, як байт в STDOUT. Тільки Чак може це зробити. Ця команда для Брайана не працює.
  • + (43 ): Збільшення поточної комірки пам'яті.
  • - (45 ): Зменшення поточної комірки пам'яті.
  • ?( 63): Якщо поточна комірка пам’яті дорівнює нулю, це не працює. В іншому випадку передайте контроль іншій програмі. Головка стрічки в програмі, яка використовує? , залишиться на ?. Голова стрічки іншої програми перемістить одну клітинку праворуч перед виконанням першої команди (тому комірка, яка використовується як тест, не виконується сама).
  • < (60 ): Перемістіть стрічку на одну клітинку ліворуч. Це неможливо, якщо головка стрічки вже знаходиться в лівому кінці стрічки.
  • > (62 ): Перемістіть головку стрічки на одну клітинку праворуч.
  • { (123 ): Неодноразово переміщуйте головку стрічки вліво, поки або поточна комірка не дорівнює нулю або не буде досягнуто лівого кінця стрічки.
  • }( 125): Неодноразово переміщуйте головку стрічки вправо, поки поточна комірка не дорівнює нулю.

Програма припиняється, коли покажчик інструкцій активної програми досягає точки, де більше немає інструкцій праворуч.

Вихідний код

Вихідний файл обробляється так:

  • Якщо файл містить рядок ``` , він буде розділений на дві частини навколо першого появи цього рядка. Всі провідні та кінцеві пробіли позбавлені, і перша частина використовується як вихідний код Брайана, а друга частина для Чака.
  • Якщо файл не містить цього рядка, перший рядок файлу буде використаний як джерело для Брайана, а другий - для Чака (крім розмежувального нового рядка, пробіл не буде видалений).
  • Усі входження _в обох програмах замінюються байтами NULL.
  • Дві стрічки пам'яті ініціалізуються кодами символів, що відповідають отриманому рядку.

Як приклад, наступний вихідний файл

  abc
```
0_1
23

Випускаються такі початкові стрічки:

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

Перекладач

Перекладач написаний на Рубі. Він потребує двох прапорів командного рядка, які не повинні використовуватися жодним рішенням (оскільки вони не є частиною фактичної специфікації мови):

  • -d: З цим прапором Брайан і Чак розуміють ще дві команди. !буде надруковано рядкове представлення обох стрічок пам'яті, активна програма буде вказана першою (a ^позначатиме поточні головки стрічки). @також зробить це, але потім негайно припиніть програму. Оскільки я лінивий, жоден з цих не працює, якщо це остання команда в програмі, тому, якщо ви хочете їх використовувати там, повторіть їх або напишіть після них неоперативний варіант.
  • -D: Це багатослівний режим налагодження. Він надрукує таку саму інформацію про налагодження, що і !після кожної галочки. @також працює в цьому режимі.

Ось код:

# coding: utf-8

class Instance
    attr_accessor :tape, :code, :ip

    OPERATORS = {
        '+'.ord  => :inc,
        '-'.ord  => :dec,
        '>'.ord  => :right,
        '<'.ord  => :left,
        '}'.ord  => :scan_right,
        '{'.ord  => :scan_left,
        '?'.ord  => :toggle,
        ','.ord  => :input,
        '.'.ord  => :output,
        '!'.ord  => :debug,
        '@'.ord  => :debug_terminate
    }

    OPERATORS.default = :nop

    def initialize(src)
        @code = src.chars.map(&:ord)
        @code = [0] if code.empty?

        @ip = 0
    end

    def tick
        result = :continue
        case OPERATORS[@code[@ip]]
        when :inc
            @tape.set(@tape.get + 1)
        when :dec
            @tape.set(@tape.get - 1)
        when :right
            @tape.move_right
        when :left
            @tape.move_left
        when :scan_right
            @tape.move_right while @tape.get != 0
        when :scan_left
            @tape.move_left while @tape.ip > 0 && @tape.get != 0
        when :toggle
            if @tape.get != 0
                @tape.move_right
                result = :toggle
            end
        when :input
            input
        when :output
            output
        when :debug
            result = :debug
        when :debug_terminate
            result = :debug_terminate
        end

        return :terminate if result != :toggle && @ip == @code.size - 1

        move_right if result != :toggle

        return result
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_left
        @ip -= 1 if @ip > 0
    end

    def get
        @code[@ip]
    end

    def set value
        @code[@ip] = value
    end

    def input() end
    def output() end

    def to_s
        str = self.class.name + ": \n"
        ip = @ip
        @code.map{|i|(i%256).chr}.join.lines.map do |l|
            str << l.chomp << $/
            str << ' '*ip << "^\n" if 0 <= ip && ip < l.size
            ip -= l.size
        end
        str
    end
end

class Brian < Instance
    def input
        byte = STDIN.read(1)
        @tape.set(byte ? byte.ord : -1)
    end
end

class Chuck < Instance
    def output
        $> << (@tape.get % 256).chr
    end
end

class BrianChuck

    class ProgramError < Exception; end

    def self.run(src, debug_level=0)
        new(src, debug_level).run
    end

    def initialize(src, debug_level=false)
        @debug_level = debug_level

        src.gsub!('_',"\0")

        if src[/```/]
            brian, chuck = src.split('```', 2).map(&:strip)
        else
            brian, chuck = src.lines.map(&:chomp)
        end

        chuck ||= ""

        brian = Brian.new(brian)
        chuck = Chuck.new(chuck)

        brian.tape = chuck
        chuck.tape = brian

        @instances = [brian, chuck]
    end

    def run
        (puts @instances; puts) if @debug_level > 1

        loop do
            result = current.tick

            toggle if result == :toggle

            (puts @instances; puts) if @debug_level > 1 || @debug_level > 0 && (result == :debug || result == :debug_terminate)

            break if result == :terminate || @debug_level > 0 && result == :debug_terminate
        end
    end

    private

    def current
        @instances[0]
    end

    def toggle
        @instances.reverse!
    end
end

case ARGV[0]
when "-d"
    debug_level = 1
when "-D"
    debug_level = 2
else
    debug_level = 0
end

if debug_level > 0
    ARGV.shift
end

BrianChuck.run(ARGF.read, debug_level)

Ось власне (рукописне) рішення проблеми:

>}>}>
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>} Append a bunch of 1s as a dummy list element:
+>+>+>+>+>+>+>+>+>+
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
{<<<<<<<<<{<{    Move back to the start
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}<<<<<<- Subtract 1 from the result to account for initial 1
?   If integer was positive switch to Chuck
@todo: process end
_
This code is run when reading 1:
}>}>>>>>>>>>}<<<<<<+ Move to the end of Chuck; skip one null cell; move to the end of the list
{<<<<<<<<<{<?   Move back to the code that resets this loop.
_
This code is run after finalising an integer:
change the code after the integer first
<<--<--<--}
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: +
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<<<+<<{<{    Move back to the start; incrementing the list length
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}
Leave the resetting code, but remove the rest of the last list element:
<<<--<--<--
1: <-
question mk: <---------------------------------------------------------------
arrow left: <------------------------------------------------------------
brace right: <-----------------------------------------------------------------------------------------------------------------------------
1: <-
<{< Move back to the cell we reserved for the counter
<<<<<<-- decrement list size by two so we don't process the two largest elements
_

<{<<<<<<{<{<{<{<{>}>}>>>>>>> This is the beginning of the loop which decrements all list elements by 1
+ Add 1 to the running total
>>- Set marker of dummy list element to zero
_ Beginning of loop that is run for each list element
<{<<<<<<{<{<{<{<{>}>}>}>}+ set last marker back to 1
>>>>>>>>>> move to next marker
? Skip the next bit if we're not at the end of the list
<? Move back to the beginning of the loop
@ we should never get here
_
This is run when we're not at the end of the list
<<<- Set marker to 0 to remember current position
>>>>- Move to the current value and decrement it
? Move back to loop beginning if value is not zero yet
- Make element negative so it's skipped in the future
{<{<{>- Move to remaining list length and decrement it
? If it's nonzero switch to Chuck
>>>>>>>>->->->->->->->->->- Remove the dummy list to make some space for new code:
>}+ Fill in the marker in the list
{<<<<<<<<< Add some loop resetting code after the result:
brace left: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
This loop adds a print command to Chuck's code while decrementing the result
>>>>>>>>}>>>>>}>>>>>} Move to the very end of Chuck's code and leave some space to seek the 1
print: ++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<{<<<<<{<<<<<<<{<
- decrement the result
? if nonzero run loop again
At this point we just need to make Chuck seek for the 1 at the end of this code print it often enough
>>}>>>>>>>}>>>>>}
arrow right: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<?1 Switch to Chuck which moves Brian's tape head onto the 1 and then prints it N times


```

_   Dummy cell to hold input
This code is run when reading a 1:
{<{<{<{ ensure we're at the start
}>}<? Skip 0 handling code and switch to Brian
_ This code is run after a 1 has been processed:
{<{<?

Цей код є працездатним , як є, тому що все анотації використовують не-OPS і пропускаються {і }.

Основна ідея:

  1. Додайте до списку новий нульовий елемент (наприкінці стрічки Чака) та збільште довжину списку на 1.
  2. Поки ми читаємо 1s, збільшуємо цей елемент.
  3. Коли ми читаємо а 0 , зробіть чистку. Якщо отримане ціле число було більше нуля, поверніться до 1.

    Тепер у нас є список вхідних чисел в кінці стрічки Чака, і ми знаємо довжину списку.

  4. Віднімаємо 2 від довжини списку (тому наступні кроки ігнорують два найбільші елементи), називаємо це N.

  5. У той час N > 0, збільшуйте загальний обсяг, а потім зменшуйте всі елементи списку. Щоразу, коли елемент списку не дорівнює нулю, зменшенняN .

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

  6. Напишіть Mкопії .до кінця стрічки Чака.

  7. На Чак знайдіть 1стрічку Брайана та виконайте створені .в кінці.

Закінчивши це, я зрозумів, що в деяких місцях можу це досить спростити. Наприклад, замість того, щоб відслідковувати цей лічильник і записувати .його на стрічку Чака, я міг просто надрукувати 1відразу, кожен раз, перш ніж декрементувати всі елементи списку. Однак внесення змін до цього коду є досить болючим, оскільки він розповсюджує інші зміни всюди, тому я не переймався внесенням змін.

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

Наступна проблема полягає в тому, що нам потрібно залишити список декрементом, Nпоки ми його обробляємо, і нам потрібно повернутися до того самого місця, де було раніше. Але {і }просто пропустив би повз весь список.

Тому нам потрібно динамічно записати якийсь код на Чак. Фактично, кожен елемент списку iмає форму:

[1 <Code A> i <Code B>]

1це маркер, який ми можемо встановити на нуль, щоб вказати, де ми зупинили обробку списку. Її мета - зловити {або }який просто перейде через код і i. Ми також використовуємо це значення, щоб перевірити, чи знаходимося ми в кінці списку під час обробки, тому, поки ми цього не робимо, це буде, 1і умовне ?переключить управління на Чак.Code Aвикористовується для вирішення такої ситуації та відповідно переміщення ІС на Брайана.

Тепер, коли ми декрементуємо, iнам потрібно перевірити, чи iвже дорівнює нулю. Поки це не ?буде, знову перемикатиметься управлінням, тому Code Bє , щоб це впоратися.



@cardboard_box Приємно!
mbomb007

15

HPR, написана на Python 3 ( Розтріскано TheNumberOne )

HPR (назва нічого не означає) - це мова для обробки списків цілих чисел. Він розроблений так, щоб він був мінімалістичним , надзвичайно обмеженим і не мав «штучних» обмежень . Програмування в HPR болісно не тому, що вам потрібно розгадати загадку, щоб перекладач не кричав на вас, а тому, що важко змусити програму зробити щось корисне. Я не знаю, чи здатна HPR до чогось істотно цікавішого, ніж обчислення третього за величиною елемента списку.

Специфікація мови

Програма HPR запускається в середовищі , що представляє собою не упорядкований набір без дублікатів безвід'ємних цілих чисел та списків негативних цілих чисел. Спочатку середовище містить лише список вхідних даних (перекладач аналізує його для вас). Існують три команди та два оператори "управління потоком", які змінюють середовище:

  • *видаляє перший елемент кожного непустого списку в оточенні та розміщує його в оточенні. Порожні списки не впливають. Наприклад, вона перетворює

    {4,1,[0,2],[1,3],[]} -> {4,1,0,[2],[3],[]}
    
  • -зменшує всі числа в оточенні, а потім видаляє негативні елементи. Наприклад, вона перетворює

    {4,2,0,[0,2],[4,4,4]} -> {3,1,[0,2],[4,4,4]}
    
  • $обертає кожен список у оточенні на один крок вліво Наприклад, вона перетворює

    {4,1,[0,2],[3,4,1]} -> {4,1,[2,0],[4,1,3]}
    
  • !(A)(B), де AіB є програми, в основному це whileцикл. Він виконує "дію", Aпоки "тест" Bне призведе до порожнього середовища. Це може створити нескінченну петлю.
  • #(A)(B), де Aі Bє програмами, застосовуєтьсяA і Bдо поточного середовища і приймає симетричну різницю результатів.

Команди виконуються зліва направо. Наприкінці розмір середовища друкується одинаково.

Перекладач

Цей інтерпретатор містить команду налагодження ?, яка друкує середовище, не змінюючи її. Вона не повинна відображатися в жодному вирішенні завдання. Будь-які символи, крім того *-$!#()?, просто ігноруються, тому ви можете писати коментарі безпосередньо в код. Нарешті, інтерпретатор визнає ідіому !(A)(#(A)())"виконувати, Aпоки результат більше не змінюється", і оптимізує її для додаткової швидкості (мені знадобилася, щоб моє рішення закінчилося менше години на останньому тестовому випадку).

import sys

def parse(prog):
    "Parse a prefix of a string into an AST. Return it and the remaining input."
    ret = []
    while prog:
        if prog[0] in "#!":
            sub1, prog1 = parse(prog[2:])
            sub2, prog2 = parse(prog1[1:])
            ret += [prog[0],sub1,sub2]
            prog = prog2
        elif prog[0] == ')':
            prog = prog[1:]
            break
        else:
            ret += [prog[0]]
            prog = prog[1:]
    return ret, prog

def intp(ast, L_env, N_env):
    "Interpret the AST on an environment, return the resulting environment."
    ptr = 0
    while ptr < len(ast):
        cmd = ast[ptr]
        if cmd == '*':
            N_env = N_env | set(L[0] for L in L_env if L)
            L_env = set(L[1:] for L in L_env)
            ptr += 1
        elif cmd == '-':
            N_env = set(N-1 for N in N_env if N>0)
            ptr += 1
        elif cmd == '$':
            L_env = set(L[1:]+L[:1] for L in L_env)
            ptr += 1
        elif cmd == '!':
            # Speed optimization
            cond = ast[ptr+2]
            if cond == ['#', ast[ptr+1], []]:
                L_next, N_next = intp(ast[ptr+1], L_env, N_env)
                while L_next != L_env or N_next != N_env:
                    L_env, N_env = L_next, N_next
                    L_next, N_next = intp(ast[ptr+1], L_env, N_env)
            else:
                while True:
                    L_test, N_test = intp(cond, L_env, N_env)
                    if not L_test and not N_test:
                        break
                    L_env, N_env = intp(ast[ptr+1], L_env, N_env)
            ptr += 3
        elif cmd == '#':
            L_env1, N_env1 = intp(ast[ptr+1], L_env, N_env)
            L_env2, N_env2 = intp(ast[ptr+2], L_env, N_env)
            L_env = L_env1 ^ L_env2
            N_env = N_env1 ^ N_env2
            ptr += 3
        elif cmd == '?':
            print(L_env | N_env)
            ptr += 1
        else:
            ptr += 1
    return L_env, N_env

def main(p, L):
    "Run the program on the input, return the output."
    # Parse the input list
    L = ''.join(c for c in L if c in "01")
    while "00" in L:
        L = L.replace("00","0")
    L = [-2] + [i for i in range(len(L)-1) if L[i:i+2] == "10"]
    L = tuple(b-a-1 for (a,b) in zip(L, L[1:]))
    # Parse the program
    ast = parse(p)[0]
    L_env, N_env = intp(ast, set([L]), set())
    return '1'*(len(L_env) + len(N_env))

if __name__ == "__main__":
    filename = sys.argv[1]
    f = open(filename, 'r')
    prog = f.read()
    f.close()
    L = input()
    print(main(prog, L))

Моє рішення

Моє довідкове рішення довжиною 484 байти, настільки коротке порівняно з 3271-байтною програмою TheNumberOne. Це, швидше за все, через складну та дивовижну макросистему TheNumberOne, розроблену для програмування в HPR. Основна ідея в обох наших програмах схожа:

  1. Дізнайтеся, як створити максимальний елемент списку.
  2. Щоб вилучити максимальний елемент, обертайте список, поки перший елемент не дорівнює максимальному, а потім виведіть його.
  3. Видаліть максимум двічі, після чого надрукуйте новий максимальний елемент.

Однак, наскільки я можу сказати, точні деталі реалізації зовсім інші. Ось моє рішення:

!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())-#(!(-)(#(-)()))()

А ось коментована програма Python, яка її виробляє (тут нічого фантазійного, лише основні рядкові маніпуляції, щоб позбутися від усіх повторень):

# No numbers in the environment
no_nums = "#(-)()"
# No non-empty lists in the environment
no_lists = "#(*)()"
# Remove all numbers from the environment
del_nums = "!(-)(" + no_nums + ")"
# Remove all lists from the environment
del_lists = "#(" + del_nums + ")()"
# Splat the list to the environment:
#  pop the list until it's empty and delete the empty list,
#  then take symmetric difference with all numbers removed
splat = "#(!(*)(" + no_lists + ")" + del_lists + ")(" + del_nums + ")"
# Put into the environment all numbers up to list maximum:
#  decrement and splat until a fixed point is reached.
#  Without the speed optimization, this is very slow if the list elements are large.
splat_upto = "!(-" + splat + ")(#(-" + splat + ")())"
# Copy maximum element to environment:
#  take all elements up to maximum,
#  then take symmetric difference of decrement and list deletion
copy_max = splat_upto + "#(-)(" + del_lists + ")"
# Delete maximum element from list:
#  rotate until first element is maximal, then pop and delete it
del_max = "!($)(" + del_nums + "#(" + copy_max + ")(*)" + del_lists + ")*" + del_nums
# Full program:
#  remove the maximum twice, then produce all numbers up to maximum,
#  then decrement and remove lists. The environment will contain exactly
#  the integers from 0 to third largest - 1, and their number is printed.
main = del_max + del_max + splat_upto + "-" + del_lists
print(main)


@TheNumberOne Додав моє рішення.
Згарб

12

TKDYNS (Щоб убити дракона, вам потрібен меч) - тріснув Мартін Бюттнер

EDIT: Я додав своє рішення та пояснення нижче основної публікації.

Фон

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

...

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

Ще кілька деталей

Берего дракона має форму сітки 10х10. Між певними сусідніми точками в сітці є вузька доріжка; між іншими існує глибока прірва і певна смерть. Приклад компонування сітки 4x4 може бути таким:

 0---1   2---3
     |   |   |
 4---5---6   7
 |           |
 8   9--10  11
     |       |
12--13--14--15

Ви знаєте, що завжди є спосіб дістатися з однієї точки до будь-якої іншої точки, але не більше ніж вам було розкрито.

Щоб успішно перемогти дракона, спочатку потрібно зібрати деякі предмети, які ви зможете поєднати разом, щоб створити магічне лезо вбивства дракона. Зручно, що всі шматки для цієї зброї були розкидані навколо драбини дракона. Ви просто повинні їх зібрати.

Поворот у тому, що кожен шматок зброї потрапив у пастку. Щоразу, коли один збирається, схема розташування доріжок змінюється. Раніше безпечні шляхи тепер могли призвести до певної смерті, і навпаки.

Команди

Існує лише 5 дійсних команд.

  • < - Зробіть крок вліво

  • > - Зробіть крок праворуч

  • ^ - Зробіть крок вгору

  • v - Зробіть крок вниз

  • c- Зберіть будь-які предмети, які, можливо, лежать на вашому поточному положенні. Якщо були присутні предмети, розташування лігва змінюється. З позиціями, пронумерованими рядками, як вище, візьміть свій модуль позиції 10. В інтерпретаторі є 10 макетів, які жорстко закодовані, і макет змінюється на відповідний. Наприклад, якщо ви перебуваєте в положенні 13, то макет змінюється наlayouts[3]

Макети, як вони з'являються в інтерпетері, були закодовані до цілих чисел наступним чином:

  • Порожній макет кодується до нуля.

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

    • Якщо крок горизонтальний, додайте 2^(2*x)до кодування (це потужність, а не XOR)

    • Якщо крок вертикальний, додайте 2^(2*x + 1)до кодування.

Виконання потоку

Інтерпретатор запускається з ім'ям вихідного файла як аргументом командного рядка.

Коли інтерпретатор запущений, він запропонує користувачеві виконати квест. Цей вхід повинен бути у формі, описаній у запитанні, та визначати розташування у лігві складових частин зброї. Зокрема, кожне вхідне ціле число приймається за модулем 100 і розміщується у відповідному місці в лігві.

Кожна вихідна програма складається з декількох рядків, кожен рядок складається з певної послідовності з вищезгаданих 5 дійсних символів. Ці рядки представляють ваших міньйонів. Ви, воїне, стежите за послідовністю дій, які, як відомо, є безпечними. Спочатку ви нічого не знаєте про лігво, тому ця послідовність порожня. Взявши кожного міньйона по черзі, виконується наступне, починаючи з позиції 0:

  • Міньйону доручено виконувати всі відомі безпечні дії з подальшими діями у власному рядку коду.

    • Якщо міньйон вмирає в будь-який момент, про це вам повідомляється, і лігво повертається до своєї початкової конфігурації. Всі елементи замінюються, а доріжки повертаються у вихідні положення.

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

Після того, як всі міньйони вичерпані, ви, воїн, виконайте всі дії, які, як відомо, є безпечними, знову починаючи з позиції 0. Є два можливі результати:

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

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

Код перекладача (Python 2)

import collections
import copy
import sys

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

class Interpreter(object):

    def __init__(self, source_file):
        self.source_filename = source_file
        self.layout = layouts[0]
        self.position = 0
        self.ingredients = []
        self.quest_items = {}
        self.attempts = collections.deque()

        self.safe_position = 0
        self.safe_ingredients = []
        self.safe_quest_items = {}
        self.safe_layout = layouts[0]

    def get_input(self):
        s = raw_input("Which quest would you like to embark on today?")
        ind = s.find('00')
        s = s[:ind]
        items = map(len, s.split('0'))
        for item in items:
            if item not in self.safe_quest_items:
                self.safe_quest_items[item] = 1
            else:
                self.safe_quest_items[item] += 1

    def parse_attempts(self):
        with open(self.source_filename, 'r') as source:
            for line in source:
                self.attempts.append(line.strip())

    def enc(self, x, y):
        x, y = min(x, y), max(x, y)
        if x < 0:
            return 0
        if y == x + 1:
            return 1 << (2*x)
        elif y == x + size:
            return 1 << (2*x + 1)
        else:
            return 0

    def exec_command(self, char):
        if char == '<':
            if self.enc(self.position, self.position-1) & self.layout:
                self.position -= 1
            else:
                return False
        elif char == '>':
            if self.enc(self.position, self.position+1) & self.layout:
                self.position += 1
            else:
                return False
        elif char == '^':
            if self.enc(self.position, self.position-size) & self.layout:
                self.position -= size
            else:
                return False
        elif char == 'v':
            if self.enc(self.position, self.position+size) & self.layout:
                self.position += size
            else:
                return False
        elif char == 'c':
            for item in xrange(self.position, 10**6, size*size):
                if item in self.quest_items:
                    self.ingredients += ([item] * self.quest_items.pop(item))
                    self.ingredients.sort()
                    self.layout = layouts[self.position % 10]
        else:
            raise ValueError

        return True

    def run_minion(self):
        minion = self.attempts.popleft()
        self.position = self.safe_position
        self.ingredients = copy.copy(self.safe_ingredients)
        self.quest_items = copy.copy(self.safe_quest_items)
        self.layout = self.safe_layout
        dead = False

        for cmd in minion:
            if not self.exec_command(cmd):
                dead = True

        if not dead:
            self.safe_position = self.position
            self.safe_ingredients = copy.copy(self.ingredients)
            self.safe_quest_items = copy.copy(self.quest_items)
            self.safe_layout = self.layout

    def process_minions(self):
        while self.attempts:
            self.run_minion()

    def final_run(self):
        if len(self.safe_quest_items) == 0:
            print "You killed the dragon" + "!!1" * self.safe_ingredients[-3]
        else:
            print "The dragon lives on. Better luck next time..."

    def interpret(self):
        self.get_input()
        self.parse_attempts()
        self.process_minions()
        self.final_run()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Wrong number of arguments"
    else:
        test = Interpreter(sys.argv[1])
        test.interpret()

Найкраща удача, доблесний воїн.

Моє рішення та пояснення

Ось сценарій Python, який генерує вихідний код для вирішення проблеми. Для інтересу кінцевий вихідний код Мартіна приблизно в 5 разів менший, ніж код, створений моїм сценарієм. З іншого боку, мій сценарій для генерації коду приблизно в 15 разів менший, ніж програма Математика Мартіна ...

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

def enc(edge):
    x,y = min(edge), max(edge)
    if x < 0:
        return 0
    if y == x + 1:
        return 1 << (2*x)
    elif y == x + size:
        return 1 << (2*x + 1)

def path(x, y, tree):
    stack = [(x,'')]
    while stack[-1][0] != y:
        vertex, path = stack.pop()
        if (enc((vertex, vertex+1))&tree) and ((not path) or path[-1] != '<'):
            stack.append((vertex+1, path+'>'))
        if (enc((vertex, vertex-1))&tree) and ((not path) or path[-1] != '>'):
            stack.append((vertex-1, path+'<'))
        if (enc((vertex, vertex+size))&tree) and ((not path) or path[-1] != '^'):
            stack.append((vertex+size, path+'v'))
        if (enc((vertex, vertex-size))&tree) and ((not path) or path[-1] != 'v'):
            stack.append((vertex-size, path+'^'))
    return stack[-1][1]

def reverse(path):
    rev = ''
    for i in xrange(len(path)-1, -1 ,-1):
        if path[i] == '<':
            rev += '>'
        if path[i] == '>':
            rev += '<'
        if path[i] == 'v':
            rev += '^'
        if path[i] == '^':
            rev += 'v'
    return rev

def assert_at(x, tree):
    path_ul = path(x, 0, tree)
    path_dr = path(x, size*size - 1, tree)
    return path_ul + reverse(path_ul) + path_dr + reverse(path_dr)

def safe_path(x, y, tree):
    return assert_at(x, tree) + path(x, y, tree)

with open('source.txt', 'w') as f:
    for x in xrange(size*size - 1):
        for tree in layouts:
            f.write(safe_path(x, x+1, tree) + 'c\n')

Основна структура

Це генерує 990 рядків вихідного коду, які входять у групи по 10. Перші 10 рядків містять інструкції, які намагаються перемістити міньйон з положення 0в положення 1, а потім збирають предмет - по одному набору для кожного можливого макета. Наступні 10 рядків містять вказівки, які намагаються перемістити міньйон з положення 1в положення 2, а потім збирають предмет. І так далі ... Ці шляхи обчислюються за допомогою pathфункції в сценарії - це просто простий пошук по глибині.

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

Питання з підходом

Не завжди може бути так, що саме один міньйон із групи 10 успіхів - наприклад, міньйон, призначений дістатися з позиції 0на позицію, 1може випадково досягти успіху перейти з позиції 1на позицію2 (через схожість у макетах), і що прорахунок буде поширюватися через, що може спричинити збій.

Як це виправити

Виправлення, яке я використав, було таке:

Кожному міньйону, який намагається дістатись із положення nдо місця n+1, спочатку змусьте його ходити з положення nв положення 0(верхній лівий кут) і знову назад, потім з положення nв положення 99(нижній правий кут) і назад знову. Ці вказівки можна безпечно виконувати лише з позиціїn - будь-яке інше вихідне положення і міньйон піде з краю.

Отже, ці додаткові інструкції запобігають випадковому виходу мінонів кудись, куди вони не призначені, і це гарантує успіх саме одного міньона з кожної групи з 10 осіб. Зауважте, що це не обов'язково міньйон, якого ви очікуєте - це може бути так, що міньйон, який вважає, що він перебуває в макеті 0, досягає успіху, навіть коли ми справді перебуваємо в макеті 7, - але в будь-якому випадку, факт, що ми маємо тепер змінене становище означає, що всі інші прислужники в групі обов'язково загинуть. Ці додаткові етапи обчислюються assert_atфункцією, і safe_pathфункція повертає шлях, який є об'єднанням цих додаткових кроків із звичайним шляхом.


1
Тріснув. Це було дуже цікаво, але я думаю, що це викликає проблему з "вашою мовою програмування має вирішувати лише це одне завдання", оскільки зламання головоломки не має нічого спільного з фактичним вирішенням цієї задачі програмування. ;)
Мартін Ендер

Я створив цю відповідь головним чином тому, що помітив, що проблема існує - і, здається, ніщо не заважає комусь використовувати справді важку обчислювальну проблему замість неї. Заборона на "без криптовалюти" здається довільно вузькою ...
Сем Капплман-Лайнс

правда. Я думаю, саме тому це конкурс на популярність. Якщо проблема мала більше обчислювальний характер і не була зафіксована такою приємною історією стільки голосів, як відповідь належною (потенційно Тюрінг повною) мовою, яку насправді просто важко використовувати.
Мартін Ендер

Додав моє рішення для зацікавлення. Також для інтересу я спочатку створив головоломку з сіткою 1000х1000, але в інтересах відсутності макетів, кодованих до ~ 600000-цифрних цифр, я вибрав менший розмір.
Сем Капплман-Лайнс

8

Firetype, потрісканий Мартіном Бюттнером

Справді дивна суміш BF і CJam. І хто знає що ще! Досить впевнений, що це буде легко, але все одно було весело. FYI, назва стосується Vermillion Fire від Final Fantasy Type-0 .

ПРИМІТКА : Пробачте мене про будь-які неясності в цьому описі. Я не найкращий письменник ...: О

Мартін зламав це дуже швидко! Це була моя оригінальна програма для вирішення проблеми:

_
,
^
~
+
|
|
-
%
+
_
+
=











`
~
+
|
%

_
=

\
@
-
-
!
<
>
>
>

_
+
.
<
-
`
~
~
+
|
|
-
#
%

Синтаксис

Сценарій Firetype - це в основному список рядків. Перший символ кожного рядка - команда для запуску. Порожні рядки - це в основному НОП.

Семантика

У вас є масив цілих чисел і вказівник (думаю, BF). Ви можете переміщати ліворуч і праворуч або "натискати" елементи на масив.

Натискання

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

Команди

_

Натисніть нуль на масив.

+

Збільшення елемента за поточним вказівником.

-

Зменшення елемента за поточним вказівником.

*

Подвійний елемент за поточним вказівником.

/

Половину елемента в поточному покажчику.

%

Візьміть елемент за поточним вказівником і перескочіть вперед, що багато ліній, і перемістіть вказівник ліворуч. Якщо значення негативне, скочіть назад.

=

Візьміть елемент у поточному покажчику та перейдіть до цього рядка + 1. Наприклад, якщо поточний елемент є 0, він перейде до рядка 1. Це також переміщує вказівник ліворуч.

,

Прочитайте символ зі стандартного вводу та натисніть його значення ASCII.

^

Візьміть елемент у поточному покажчику, інтерпретуйте його як значення ASCII для символу та перетворіть його на ціле число. Наприклад, якщо поточне значення 49 (значення ASCII 1), елемент у поточному покажчику буде встановлений на ціле число 1.

.

Запишіть на екран поточне число.

!

Візьміть елемент за поточним вказівником і повторіть наступний рядок, що багато разів. Також переміщує вказівник ліворуч.

<

Перемістіть курсор вліво. Якщо ви вже на початку, видається помилка.

>

Перемістіть вказівник праворуч. Якщо ви вже в кінці, помилка видається.

~

Якщо поточний елемент не нульовий, замініть його 0; в іншому випадку замініть його на 1 .

|

Квадрат поточного елемента.

@

Встановіть поточний елемент на довжину масиву.

`

Скопіюйте поточний елемент.

\

Сортуйте елементи за вказівником та перед ним.

#

Негатуйте поточний елемент.

Перекладач

Також доступний у Github .

#!/usr/bin/env python

# The FireType interpreter.
# Runs under Python 2 and 3.
import sys

class Array(object):
    def __init__(self):
        self.array = []
        self.ptr = 0

    def push_zero(self):
        if self.ptr == len(self.array):
            self.array.append(0)
        else:
            self.array[self.ptr] = 0
        self.ptr += 1

    def left(self):
        self.ptr -= 1
        assert self.ptr >= 0 and self.array, 'pointer underflow (at %d)' % i

    def right(self):
        self.ptr += 1
        assert self.ptr <= len(self.array), 'pointer overflow (at %d)' % i

    def sort(self):
        lhs = self.array[:self.ptr-1]
        rhs = self.array[self.ptr-1:]
        lhs.sort()
        lhs.reverse()
        self.array = lhs + rhs

    def __call__(self, *args):
        args = list(args)
        assert self.array, 'out-of-bounds (at %d)' % i
        if not args:
            return self.array[self.ptr-1]
        self.array[self.ptr-1] = args.pop()
        assert not args

    def __len__(self):
        return len(self.array)

    def __str__(self):
        return 'Array(array=%s, ptr=%s)' % (self.array, self.ptr)

    def __repr__(self):
        return 'Array(array=%r, ptr=%r)' % (self.array, self.ptr)

def execute(lines):
    global i, array
    i = 0
    array = Array()
    rep = 0
    while i < len(lines):
        line = lines[i]
        if not line:
            i += 1
            continue
        line = line[0]
        if line == '_':
            array.push_zero()
        elif line == '+':
            array(array() + 1)
        elif line == '-':
            array(array() - 1)
        elif line == '*':
            array(array() * 2)
        elif line == '/':
            array(int(array() / 2))
        elif line == '%':
            i += array()
            array.left()
        elif line == '=':
            i = array()-1
            array.left()
        elif line == ',':
            array.push_zero()
            array(ord(sys.stdin.read(1)))
        elif line == '.':
            sys.stdout.write(str(array()))
        elif line == '!':
            rep = array()
            array.left()
            i += 1
        elif line == '<':
            array.left()
        elif line == '>':
            array.right()
        elif line == '^':
            array(int(chr(array())))
        elif line == '~':
            array(int(not array()))
        elif line == '|':
            array(array() ** 2)
        elif line == '@':
            array(len(array))
        elif line == '`':
            top = array()
            array.push_zero()
            array(top)
        elif line == '\\':
            array.sort()
        elif line == '#':
            array(-array())

        if rep:
            rep -= 1
        else:
            i += 1

def main(args):
    try:
        _, path = args
    except ValueError:
        sys.exit('usage: %s <file to run, - for stdin>')

    if path == '-':
        data = sys.stdin.read()
    else:
        with open(path) as f:
            data = f.read()

    try:
        execute(data.split('\n'))
    except:
        print('ERROR!')
        print('Array was %r' % array)
        print('Re-raising error...')
        raise

if __name__ == '__main__':
    main(sys.argv)

Я думаю, що твердження про нижню межу масиву є помилковою. Оскільки ви використовуєте self.ptr-1для доступу, ви, ймовірно, self.ptr>0не можете перевірити це >=0. (Це не повинно визнати недійсними жодні дійсні програми, але вони можуть змусити деякі програми випадково працювати, що не повинно.)
Martin Ender

І ще одне: код каже, що =встановлює значення array() - 1, документація говорить +1?
Мартін Ендер

Тріснув. (Якщо припустити, що перекладач є нормативним, а не описом.)
Мартін Ендер

@ MartinBüttner Данг, це було швидше, ніж я думав! : OI виправив згадані вами проблеми з doc.
kirbyfan64sos

7

Acc !! (безпечний)

Це бейк ...

введіть тут опис зображення

... і, сподіваємось, безумовно, більш щілинних.

Я вже читав Acc! спец. Як Acc !! інший?

В Acc !! , змінні циклу виходять за межі, коли цикл виходить. Використовувати їх можна лише всередині циклу. Зовні ви отримаєте помилку "ім'я не визначено" Крім цієї зміни, мови однакові.

Заяви

Команди аналізуються за рядком. Існує три типи команд:

  1. Count <var> while <cond>

Зараховується <var>від 0 до тих пір, як <cond>це ненульове значення, еквівалентне C ++ for(int <var>=0; <cond>; <var>++). Лічильником циклу може бути будь-яка одна маленька літера. Умовою може бути будь-який вираз, не обов'язково включаючи змінну циклу. Цикл припиняється, коли значення умови стає 0.

Петлі вимагають фігурних брекетів у стилі K&R (зокрема, варіант Stroustrup ):

Count i while i-5 {
 ...
}

Як було сказано вище, змінні циклу доступні лише всередині їх циклів ; спроба посилання на них згодом викликає помилку.

  1. Write <charcode>

Виводить один символ із заданим значенням ASCII / Unicode для stdout. Шаркодом може бути будь-який вираз.

  1. Вираз

Будь-який вираз, що стоїть сам по собі, оцінюється і присвоюється назад акумулятору (який доступний як _). Так, наприклад, 3це твердження, яке встановлює акумулятор 3; _ + 1збільшує акумулятор; і _ * Nчитає персонаж і помножує акумулятор на його код.

Примітка: акумулятор - єдина змінна, до якої можна безпосередньо призначити; змінні циклу і Nможуть використовуватися в обчисленнях, але не змінюватися.

Акумулятор спочатку дорівнює 0.

Вирази

Вираз може включати цілі літерали, змінні циклу ( a-z), _для акумулятора та спеціальне значенняN , яке читає символ і оцінює його штрих-код кожного разу, коли воно використовується. Примітка. Це означає, що ви можете прочитати лише один кадр; при наступному використанні Nви прочитаєте наступний.

Оператори:

  • +, доповнення
  • -, віднімання; одинарне заперечення
  • *, множення
  • /, ціле ділення
  • %, модуль
  • ^, експоненція

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

Пробіли та коментарі

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

# починається однорядковий коментар.

Введення-виведення

Acc !! очікує введення одного рядка символів. Кожен вхідний символ можна отримати в послідовності, а його штрих-код обробити за допомогою N. Спроба прочитати останній символ рядка викликає помилку. Символ може бути виведений, передавши його charcode до Writeзаяви.

Перекладач

Перекладач (написаний Python 3) перекладає Acc !! код в Python і execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
                pyCode.append(" "*indent + "del " + loopVar)
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()

Рішення

Падіння оригінального Acc!являв собою змінні циклу, які продовжували бути доступними поза їх петлями. Це дозволило зберегти копії акумулятора, що зробило рішення надто простим.

Тут без цього отвору в петлі (вибачте) у нас є лише акумулятор для зберігання речей. Однак для вирішення задачі нам потрібно зберігати чотири довільно великих значення. 1 Рішення: переплутайте їх біти і збережіть отриманий комбінований номер у акумуляторі. Наприклад, значення акумулятора 6437 зберігало б такі дані (використовуючи біт нижчого порядку як однобітний прапор):

1100100100101  Binary representation of accumulator
321032103210F  Key

The flag is 1 and the four numbers are
Number 0: 010 = 2
Number 1: 001 = 1
Number 2: 100 = 4
Number 3: 110 = 6

Ми можемо отримати доступ до будь-якого біта будь-якого числа, розділивши акумулятор на відповідну потужність 2, мод 2. Це також дозволяє встановити або перевернути окремі біти.

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

Найскладнішою частиною (і з причини, що у мене було змінних глобальних циклів у першому втіленні), є порівняння двох чисел, щоб знати, чи потрібно їх замінювати. Щоб порівняти два біти, ми можемо перетворити таблицю істинності в математичний вираз; мій прорив для Acc !! знаходив алгоритм порівняння, який переходив від бітів низького порядку до бітів високого порядку, оскільки без глобальних змінних немає способу перевести біт на номер зліва направо. Біт нижнього порядку в акумуляторі зберігає прапор, який сигналізує про те, чи слід міняти два розглянуті числа.

Підозрюю, що Acc !! є Тюрінг-завершеним, але я не впевнений, що хочу вирішити проблеми.

Ось моє рішення з коментарями:

# Read and process numbers until the double 0

Count y while N-48 {
    # Read unary number and store it (as binary) in number 0
    # The above loop header consumed the first 1, so we need to add 1 to number 0

    _ + 2

    # Increment number 0 for each 1 in input until next 0

    Count z while N-48 {
        # In this context, the flag indicates a need to carry; set it to 1
        _ - _%2 + 1

        # While carry flag is set, increment the next bit in line
        Count i while _%2 {
            # Set carry flag to 1 if i'th bit is 1, 0 if it's 0
            # Set i'th bit to 1 if it was 0, 0 if it was 1
            _ - _%2 + _/2^(i*4+1)%2 + (-1)^(_/2^(i*4+1)%2)*2^(i*4+1)
        }
    }

    # Bubble number 0 upwards

    Count n while n-3 {
        # The flag (rightmost bit of accumulator) needs to become 1 if we want to swap
        # numbers (n) and (n+1) and 0 if we don't
        # Iterate over bit-groups of accumulator, RTL
        Count i while _/2^(i*4+1) {
            # Adjust the flag as follows:
            # _/2^(i*4+n+1)%4 is the current bit of number (n+1) followed by the current
            # bit of number (n), a value between 0 and 3
            # - If this quantity is 1 (01), number (n) is bigger so far; set flag to 1
            # - If this quantity is 2 (10), number (n+1) is bigger so far; set flag to 0
            # - If this quantity is 0 (00) or 3 (11), the two bits are the same; keep
            #   current value of flag
            _ + (_/2^(i*4+n+1)%4%3 + 1)/2*(_/2^(i*4+n+1)%4%3%2 - _%2)
        }

        # Now swap the two if the flag is 1
        Count i while (_%2)*(_/2^(i*4+1)) {
            # _/2^(i*4+n+1)%2 is the current bit of number (n)
            # _/2^(i*4+n+2)%2 is the current bit of number (n+1)
            _ - (_/2^(i*4+n+1)%2)*2^(i*4+n+1) - (_/2^(i*4+n+2)%2)*2^(i*4+n+2) + (_/2^(i*4+n+2)%2)*2^(i*4+n+1) + (_/2^(i*4+n+1)%2)*2^(i*4+n+2)
        }
    }

    # Discard number 0, setting it to all zeros for the next iteration
    Count i while _/2^(i*4+1) {
        _ - _/2^(i*4+1)%2*2^(i*4+1)
    }
}

# Once the loop is over, all input has been read and the result is in number 1
# Divide by 2 to get rid of flag bit

_ / 2

# Zero out numbers 2 and 3

Count i while _/2^(i*4) {
    _ - _/2^(i*4+2)%2*2^(i*4+2)
}

Count i while _/2^(i*4) {
    _ - _/2^(i*4+3)%2*2^(i*4+3)
}

# Move bits of number 1 down to their final locations

Count i while _/2^i {
    _ - _/2^(i*4+1)%2*2^(i*4+1) + _/2^(i*4+1)%2*2^i
}

# _ now contains the correct answer in decimal; to output in unary:

Count z while z-_ {
    Write 49
}

1 Відповідно до специфікації питань, потрібно підтримувати лише значення до 1 мільйона. Я радий, що ніхто не скористався цим для більш простого рішення - хоча я не зовсім впевнений, як би ви зробили порівняння.


Фото LOL @ the Bill the Cat
спагетто

7

Picofuck (безпечно)

Picofuck схожий на Smallfuck . Він працює на двійковій стрічці, яка не пов'язана праворуч, обмежена ліворуч. Він має такі команди:

  • > перемістити вказівник праворуч

  • <перемістити вказівник вліво. Якщо вказівник відвалиться від стрічки, програма припиняється.

  • * переверніть біт на вказівник

  • (якщо біт вказівника є 0, перейдіть до наступного)

  • )нічого не робити - дужки в Picofuck - це ifблоки, а не whileпетлі.

  • .написати в stdout біт за вказівником як ascii 0або 1.

  • ,читати від stdin, поки ми не зіткнемось з a 0або 1, і збережемо це в біті вказівника.

Код Picofuck завершується - як тільки буде досягнуто кінця програми, воно продовжується з самого початку.

Крім того, Picofuck забороняє вкладені дужки. Парези, що з’являються в програмі Picofuck, повинні чергуватись (і )починати з (і закінчуватись ).

Перекладач

Написано в Python 2.7

використання: python picofuck.py <source_file>

import sys

def interpret(code):
    # Ensure parentheses match and are not nested.
    in_if_block = False
    for c in code:
        if c == '(':
            if in_if_block:
                print "NESTED IFS DETECTED!!!!!"
                return
            in_if_block = True
        elif c == ')':
            if not in_if_block:
                print "Unmatched parenthesis"
                return
            in_if_block = False
    if in_if_block:
        print "Unmatched parenthesis"
        return


    code_ptr = 0
    array = [0]
    ptr = 0

    while 1:
        command = code[code_ptr]
        if command == '<':
            if ptr == 0:
                break
            ptr -= 1
        elif command == '>':
            ptr += 1
            if ptr == len(array):
                array.append(0)
        elif command == '*':
            array[ptr] = 1-array[ptr]
        elif command == '(':
            if array[ptr] == 0:
                while code[code_ptr] != ')':
                    code_ptr = (code_ptr + 1) % len(code)
        elif command == ',':
            while True:
                c = sys.stdin.read(1)
                if c in ['0','1']:
                    array[ptr] = int(c)
                    break
        elif command == '.':
            sys.stdout.write(str(array[ptr]))
        code_ptr = (code_ptr+1)%len(code)

if __name__ == "__main__":
    with open(sys.argv[1]) as source_file:
        code = source_file.read()
    interpret(code)

Рішення

Наступна програма python 2.7 видає моє рішення, яке можна знайти тут

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

states = {
    "SETUP":(
        "*>",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "GET_NUMBER":(
        ",",
        "CHANGE_A",
        "PREPARE_PRINT_C"
    ),

    "GET_DIGIT":(
        ",",
        "CHANGE_A",
        "GOT_DIGIT"
    ),

    "GOT_DIGIT":(
        ">>>>",
        "GO_BACK",
        "GO_BACK"
    ),

    "CHANGE_A":(
        ">",
        "CHANGE_B",
        "SET_A"
    ),

    "SET_A":(
        "*>>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_B":(
        ">",
        "CHANGE_C",
        "SET_B"
    ),

    "SET_B":(
        "*>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_C":(
        ">",
        "CONTINUE_GET_NUMBER",
        "SET_C"
    ),

    "SET_C":(
        "*>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CONTINUE_GET_NUMBER":(
        ">>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "GO_BACK":(
        "<<<<<",
        "FINISH_GO_BACK",
        "GO_BACK"
    ),

    "FINISH_GO_BACK":(
        ">",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "PREPARE_PRINT_C":(
        ">>>",
        "PRINT_C",
        "PRINT_C"
    ),

    "PRINT_C":(
        ".>>>>>",
        "PRINT_C",
        "TERMINATE"
    ),

    "TERMINATE":(
        "<",
        "TERMINATE",
        "TERMINATE"
    ),
}

def states_to_nanofuck(states,start_state):
    state_list = list(states)
    state_list.remove(start_state)
    state_list.insert(0,start_state)

    states_by_index = []
    for i,state in enumerate(state_list):
        commands, next1, next0 = states[state]
        states_by_index.append((commands,state_list.index(next1),state_list.index(next0)))


    # setup first state
    fragments = ['*(*>>>>>*<<<<<)>>>>>']

    # reset states that don't match
    for index in range(len(states_by_index)):
        for bool in range(2):
            # at state_0_0
            state_dist = index*3 + bool
            # move state to curstate
            fragments.append('>'*state_dist)
            fragments.append('(*')
            fragments.append(  '<'*state_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*state_dist)
            fragments.append(')')
            fragments.append('<'*state_dist)

            # go to arr
            fragments.append('<<<')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # compute match = arr & curstate
            fragments.append('(>)(>*<)<(<)>')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # reset curstate
            fragments.append('>(*)')

            # move match to matchstate, go back to state_0_0
            matchstate_dist = index*3 + 2
            fragments.append('>(*>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(  '*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append('<)>')

    #fragments.append('|')

    # do the commands of the matching state
    for index,state in enumerate(states_by_index):
        for bool in range(2):
            # at state_0_0
            matchstate_dist = index*3 + 2
            # move matchstate to curstate
            fragments.append('>'*matchstate_dist)
            fragments.append('(*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(')')
            fragments.append('<'*matchstate_dist)

            # if curstate, reset curstate
            fragments.append('<<(*')

            # go to arr
            fragments.append('<')

            # do commands
            commands,next1,next0 = state
            for c in commands:
                if c in '<>':
                    fragments.append(c*(3*len(states_by_index)+5))
                else:
                    fragments.append(c)

            # go to state_0_0
            fragments.append('>>>')

            # set next states
            for dist in [next0*3, next1*3+1]:
                fragments.append('>'*dist)
                fragments.append('*')
                fragments.append('<'*dist)

            # go to curstate
            fragments.append('<<')

            # end if
            fragments.append(')')

            # go to state_0_0
            fragments.append('>>')


    # go back to setup and set it
    fragments.append('<<<<<*')

    code = ''.join(fragments)

    return code



print states_to_nanofuck(states, "SETUP")

2
чекає майже 2 роки Це пізніше ще?
CalculatorFeline

Просто FYI, посилання, яке ви надали, тепер мертве. "
Conor O'Brien

Посилання вимагає завантаження, і я занадто ледачий. Виправте, будь ласка.
CalculatorFeline

@CalculatorFeline Це 13 КБ, це набагато простіше в обробці як завантаження.
mbomb007

7

PQRS - Безпечно! / Надається рішення

Основи

Усі маються на увазі інструкції мають чотири операнди адрес пам'яті:

P₀ Q₀ R₀ S₀
P₁ Q₁ R₁ S₁
...
Pᵥ₋₁ Qᵥ₋₁ Rᵥ₋₁ Sᵥ₋₁

Де v розмір пам’яті в квартетах.

Pᵢ, Qᵢ,Rᵢ , SᵢПідписуються цілі числа в рідному розмірі вашої машини (наприклад , 16, 32 або 64 біт) , які ми будемо називати слова.

Для кожного квартету iмається на увазі операція із []позначенням непрямості:

if (([Pᵢ] ← [Qᵢ] − [Rᵢ]) ≤ 0) go to Sᵢ else go to Pᵢ₊₁

Зауважте, що Subleq - це підмножина PQRS .

Subleq було доведено повним, тому PQRS повинен бути також повним!

Структура програми

PQRS визначає початковий заголовок наступним чином:

H₀ H₁ H₂ H₃ H₄ H₅ H₆ H₇

H₀ H₁ H₂ H₃завжди перша інструкція P₀ Q₀ R₀ S₀. H₀в H₃повинні бути визначені під час завантаження.

PQRS має зачаток вводу / виводу, але достатній для виклику.

H₄ H₅: при запуску програми він зчитує максимум H₅ASCII символів зі стандартного введення та зберігає як слова з індексу H₄далі. H₄і їх H₅потрібно визначити під час завантаження. Після читання H₅буде встановлено кількість прочитаних символів (і збережені слова).

H₆ H₇: при завершенні програми, починаючи з індексу H₆, він друкує всі байти, що містять H₇слова, до стандартного виводу у вигляді символів ASCII. H₆і їх H₇потрібно визначити до закінчення програми. Нульові байти '\0'у висновку будуть пропущені.

Припинення

Припинення досягається встановленням Sᵢмеж i < 0або i ≥ v.

Витівки

Квартети Pᵢ Qᵢ Rᵢ Sᵢне повинні бути вирівняними або послідовними, розгалуження дозволено з підквартальними інтервалами.

PQRS має непрямий характер, тому, на відміну від Subleq, є достатня гнучкість для здійснення підпрограм.

Код може бути самозмінним!

Перекладач

Перекладач написаний на С:

#include <stdlib.h>
#include <stdio.h>

// The "architecture"
enum {P, Q, R, S, START_OF_INPUT, LENGTH_OF_INPUT, START_OF_OUTPUT, LENGTH_OF_OUTPUT};
const int NEXT = S + 1;

// Recommend optimized!
#define OPTIMIZED

#ifdef PER_SPECS
// This may not work on all OSes and architectures - just too much memory needed!
const int K = 1002000200;
#else // OPTIMIZED
// This provides enough space to run the test cases with challenge-optimized.pqrs
const int K = 5200;
#endif

int main(int argc, char *argv[])
{
    int i, *M;
    char *p;
    FILE *program;

    // Allocate enough memory
    M = calloc(K, sizeof(int));

    // Load the program
    for (i = 0, program = fopen(argv[1], "r"); i < K && !feof(program); i++)
        if (!fscanf(program, "%d", M + i))
            break;
    fclose(program);

    // Read in the input
    for (i = 0; i < M[LENGTH_OF_INPUT] && !feof(stdin); i++)
    {
        int c = fgetc(stdin);
        if (c != EOF)
            M[M[START_OF_INPUT] + i] = c;
        else
            break;
    }
    M[LENGTH_OF_INPUT] = i;

    // Execute until terminated
    for (i = 0; i >= 0 && i < K; )
        i = (M[M[P + i]] = M[M[Q + i]] - M[M[R + i]]) <= 0? M[S + i]: i + NEXT;

    // Write the output
    for (i = 0, p = (char *)(M + M[START_OF_OUTPUT]); i < M[LENGTH_OF_OUTPUT] * sizeof(int); i++)
        // Ignore '\0'
        if (p[i])
            fputc(p[i], stdout);

    // Done
    free(M);

    return 0;
}

Для використання збережіть вище вказане як pqrs.c, а потім компілюйте:

gcc -o pqrs pqrs.c

Зразок програми

Ехо-введення до 40 символів, перед яким "PQRS-".

8 8 8 -1 14 40 9 45 0 80 81 82 83 45

Щоб запустити, збережіть наведене вище як echo.pqrs, а потім:

$ ./prqs echo.pqrs
greetings[enter]
[ctrl-D]
PQRS-greetings

Запуск тестових випадків:

$ ./pqrs challenge-optimized.pqrs < test-1.txt
1

$ ./pqrs challenge-optimized.pqrs < test-2.txt
11111111111111111

$ ./pqrs challenge-optimized.pqrs < test-3.txt
[lots of ones!]

$ ./pqrs challenge-optimized.pqrs < test-3.txt | wc
0       1     773

Усі тестові справи працюють дуже швидко, наприклад, <500 мс.

Змагання

PQRS можна вважати стабільним, тому виклик починається 2015-10-31 13:00 і закінчується 2015-11-08 13:00, разів у UTC.

Удачі!

Рішення

Мова досить схожа на ту, що використовується у "Baby" - першій у світі електронної цифрової машини, що зберігається у програмі. На цій сторінці розміщена програма, щоб знайти найвищий коефіцієнт цілого числа у менше ніж 32 слова пам'яті (CRT!)!

Я виявив, що написання рішення, яке відповідає специфікаціям, не було сумісним з ОС і машиною, яку я використовував (похідне Linux Ubuntu на трохи старшому апаратному забезпеченні). Це просто вимагало більше пам’яті, ніж доступно, і демпінг ядра. На ОС з розширеним управлінням віртуальною пам'яттю або на машинах, що мають щонайменше 8 ГБ пам'яті, ви, ймовірно, можете запускати рішення за специфікаціями. Я забезпечив обидва рішення.

Дуже важко кодувати в PQRS безпосередньо, схожий на написання машинної мови, можливо навіть мікрокод. Натомість простіше написати якоюсь мовою складання, а потім "скласти". Нижче наводиться анотована мова збірки для рішення, оптимізованого для запуску тестових випадків:

; ANNOTATED PQRS ASSEMBLER CODE
; MINIMAL SIZED BUFFERS TO RUN THE TEST CASES

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       4000        
6         L0:         OUTPUT      1000        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10]

; I/O SPACE
152       INPUT:      [4000]
4152      OUTPUT:     [1000]
5152

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

Зауважте, що INC(приріст) від'ємний і DEC(декремент) позитивний! Там, де він використовується L#або L#+1як P-або Q-OPs, що відбувається, це те, що він оновлює покажчики: збільшення, декрементування, заміна тощо. Асемблер був вручну складений в PQRS , замінивши мітки компенсаціями. Нижче наведено оптимізоване рішення PQRS :

137 132 132 8
152 4000
4152 1000
137 152 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
4152 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Код, наведений вище, може бути збережений challenge-optimized.pqrsдля запуску тестових випадків.

Для повноти, ось джерела специфікації:

; ANNOTATED PQRS ASSEMBLER CODE
; FULL SIZED BUFFERS TO RUN ACCORDING TO SPECS

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       10^9        
6         L0:         OUTPUT      10^6        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10^6]

; I/O SPACE
1000142   INPUT:      [10^9]
1001000142 OUTPUT:    [10^6]
1002000142

І рішення:

137 132 132 8
1000142 1000000000
1001000142 1000000
137 1000142 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
1001000142 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Для запуску вище, ви повинні закомментировать #define OPTIMIZEDі додати #define PER_SPECSвpqrs.c і перекомпіліровать.

Це було великим викликом - дуже сподобалася розумова тренування! Повернув мене до своїх старих 6502 днів асемблера ...

Якби я реалізував PQRS як "реальну" мову програмування, я, ймовірно, додав би додаткові режими прямого та подвійного непрямого доступу на додаток до непрямого доступу, а також відносні позиції та абсолютний позиції, як з опціями непрямого доступу для розгалуження!


3
Ви повинні мати готовий розчин перед публікацією.
feersum

1
Так, рішення готове. Я розумію, що є певні сумніви, оскільки мова справді є досить складною для роботи. Для тих, хто бажає попереднього перегляду, я можу надіслати вам її, якщо ви обіцяєте не розголошувати її до кінця виклику!

6

Цинк, потрісканий! автор @Zgarb

Також доступний на GitHub .

Вам потрібен Дарт 1,12 та паб. Просто запустіть, pub getщоб завантажити єдину залежність, розбирати бібліотеку.

Ось надія на це триває довше 30 хвилин! : О

Мову

Цинк орієнтований на переосмислення операторів. Ви можете легко змінити всі оператори мовою!

Структура типової програми для цинку виглядає так:

let
<operator overrides>
in <expression>

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

Вирази

У цинку наведені дійсні вирази:

Літерали

Цинк підтримує всі нормальні цілі літерали, як 1і -2.

Змінні

Цинк має змінні (як і більшість мов). Для посилання на них просто скористайтеся назвою. Знову, як і більшість мов!

Однак існує спеціальна змінна назва, Sяка поводиться на зразок Pyth Q. Під час першого використання він прочитає рядок зі стандартного введення та інтерпретуватиме його як набір чисел. Наприклад, рядок введення 1234231перетвориться на набір {1, 2, 3, 4, 3, 2, 1}.

ВАЖЛИВА ПРИМІТКА !!!У деяких випадках літерал в кінці переоперації оператора аналізується неправильно, тому вам доведеться оточити його дужками.

Бінарні операції

Підтримуються наступні бінарні операції:

  • Додавання з допомогою +: 1+1.
  • Віднімання з допомогою -: 1-1.
  • Множення з допомогою *: 2*2.
  • Відділ по /: 4/2.
  • Рівність з =: 3=3.

Крім того, підтримується наступна одноразова операція:

  • Довжина з #: #x.

Прецедент завжди право-асоціативний. Ви можете скористатися дужками, щоб змінити це.

Тільки рівність і довжина працюють над наборами. Коли ви спробуєте отримати довжину цілого числа, ви отримаєте кількість цифр у його рядковому поданні.

Поставте розуміння

Для того, щоб маніпулювати наборами, Цинк поставив розуміння. Вони виглядають так:

{<variable>:<set><clause>}

Пункт - це або коли, або такий варіант.

А коли виглядає застереження^<expression> . Вираз, що слідує за каретою, повинен мати ціле число. Використовуючи пункт, коли буде взято лише ті елементи, у множині яких expressionнемає нуля. У межах виразу змінна _буде встановлена ​​на поточний індекс у наборі. Це приблизно еквівалентно цьому Python:

[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]

Пункт сортування , який виглядає $<expression>, сортує набір сходив за значенням <expression>. Він дорівнює цьому Python:

sorted(<set>, key=lambda <variable>: <expression>)[::-1]

Ось кілька прикладів розуміння:

  • Візьміть лише елементи множини, sщо дорівнюють 5:

    {x:s^x=5}
    
  • Сортуйте набір sза значенням, якщо його елементи у квадраті:

    {x:s$x*x}
    

Відміняє

Поміщення операторів дозволяє переглядати операторів. Вони виглядають так:

<operator>=<operator>

або:

<variable><operator><variable>=<expression>

У першому випадку ви можете визначити оператора рівним іншому оператору. Наприклад, я можу визначити, +як насправді відняти через:

+=-

Коли ви це зробите, ви можете переосмислити оператора, щоб він був магічним оператором . Є два магічні оператори:

  • joinприймає набір і ціле число і приєднується до вмісту набору. Наприклад, приєднання {1, 2, 3}до 4результату призведе до цілого числа 14243.

  • cutтакож приймає набір і ціле число і розділить набір при кожному виникненні цілого числа. Використання cutна {1, 3, 9, 4, 3, 2}і 3буде створювати {{1}, {9, 4}, {2}}... АЛЕ будь набори одноелементні сплющені, так що результат буде на самому справі {1, {9, 4}, 2}.

Ось приклад, який переосмислює +оператор у значення join:

+=join

В останньому випадку ви можете переосмислити оператора в заданому виразі. Як приклад, це визначає операцію плюс, щоб додати значення, а потім додати 1:

x+y=1+:x+:y

Але що +:? Ви можете додати двокрапку :до оператора, щоб завжди використовувати вбудовану версію. У цьому прикладі використовується вбудований файл +via+: щоб додати числа разом, потім він додає 1 (пам’ятайте, все правильно-асоціативно).

Переопределення оператора довжини виглядає приблизно так:

#x=<expression>

Зауважте, що майже всі вбудовані операції (крім рівності) використовуватимуть цей оператор довжини для визначення довжини набору. Якщо ви визначили це так:

#x=1

кожна частина цинку, яка працює на наборах, крім = того, діяла б лише над першим елементом набору, який йому було надано.

Кілька перевизначень

Можна змінити кілька операторів, розділивши їх комами:

let
+=-,
*=/
in 1+2*3

Друк

Ви не можете безпосередньо друкувати що-небудь в цинку. Результат наступного виразу inбуде надруковано. Значення набору будуть зв'язані з роздільником. Наприклад, візьміть це:

let
...
in expr

Якщо exprцей параметр встановлений {1, 3, {2, 4}}, 1324він буде надрукований на екран, коли програма закінчиться.

Збираючи все це разом

Ось проста програма з цинком, яка, здається, додає, 2+2але спричиняє результат 5:

let
x+y=1+:x+:y
in 1+2

Перекладач

Це стосується bin/zinc.dart:

import 'package:parsers/parsers.dart';
import 'dart:io';

// An error.
class Error implements Exception {
  String cause;
  Error(this.cause);
  String toString() => 'error in Zinc script: $cause';
}


// AST.
class Node {
  Obj interpret(ZincInterpreter interp) => null;
}

// Identifier.
class Id extends Node {
  final String id;
  Id(this.id);
  String toString() => 'Id($id)';
  Obj interpret(ZincInterpreter interp) => interp.getv(id);
}

// Integer literal.
class IntLiteral extends Node {
  final int value;
  IntLiteral(this.value);
  String toString() => 'IntLiteral($value)';
  Obj interpret(ZincInterpreter interp) => new IntObj(value);
}

// Any kind of operator.
class Anyop extends Node {
  void set(ZincInterpreter interp, OpFuncType func) {}
}

// Operator.
class Op extends Anyop {
  final String op;
  final bool orig;
  Op(this.op, [this.orig = false]);
  String toString() => 'Op($op, $orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0[op] : interp.op1[op];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}

// Unary operator (len).
class Lenop extends Anyop {
  final bool orig;
  Lenop([this.orig = false]);
  String toString() => 'Lenop($orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0['#'] : interp.op1['#'];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}

// Magic operator.
class Magicop extends Anyop {
  final String op;
  Magicop(this.op);
  String toString() => 'Magicop($op)';
  Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
    if (op == 'cut') {
      if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
      if (x is IntObj) {
        return new SetObj(x.value.toString().split(y.value.toString()).map(
          int.parse));
      } else {
        assert(x is SetObj);
        List<List<Obj>> res = [[]];
        for (Obj obj in x.vals(interp)) {
          if (obj == y) { res.add([]); }
          else { res.last.add(obj); }
        }
        return new SetObj(new List.from(res.map((l) =>
          l.length == 1 ? l[0] : new SetObj(l))));
      }
    } else if (op == 'join') {
      if (x is! SetObj) { throw new Error('can only join set'); }
      if (y is! IntObj) { throw new Error('can only join set with int'); }
      String res = '';
      for (Obj obj in x.vals(interp)) {
        if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
        res += obj.value.toString();
      }
      return new IntObj(int.parse(res));
    }
  }
}

// Unary operator (len) expression.
class Len extends Node {
  final Lenop op;
  final Node value;
  Len(this.op, this.value);
  String toString() => 'Len($op, $value)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, value.interpret(interp), null);
}

// Binary operator expression.
class Binop extends Node {
  final Node lhs, rhs;
  final Op op;
  Binop(this.lhs, this.op, this.rhs);
  String toString() => 'Binop($lhs, $op, $rhs)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}

// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
  final ClauseKind kind;
  final Node expr;
  Clause(this.kind, this.expr);
  String toString() => 'Clause($kind, $expr)';
  Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
    List<Obj> res = [];
    List<Obj> values = set.vals(interp);
    switch (kind) {
    case ClauseKind.Where:
      for (int i=0; i<values.length; i++) {
        Obj obj = values[i];
        interp.push_scope();
        interp.setv(id.id, obj);
        interp.setv('_', new IntObj(i));
        Obj x = expr.interpret(interp);
        interp.pop_scope();
        if (x is IntObj) {
          if (x.value != 0) { res.add(obj); }
        } else { throw new Error('where clause condition must be an integer'); }
      }
      break;
    case ClauseKind.Sort:
      res = values;
      res.sort((x, y) {
        interp.push_scope();
        interp.setv(id.id, x);
        Obj x_by = expr.interpret(interp);
        interp.setv(id.id, y);
        Obj y_by = expr.interpret(interp);
        interp.pop_scope();
        if (x_by is IntObj && y_by is IntObj) {
          return x_by.value.compareTo(y_by.value);
        } else { throw new Error('sort clause result must be an integer'); }
      });
      break;
    }
    return new SetObj(new List.from(res.reversed));
  }
}

// Set comprehension.
class SetComp extends Node {
  final Id id;
  final Node set;
  final Clause clause;
  SetComp(this.id, this.set, this.clause);
  String toString() => 'SetComp($id, $set, $clause)';
  Obj interpret(ZincInterpreter interp) {
    Obj setobj = set.interpret(interp);
    if (setobj is SetObj) {
      return clause.interpret_with(interp, setobj, id);
    } else { throw new Error('set comprehension rhs must be set type'); }
  }
}

// Operator rewrite.
class OpRewrite extends Node {
  final Anyop op;
  final Node value;
  final Id lid, rid; // Can be null!
  OpRewrite(this.op, this.value, [this.lid, this.rid]);
  String toString() => 'OpRewrite($lid, $op, $rid, $value)';
  Obj interpret(ZincInterpreter interp) {
    if (lid != null) {
      // Not bare.
      op.set(interp, (interp,x,y) {
        interp.push_scope();
        interp.setv(lid.id, x);
        if (rid == null) { assert(y == null); }
        else { interp.setv(rid.id, y); }
        Obj res = value.interpret(interp);
        interp.pop_scope();
        return res;
      });
    } else {
      // Bare.
      if (value is Magicop) {
        op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
      } else {
        op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
      }
    }
    return null;
  }
}

class Program extends Node {
  final List<OpRewrite> rws;
  final Node expr;
  Program(this.rws, this.expr);
  String toString() => 'Program($rws, $expr)';
  Obj interpret(ZincInterpreter interp) {
    rws.forEach((n) => n.interpret(interp));
    return expr.interpret(interp);
  }
}


// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);

class Obj {}

class IntObj extends Obj {
  final int value;
  IntObj(this.value);
  String toString() => 'IntObj($value)';
  bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
  String dump() => value.toString();
}

class SetObj extends Obj {
  final List<Obj> values;
  SetObj(this.values) {
    if (values.length == 0) { throw new Error('set cannot be empty'); }
  }
  String toString() => 'SetObj($values)';
  bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
  String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
  List<Obj> vals(ZincInterpreter interp) {
    Obj lenobj = interp.op1['#'](interp, this, null);
    int len;
    if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
    len = lenobj.value;
    if (len < 0) { throw new Error('result of # operator must be positive'); }
    return new List<Obj>.from(values.getRange(0, len));
  }
}


// Parser.
class ZincParser extends LanguageParsers {
  ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
  get start => prog().between(spaces, eof);
  get comma => char(',') < spaces;
  get lp => symbol('(');
  get rp => symbol(')');
  get lb => symbol('{');
  get rb => symbol('}');
  get colon => symbol(':');
  get plus => symbol('+');
  get minus => symbol('-');
  get star => symbol('*');
  get slash => symbol('/');
  get eq => symbol('=');
  get len => symbol('#');
  get in_ => char(':');
  get where => char('^');
  get sort => char('\$');

  prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
            (_1,o,_2,x) => new Program(o,x);
  oprw() => oprw1() | oprw2() | oprw3();
  oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
             (o,_,r) => new OpRewrite(o,r);
  oprw2() => (id() + op() + id()).list + eq + expr() ^
             (l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
  oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
  magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
  basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
  op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
  lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
             len ^ (_) => new Lenop();
  expr() => setcomp() | unop() | binop() | prim();
  setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
               (_1,i,_2,x,c,_3) => new SetComp(i,x,c);
  clausekind() => (where ^ (_) => ClauseKind.Where) |
                  (sort  ^ (_) => ClauseKind.Sort);
  clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
  unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
  binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
  prim() => id() | intlit() | parens(rec(expr));
  id() => identifier ^ (i) => new Id(i);
  intlit() => intLiteral ^ (i) => new IntLiteral(i);
}


// Interpreter.
class ZincInterpreter {
  Map<String, OpFuncType> op0, op1;
  List<Map<String, Obj>> scopes;
  ZincInterpreter() {
    var beInt = (v) {
      if (v is IntObj) { return v.value; }
      else { throw new Error('argument to binary operator must be integer'); }
    };
    op0 = {
      '+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
      '-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
      '*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
      '/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
      '=': (_,x,y) => new IntObj(x == y ? 1 : 0),
      '#': (i,x,_2) =>
        new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
    };
    op1 = new Map<String, OpFuncType>.from(op0);
    scopes = [{}];
  }

  void push_scope() { scopes.add({}); }
  void pop_scope() { scopes.removeLast(); }
  void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
  Obj getv(String name) {
    for (var scope in scopes.reversed) {
      if (scope[name] != null) { return scope[name]; }
    }
    if (name == 'S') {
      var input = stdin.readLineSync() ?? '';
      var list = new List.from(input.codeUnits.map((c) =>
        new IntObj(int.parse(new String.fromCharCodes([c])))));
      setv('S', new SetObj(list));
      return getv('S');
    } else throw new Error('undefined variable $name');
  }
}


void main(List<String> args) {
  if (args.length != 1) {
    print('usage: ${Platform.script.toFilePath()} <file to run>');
    return;
  }
  var file = new File(args[0]);
  if (!file.existsSync()) {
    print('cannot open ${args[0]}');
    return;
  }
  Program root = new ZincParser().start.parse(file.readAsStringSync());
  ZincInterpreter interp = new ZincInterpreter();
  var res = root.interpret(interp);
  print(res.dump());
}

Це стосується pubspec.yaml:

name: zinc
dependencies:
  parsers: any

Задумане рішення

let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}

1
Я правильно розумію, що набори впорядковані і можуть мати дублікати, тому вони в основному є списками? Крім того, якщо я joinзмішаний набір, як {1,{3,2}}, чи буде помилка? Я не можу зараз встановити Dart, тому не можу перевірити себе.
Згарб

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

Як запустити перекладача? Якщо я просто спробую, dart bin/zinc.dart test.zncя отримую синтаксичну помилку: 'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'...var input = stdin.readLineSync() ?? '';
Мартін Ендер


1
@ Zgarb Пригадайте, коли в специфікації я сказав, що всі вбудовані операції, крім рівності, використовують оператор довжини? Я переосмислив його, щоб повернутись, -2+#:Sколи дано S, що відрізало дві задні нулі. Саме так я сподівався, що це буде вирішено. І ^не слід змінювати набір ... це була помилка ...
kirbyfan64sos

5

Суп з компасом ( розламується cardboard_box )

Перекладач: C ++

Компасовий суп - це на зразок машини Тюрінга з нескінченною двовимірною стрічкою. Основна увага полягає в тому, що пам'ять інструкцій та пам'ять даних знаходяться в одному просторі, а вихід програми - весь вміст цього простору.

введіть тут опис зображення

Як це працює

Програма - це двовимірний блок тексту. Простір програми починається з усього вихідного коду, розміщеного з першим символом у (0,0). Решта програмного простору нескінченна і ініціалізується нульовими символами (ASCII 0).

Є два покажчики, які можуть переміщатися по програмному простору:

  • Вказівник виконання має місце та напрямок (Північ, Південь, Схід чи Захід). Кожна галочка, інструкція під покажчиком виконання, виконується, потім покажчик виконання переміщується у своєму поточному напрямку. Вказівник виконання починає рухатися на схід (додатний х), у місці знаходження! знака або у (0,0), якщо цього немає.
  • Покажчик даних має лише розташування. Він переміщається з інструкціями x, X, y, і Y. Він починається з розташування @символу або з (0,0), якщо цього не існує.

Вхідні дані

Вміст stdin друкується в програмному просторі, починаючи з розташування >символу, або з (0,0), якщо цього не існує.

Вихідні дані

Програма припиняється, коли покажчик виконання безповоротно виходить за межі. Вихід - це весь вміст програмного простору на той час. Він надсилається до stdout та 'result.txt'.

Інструкції

  • n - перенаправляє покажчик виконання North (мінус y)
  • e - перенаправляє покажчик виконання East (позитивний х)
  • s - перенаправляє покажчик виконання South (позитивний y)
  • w - перенаправляє покажчик виконання West (мінус x)
  • y - переміщує покажчик даних на північ (мінус у)
  • X - переміщує покажчик даних на схід (позитивний х)
  • Y - переміщує покажчик даних на південь (позитивний у)
  • x - переміщує покажчик даних на захід (мінус х)
  • p- пише наступний символ, з яким стикається вказівник виконання на покажчик даних. Цей символ не виконується як інструкція.
  • j- перевіряє наступний символ, з яким стикається покажчик виконання, проти символу під покажчиком даних. Цей символ не виконується як інструкція. Якщо вони однакові, покажчик виконання переходить через наступний символ.
  • c - записує нульовий символ у покажчик даних.
  • * - точка розриву - просто спричиняє розрив перекладача.

Усі інші символи ігноруються покажчиком виконання.

Перекладач

Інтерпретатор приймає вихідний файл як аргумент і вводить на stdin. У ньому є ступінчастий налагоджувач, до якого ви можете викликати інструкцію точки перерви в коді ( *). При порушенні покажчик виконання показаний як ASCII 178 (темніший затінений блок), а покажчик даних показаний як ASCII 177 (світліший затінений блок).

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

// Compass Soup programming language interpreter
// created by Brian MacIntosh (BMacZero)
// for https://codegolf.stackexchange.com/questions/61804/create-a-programming-language-that-only-appears-to-be-unusable
//
// 31 October 2015

struct Point
{
    int x, y;
    Point(int ix, int iy) { x = ix; y = iy; };
    bool operator==(const Point &other) const
    {
        return other.x == x && other.y == y;
    }
    bool operator!=(const Point &other) const
    {
        return other.x != x || other.y != y;
    }
};

struct Bounds
{
    int xMin, xMax, yMin, yMax;
    Bounds(int xmin, int ymin, int xmax, int ymax)
    {
        xMin = xmin; yMin = ymin; xMax = xmax; yMax = ymax;
    }
    bool contains(Point pt)
    {
        return pt.x >= xMin && pt.x <= xMax && pt.y >= yMin && pt.y <= yMax;
    }
    int getWidth() { return xMax - xMin + 1; }
    int getHeight() { return yMax - yMin + 1; }
    bool operator==(const Bounds &other) const
    {
        return other.xMin == xMin && other.xMax == xMax && other.yMin == yMin && other.yMax == yMax;
    }
    bool operator!=(const Bounds &other) const
    {
        return other.xMin != xMin || other.xMax != xMax || other.yMin != yMin || other.yMax != yMax;
    }
};

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

Bounds hull(Point a, Bounds b)
{
    return Bounds(min(a.x, b.xMin), min(a.y, b.yMin), max(a.x, b.xMax), max(a.y, b.yMax));
}

Bounds hull(Bounds a, Bounds b)
{
    return Bounds(min(a.xMin, b.xMin), min(a.yMin, b.yMin), max(a.xMax, b.xMax), max(a.yMax, b.yMax));
}

Bounds programBounds(0,0,0,0);
char** programSpace;

Point execPtr(0,0);
Point execPtrDir(1,0);
Point dataPtr(0,0);
Point stdInPos(0,0);

bool breakpointHit = false;
char breakOn = 0;

/// reads the character from the specified position
char read(Point pt)
{
    if (programBounds.contains(pt))
        return programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin];
    else
        return 0;
}

/// read the character at the data pointer
char readData()
{
    return read(dataPtr);
}

/// read the character at the execution pointer
char readProgram()
{
    return read(execPtr);
}

/// gets the bounds of the actual content of the program space
Bounds getTightBounds(bool debug)
{
    Bounds tight(0,0,0,0);
    for (int x = programBounds.xMin; x <= programBounds.xMax; x++)
    {
        for (int y = programBounds.yMin; y <= programBounds.yMax; y++)
        {
            if (read(Point(x, y)) != 0)
            {
                tight = hull(Point(x, y), tight);
            }
        }
    }
    if (debug)
    {
        tight = hull(dataPtr, tight);
        tight = hull(execPtr, tight);
    }
    return tight;
}

/// ensure that the program space encompasses the specified rectangle
void fitProgramSpace(Bounds bounds)
{
    Bounds newBounds = hull(bounds, programBounds);

    if (newBounds == programBounds) return;

    // allocate new space
    char** newSpace = new char*[newBounds.getWidth()];

    // copy content
    for (int x = 0; x < newBounds.getWidth(); x++)
    {
        newSpace[x] = new char[newBounds.getHeight()];
        for (int y = 0; y < newBounds.getHeight(); y++)
        {
            Point newWorldPos(x + newBounds.xMin, y + newBounds.yMin);
            newSpace[x][y] = read(newWorldPos);
        }
    }

    // destroy old space
    for (int x = 0; x < programBounds.getWidth(); x++)
    {
        delete[] programSpace[x];
    }
    delete[] programSpace;

    programSpace = newSpace;
    programBounds = newBounds;
}

/// outputs the current program space to a file
void outputToStream(std::ostream &stream, bool debug)
{
    Bounds tight = getTightBounds(debug);
    for (int y = tight.yMin; y <= tight.yMax; y++)
    {
        for (int x = tight.xMin; x <= tight.xMax; x++)
        {
            char at = read(Point(x, y));
            if (debug && x == execPtr.x && y == execPtr.y)
                stream << (char)178;
            else if (debug && x == dataPtr.x && y == dataPtr.y)
                stream << (char)177;
            else if (at == 0)
                stream << ' ';
            else
                stream << at;
        }
        stream << std::endl;
    }
}

/// writes a character at the specified position
void write(Point pt, char ch)
{
    fitProgramSpace(hull(pt, programBounds));
    programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin] = ch;
}

/// writes a character at the data pointer
void write(char ch)
{
    write(dataPtr, ch);
}

/// writes a line of text horizontally, starting at the specified position
void writeLine(Point loc, std::string str, bool isSource)
{
    fitProgramSpace(Bounds(loc.x, loc.y, loc.x + str.size(), loc.y));
    for (unsigned int x = 0; x < str.size(); x++)
    {
        programSpace[x + loc.x][loc.y] = str[x];

        // record locations of things
        if (isSource)
        {
            switch (str[x])
            {
            case '>':
                stdInPos = Point(loc.x + x, loc.y);
                break;
            case '!':
                execPtr = Point(loc.x + x, loc.y);
                break;
            case '@':
                dataPtr = Point(loc.x + x, loc.y);
                break;
            }
        }
    }
}

void advanceExecPtr()
{
    execPtr.x += execPtrDir.x;
    execPtr.y += execPtrDir.y;
}

void breakpoint()
{
    breakpointHit = true;
    outputToStream(std::cout, true);
    std::cout << "[Return]: step | [Space+Return]: continue | [<char>+Return]: continue to <char>" << std::endl;
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.size() == 0)
        {
            break;
        }
        else if (input.size() == 1)
        {
            if (input[0] == ' ')
            {
                breakpointHit = false;
                break;
            }
            else
            {
                breakOn = input[0];
                breakpointHit = false;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("Usage: CompassSoup <source-file>");
        return 1;
    }

    // open source file
    std::ifstream sourceIn(argv[1]);

    if (!sourceIn.is_open())
    {
        printf("Error reading source file.");
        return 1;
    }

    programSpace = new char*[1];
    programSpace[0] = new char[1];
    programSpace[0][0] = 0;

    // read starting configuration
    std::string line;
    int currentLine = 0;
    while (std::getline(sourceIn, line))
    {
        writeLine(Point(0, currentLine), line, true);
        currentLine++;
    }

    sourceIn.close();

    // take stdin
    std::string input;
    std::cout << ">";
    std::cin >> input;
    std::cin.ignore();
    writeLine(stdInPos, input, false);

    // execute
    while (programBounds.contains(execPtr))
    {
        if (execPtrDir.x == 0 && execPtrDir.y == 0)
        {
            printf("Implementation error: execPtr is stuck.");
            break;
        }

        advanceExecPtr();

        char command = readProgram();

        // breakpoint control code
        if (breakpointHit || (breakOn != 0 && command == breakOn))
        {
            breakOn = 0;
            breakpoint();
        }

        switch (command)
        {
        case 'n':
            execPtrDir = Point(0,-1);
            break;
        case 'e':
            execPtrDir = Point(1,0);
            break;
        case 's':
            execPtrDir = Point(0,1);
            break;
        case 'w':
            execPtrDir = Point(-1,0);
            break;
        case 'x':
            dataPtr.x--;
            break;
        case 'X':
            dataPtr.x++;
            break;
        case 'y':
            dataPtr.y--;
            break;
        case 'Y':
            dataPtr.y++;
            break;
        case 'p':
            advanceExecPtr();
            write(readProgram());
            break;
        case 'j':
            advanceExecPtr();
            if (readData() == readProgram())
            {
                advanceExecPtr();
            }
            break;
        case 'c':
            write(0);
            break;
        case '*':
            breakpoint();
            break;
        }
    }

    std::ofstream outputFile("result.txt");
    outputToStream(outputFile, false);
    outputToStream(std::cout, false);
    outputFile.close();
}

Приклади

Привіт Світ

Hello, World!

Кіт

>

Паритет: приймає рядок символів, що закінчується нулем ('0'). Виводи yesв першому рядку виводу, якщо число 1s на вході непарне, інакше виводиться |.

|>
!--eXj1s-c-eXj0s-c-exj|s-pyXpeXps
   c   |   c   |   |   |
  cn0j-w---n1j-w   n---w

Поради

Ви повинні використовувати хороший текстовий редактор і розумно використовувати функціональність клавіші "Вставити", а також використовувати "Alt-Drag", щоб додати або видалити текст одночасно в декількох рядках.

Рішення

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

Мій підхід полягав у тому, щоб розділити різні послідовності 1s на різні лінії, потім сортувати їх, щоб 1всі "падали", поки вони не потрапили на інший 1, і, нарешті, стерти все, крім третього рядка після введення.

  • Великий блок праворуч внизу #A#читає 1s і копіює їх в останній рядок розділення, поки не 0буде прочитано a .
  • #B#перевіряє на секунду 0і йде на північ#D# там є. В іншому випадку #C#починається нова лінія розбиття, вводячи |після останньої, і повертається до #A#.
  • Блок в і вище #F#- це гравітаційний код. Він підходить до останнього 1першого ряду і переміщує його вгору, поки не потрапить 1або -. Якщо він не може цього зробити, він позначає рядок як закінчений, поставивши +перед ним.
  • #G#видаляє всі непотрібні розбиття і #H#стирає stdin та весь код між дужками.

Код:

 s-----------------------w
 s-c-w  s-c-w  s---w    e+-
 eXj)nc-eXj)nc-exj(ncyj(nn
(n-----------------------------------------w                      ))
(  #H#                             s---w   |                      ))
(                                  exj+ncyxn                      ))
(                                  |                              ))
(                      s---w   s-c-+w                             ))
(                      exj+ncy-eXj1nn                             ))
(                      |                                          ))
(         s---w    s-c-+w    s+pxw                                ))
(         eyj-n-YY-eXj1nn    |  sn1jX--w           e----s         ))
(         |                  Y  x     e+---s e---s ns1jyw         ))
(      ej+n------s           j  |     nn+jYw-n+jxw-Yw   |         ))
(      Y   ec----s      e---s|  |                       1         ))
(      c   ns1jX-wYcYYY-n-jyww  |                       p         ))
(      ns+jxw      #G#       e--s                       Y         ))
(       e---n                   |               s------w|         ))
(                               |               |   ej-nn         ))
(             s--w              e----s   exc----eyj1n---n         ))
(#A#          p e+---s   s---w       |#F#|                        ))
(e----se---s  1 ||   |   exj|n----p+YeXj1ns                       ))
(ns-jXwn-jyw--w-nn1jXw   c #D#       n----w                       ))
( |        |         |   |                                        ))
( |        n---------+---+-------------|pw            s---w s---w ))
( |                  |   |     exp)XYs   |            eyj-nYeXj0ns)
( |         s---ws---+w  n-----+-----+---+------------+----------w))
( |         |   ||   ||  e--yp)n     e---+--s         |           )
( |     e-c-exj|neYj|nn  |     #C#       |  |         p           ))
( |     |                |     s---w s---+w s---w s---+w          ))
( |     |          #B#  e+s    |   | |   || |   | |   ||          ))
(!ep-Yj0n-c----------Xj0nne----exj|n-eYj|nn exj|n-eYj|nn          ))
(-@
 |>


Дарн, так близько! Я поділюсь своїм рішенням, коли сьогодні приїду додому.
BMac

Я не можу заставити програму паритету працювати. Чи повинна бути інструкція з налагодження на початку? Якщо я переступаю через нього, він застряє в нескінченному циклі, будь-яка ідея, що я можу робити не так?
feersum

Схоже, cна початку з’явилося зайве, яке не повинно було бути там. Я виправив це. Також додав моє рішення проблеми.
BMac

4

Acc! , Cracc'd від ppperry

Ця мова має одну циклічну структуру, основну математику цілочисельних чисел, символів вводу / виводу та акумулятор (таким чином, назва). Тільки один акумулятор. Таким чином, назва.

Заяви

Команди аналізуються за рядком. Існує три типи команд:

  1. Count <var> while <cond>

Графи <var>вгору від 0 до тих пір , як НЕ <cond>дорівнює нулю, що еквівалентно C-стилі for(<var>=0; <cond>; <var>++). Лічильником циклу може бути будь-яка одна маленька літера. Умовою може бути будь-який вираз, не обов'язково включаючи змінну циклу. Цикл припиняється, коли значення умови стає 0.

Петлі вимагають фігурних брекетів у стилі K&R (зокрема, варіант Stroustrup ):

Count i while i-5 {
 ...
}
  1. Write <charcode>

Виводить один символ із заданим значенням ASCII / Unicode для stdout. Шаркодом може бути будь-який вираз.

  1. Вираз

Будь-який вираз, що стоїть сам по собі, оцінюється і присвоюється назад акумулятору (який доступний як _). Так, наприклад, 3це твердження, яке встановлює акумулятор 3; _ + 1збільшує акумулятор; і _ * Nчитає персонаж і помножує акумулятор на його код.

Примітка: акумулятор - єдина змінна, до якої можна безпосередньо призначити; змінні циклу і Nможуть використовуватися в обчисленнях, але не змінюватися.

Акумулятор спочатку дорівнює 0.

Вирази

Вираз може включати цілі літерали, змінні циклу ( a-z), _для акумулятора, і спеціальне значенняN , яке читає символ і оцінює його штрих-код кожного разу, коли воно використовується. Примітка. Це означає, що ви можете прочитати лише один кадр; при наступному використанні Nви прочитаєте наступний.

Оператори:

  • +, доповнення
  • -, віднімання; одинарне заперечення
  • *, множення
  • /, ціле ділення
  • %, модуль
  • ^, експоненція

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

Пробіли та коментарі

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

# починається однорядковий коментар.

Введення-виведення

Acc! очікує введення одного рядка символів. Кожен вхідний символ можна отримати в послідовності, а його штрих-код обробити за допомогою N. Спроба прочитати останній символ рядка викликає помилку. Символ може бути виведений, передавши його charcode до Writeзаяви.

Перекладач

Перекладач (написаний Python 3) перекладає Acc! код в Python і execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                if loopVar is not None:
                    pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()


3

GoToTape (безпечно)

(Раніше знали як Simp-plex.)

Ця мова проста. Основним контролем потоку є гото, найбільш природна і корисна форма контролю.

Специфікація мови

Дані зберігаються на стрічці та в акумуляторі. Він працює повністю з непідписаними інтегратами. Кожен символ - це команда. Нижче наведено всі команди:

  • Букви: a- - zце goto заяви, що йдуть A- Zвідповідно.
  • :: встановіть акумулятору значення ASCII в знак char від введення.
  • ~: вивести значення char для значення ASCII в акумуляторі.
  • &: відняти один з акумулятора, якщо він 1 або більше, інакше додати його.
  • |: додайте його до акумулятора.
  • <: встановити покажчик даних на 0.
  • +: збільшення клітинки даних на покажчик даних; перемістіть покажчик +1.
  • -: відніміть одне з комірки даних за покажчиком даних, якщо він є позитивним; перемістіть покажчик +1.
  • [...]: запустити код n разів, де n - номер на стрічці за вказівником даних (не можна вкладати).
  • /: пропустити наступну інструкцію, якщо акумулятор 0.

Перекладач (C ++)

#include <iostream>
#include <memory.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int serch(char* str,char ch){
    for(int i = 0;str[i];i++){
        if(str[i]==ch)
            return i;
    }
    return -1;
}

void runCode(char* code){
    int i = 0;
    char c;
    unsigned int* tape;
    tape = new unsigned int[1000003];
    memset(tape,0,1000003*sizeof(int));
    unsigned int p=0;
    unsigned int a=0;
    unsigned int n;
    unsigned int s;

    while(c=code[i]){
        if('A'<=c && c<='Z');
        if('a'<=c && c<='z')i=serch(code, c+'A'-'a');
        if(':'==c)a=cin.get();
        if('+'==c)tape[p++]++;
        if('-'==c)tape[p++] += tape[p]?-1:0;
        if('|'==c)a++;
        if('&'==c)a=a?a-1:1;
        if('<'==c)p=0;
        if('['==c){if(tape[p]){n=tape[p];s=i;}else i+=serch(code+i,']');};
        if(']'==c)i=--n?i:s;
        if('~'==c)cout<<(char)a;
        if('/'==c)i+=a?0:1;
        if('$'==c)p=a;
        i++;
    }
    delete[](tape);
}

int main(int argc, char* argv[]) {
    if(argc == 2){

        ifstream sorceFile (argv[1]);
        string code(static_cast<stringstream const&>(stringstream() << sorceFile.rdbuf()).str());
        runCode((char*)code.c_str());
    }else
        cout << "Code file must be included as a command-line argument \n";
    return 0;
}

Веселіться!

Рішення

A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e


2
Ваше кодування C ++ вбиває мене! Чи є причина, яку ви використовували callocзамість new char, писали цикл стилю while, використовували управління пам’яттю у стилі C, змушували нас перекомпілювати файл C ++ щоразу, коли ми змінювали код, і використовували 20 ifs замість a switch? Я не
скаржусь

3
Я закріпив цяточку до м’яса перекладача.
MegaTom

@ kirbyfan64sos Код поганий. Я якось швидко це склав, і, можливо, не зробив це так добре, як я повинен. основну функцію можна змінити, щоб взяти код як вхідний. насправді я думаю, що зараз це зроблю ...
MegaTom

1
Питання говорить, що перекладачі повинні приймати ім'я файлу в командному рядку програми .
Денніс

Ось кілька коротких способів читання файлу в рядок . Потім зателефонуйте, str.c_str()щоб отримати char*.
feersum

0

Це було поганою ідеєю, оскільки майже всі езотеричні мови виглядають нечитатими (дивіться на Jelly).
Але ось що:

Pylongolf2 beta6

Натискання на стек

Натискання на стек діє інакше, ніж в інших мовах.
Код 78штовхає 7і 8в стек, однак в Pylongolf він штовхає 78.
У Pylongolf2 це можна змінити Ü.

Команди

) Print the stack.
Ü Toggle the method Pylongolf2 uses for pushing to stack.
a The useless command, removes and adds the selected item in the same place.
c Ask for input.
n Convert string to a number.
" Toggle string mode for pushing text to the stack.
s Convert a number to a string. ╨ Encode the selected item (it must be a string).
_ Duplicate the selected item next to itself.
b Swap places between the selected item and the one before.
d Set the selected item to the last one.
m Move the selected item to the end of the stack.
@ Select an item. (Number required after this command as an argument).
w Wait a specified amount of time (the time is taken from the stack).
= Compare the selected item to the one before. (WARNING. THIS DELETES THE 2 ITEMS AND PLACES A true OR A false) (V2 beta)
~ Print the stack nicely. (V2 beta)
² Square a number. (V3 beta)
| Split a string to an array by the character after |. (V4 beta)
♀ Pop the array. (the contents are left in the stack) (V4 beta)
> Begin a while statement. (V5 beta)
< Loop back to the beginning of the while statement. (V5 beta)
! Break out of the while statements. (V5 beta)
? An if statement, does nothing if the selected item is a `true` boolean. (V6 beta)
¿ If an if statement is `false`, the interpreter skips everything to this character. (V6 beta)

Об'єднання рядків та вилучення візерунка Regex з рядка

Символ + об'єднує рядки.
Ви можете використовувати символ - для видалення символів, що слідують за схемою регулярного вираження, з рядка:

c╨2"[^a-zA-Z]"-~

Цей код приймає введення та видаляє всі не алфавітні символи, видаляючи всі відповідні шаблони [^a-zA-Z].
Вибраний елемент повинен бути регулярним виразом, а попередній повинен бути рядком для редагування.

Якщо заяви

Якщо робити заяви, поставте а, =щоб порівняти вибраний елемент і той, що після.
Це розміщує або його, trueабо falseйого місце.
Команда ?перевіряє цей булів.
Якщо це trueтоді, він нічого не робить, і перекладач продовжує працювати.
Якщо це, falseто перекладач переходить до найближчого ¿персонажа.

Взяті зі сторінки Github.

Перекладач для Pylongolf2 (Java):

package org.midnightas.pylongolf2;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Pylongolf {

    public static final void main(String[] args) throws Exception {
        String content = new String(Files.readAllBytes(Paths.get(new File(args[0]).toURI()))) + " ";
        boolean fullreadMode = true;
        List<Object> stack = new ArrayList<Object>();
        List<Integer> whileStatements = new ArrayList<Integer>();
        HashMap<String, Object> vars = new HashMap<String, Object>();
        int ifStatements = 0;
        Scanner scanner = new Scanner(new UnclosableDecorator(System.in));
        int selectedIndex = 0;
        for (int cl = 0; cl < content.length(); cl++) {
            char c = content.charAt(cl);
            if (isNumber(c)) {
                if (!fullreadMode) {
                    stack.add(Double.parseDouble(c + ""));
                } else {
                    String number = "";
                    for (int cl0 = cl; cl0 < content.length(); cl0++) {
                        if (isNumber(content.charAt(cl0))) {
                            number += content.charAt(cl0);
                        } else {
                            cl = cl0 - 1;
                            stack.add(Double.parseDouble(number));
                            break;
                        }
                    }
                }
            } else if (c == ')') {
                System.out.println(Arrays.toString(stack.toArray()));
            } else if (c == 'Ü') {
                fullreadMode = !fullreadMode;
            } else if (c == '+') {
                if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Double dbl = new Double(0d);
                    for (Object o : obj) {
                        dbl += (Double) o;
                    }
                    stack.add(selectedIndex, dbl);
                } else {
                    Object obj0 = stack.remove(selectedIndex);
                    Object obj1 = stack.remove(selectedIndex);
                    if (obj0 instanceof Number && obj1 instanceof Number)
                        stack.add(((Number) obj0).doubleValue() + ((Number) obj1).doubleValue());
                    else if (obj0 instanceof String) {
                        stack.add(obj0.toString() + obj1.toString());
                    }
                }
            } else if (c == '-') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() - ((Number) obj1).doubleValue());
                else if (obj0 instanceof String && obj1 instanceof String) {
                    stack.add(obj0.toString().replaceAll(obj1.toString(), ""));
                }
            } else if (c == '*') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() * ((Number) obj1).doubleValue());
            } else if (c == '/') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() / ((Number) obj1).doubleValue());
            } else if (c == 'a') {
                stack.add(selectedIndex, stack.remove(selectedIndex));
            } else if (c == 'c') {
                stack.add(scanner.nextLine());
            } else if (c == 'n') {
                if (stack.get(selectedIndex) instanceof String) {
                    stack.add(selectedIndex, Double.parseDouble(stack.remove(selectedIndex).toString()));
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] oldArray = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[oldArray.length];
                    for (int i = 0; i < oldArray.length; i++) {
                        newArray[i] = Double.parseDouble(oldArray[i].toString());
                    }
                    stack.add(selectedIndex, newArray);
                }
            } else if (c == '"') {
                String string = "\"";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    string = string + content.charAt(cl0);
                    if (content.charAt(cl0) == '"') {
                        stack.add(string.substring(1, string.length() - 1));
                        cl = cl0;
                        break;
                    }
                }
            } else if (c == 's') {
                Object obj = stack.remove(selectedIndex);
                if (obj instanceof Double) {
                    Double dbl = (Double) obj;
                    if (dbl.doubleValue() == Math.floor(dbl)) {
                        stack.add(selectedIndex, "" + dbl.intValue() + "");
                    } else {
                        stack.add(selectedIndex, "" + dbl + "");
                    }
                }
            } else if (c == '╨') {
                cl++;
                char editmode = content.charAt(cl);
                if (editmode == '0') {
                    stack.add(selectedIndex, rot13(stack.remove(selectedIndex).toString()));
                } else if (editmode == '1') {
                    stack.add(selectedIndex,
                            new StringBuilder(stack.remove(selectedIndex).toString()).reverse().toString());
                } else if (editmode == '2') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toLowerCase());
                } else if (editmode == '3') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toUpperCase());
                }
            } else if (c == '_') {
                stack.add(selectedIndex, stack.get(selectedIndex));
            } else if (c == 'b') {
                stack.add(selectedIndex + 1, stack.remove(selectedIndex));
            } else if (c == 'd') {
                selectedIndex = stack.size() == 0 ? 0 : stack.size() - 1;
            } else if (c == 'm') {
                stack.add(stack.remove(selectedIndex));
            } else if (c == '@') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        selectedIndex = Integer.parseInt(number);
                        break;
                    }
                }
            } else if (c == 'w') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        Thread.sleep(Long.parseLong(number));
                        break;
                    }
                }
            } else if (c == '=') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                stack.add(new Boolean(obj0.equals(obj1)));
            } else if (c == '~') {
                for (Object o : stack)
                    System.out.print(o);
                System.out.println();
            } else if (c == '²') {
                if (stack.get(selectedIndex) instanceof Double) {
                    Double dbl = (Double) stack.remove(selectedIndex);
                    stack.add(selectedIndex, dbl * dbl);
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[obj.length];
                    for (int i = 0; i < obj.length; i++) {
                        newArray[i] = Math.pow((Double) obj[i], 2);
                    }
                    stack.add((Object[]) newArray);
                }
            } else if (c == '|') {
                String string = (String) stack.remove(selectedIndex);
                cl++;
                char splitChar = content.charAt(cl);
                stack.add((Object[]) string.split(splitChar + ""));
            } else if (c == '♀') {
                for (Object obj : (Object[]) stack.remove(selectedIndex)) {
                    stack.add(selectedIndex, obj);
                }
            } else if (c == '>') {
                whileStatements.add(new Integer(cl));
            } else if (c == '<') {
                cl = whileStatements.get(whileStatements.size() - 1);
            } else if (c == '!') {
                whileStatements.remove(whileStatements.size() - 1);
            } else if (c == '?') {
                if (stack.get(selectedIndex) instanceof Boolean) {
                    Boolean bool = (Boolean) stack.remove(selectedIndex);
                    if (bool == false) {
                        ifStatements++;
                        for (int cl0 = cl; cl0 < content.length(); cl0++) {
                            if (content.charAt(cl0) == '¿') {
                                ifStatements--;
                                cl = cl0;
                            }
                        }
                    }
                }
            } else if (c == 't') {
                break;
            } else if (c == '(') {
                stack.remove(selectedIndex);
            } else if (c == ':') {
                cl++;
                char charToVar = content.charAt(cl);
                vars.put(charToVar + "", stack.remove(selectedIndex));
            } else if (c >= 'A' && c <= 'Z') {
                stack.add(vars.get(c + ""));
            } else if (c == 'r') {
                stack.add(selectedIndex,
                        (double) new Random().nextInt(((Double) stack.remove(selectedIndex)).intValue() + 1));
            }
        }
        scanner.close();
    }

    public static String rot13(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c >= 'a' && c <= 'm')
                c += 13;
            else if (c >= 'A' && c <= 'M')
                c += 13;
            else if (c >= 'n' && c <= 'z')
                c -= 13;
            else if (c >= 'N' && c <= 'Z')
                c -= 13;
            sb.append(c);
        }
        return sb.toString();
    }

    public static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

}

Це, мабуть, важко використовувати? : /
CalculatorFeline

0

Веселка (Примітка: Перекладач незабаром)

Я знаю, що цей виклик закінчився.

Веселка - це суміш ... багатьох речей.

Rainbow - це двовимірна мова на основі стека з двома стеками (як Brain-Flak) та 8 напрямками ( N NE E SE S SW W NW). Є 8 команд:

  • 1, +, *, "Робити те , що вони роблять в 1+.
  • ! перемикає активний стек.
  • > обертати IP за годинниковою стрілкою.
  • , введіть символ і натисніть його.
  • . вискакуйте та виведіть символ.

Однак символи у вихідному коді виконуються не відразу. Натомість [The Character in the source code]^[Top Of Stack]подається в штучку Collatz Conjecture, і кількість кроків, необхідних для досягнення 1, перетворюється в символ ASCII таблиці. Потім цей символ виконується.

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

На початку програми вихідний код (крім останнього символу) висувається на стек.

Коли IP доходить до краю вихідного коду, він припиняється.

Апокаліпсис

n і m - два регістри. Коли >виконується інструкція, m збільшується. Апокаліпсис спрацьовує лише у тому випадку, якщо m перевищує n. Коли відбувається Апокаліпсис, це:

  • Поверніть проти годинникової стрілки замість годинникової стрілки.
  • m стає 0.
  • n стає вершиною стека. А потім, стек вискакує.

m спочатку дорівнює нулю, а n спочатку є останнім символом вихідного коду.

Шифрування

Після виконання будь-якого виконання вихідний код шифрується. ASCII 1-го символу збільшується на одиницю, 2-й зменшується на один, третій збільшується на два, 4-й зменшується на два тощо.


1
майже впевнений, що вам потрібен перекладач, щоб ця відповідь була правдивою ...
Conor O'Brien

@ ConorO'Brien Оскільки цей виклик вже минув, це просто для задоволення. Я все ж надам перекладача.
HighlyRadioactive

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