Транспіляція WordMath


25

Ми всі бачили тих онлайн "математик хекс", які виглядають так:

Think of a number, divide by 2, multiply by 0, add 8.

І за магією всі закінчують цифру 8!


Мова

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

Think of a number, <commandlist>.

Що в основному означає: Візьміть число (як вхід від STDIN) як початковий акумулятор, виконайте всі команди на ньому та виведіть результат.

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

  • add #/ subtract #- Додавання / віднімання значення від акумулятора.
  • divide by #/ multiply by #- floordiv / помножте акумулятор на задане значення.
  • subtract from #- Схожий на subtract, але робить acc = # - accзамістьacc = acc - #
  • repeat- виконайте останню команду ще раз. Це не може бути першою командою, але ви повинні підтримувати кілька послідовних повторів.

Змагання

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

Наприклад, якщо мій код знаходиться в Python 2, а сценарій:

Think of a number, subtract from 10, add 10, multiply by 2.

Виведеною програмою можуть бути:

a = input()
a = 10 - a
a += 10
a *= 2
print(a)

Або в якості альтернативи:

print(((10-input())+10)*2)

Поки це повноцінна програма, яка бере вхід STDINі друкує вSTDOUT , або найближчі еквіваленти мови.


Правила

  • Ваша оригінальна програма може припустити, що вхід завжди є дійсним сценарієм WordMath.
  • Транспільовані програми не повинні обробляти математичні помилки, такі як поділ на 0.
  • Транспільовані програми можуть припускати, що вхід представляє дійсне підписане ціле число в межах стандартного цілого діапазону вашої мови.
  • Це , тому найкоротше рішення (у байтах) виграє.
  • Має значення лише кількість байтів вашої оригінальної програми - код, що виводиться, може бути скільки завгодно!

Приклади сценаріїв

Приклад 1:

Think of a number. 

Візьміть внесок, нічого не робіть, покажіть його: програма для кішок WordMath.

Приклад 2:

Think of a number, divide by 5, subtract from 9.

Пам'ятайте, що "ділити" - це поділ на підлогу, тому для цієї програми 6 -> 8і 29 -> 4.

Приклад 3:

Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.

Розширена програма для котів!

Приклад 4:

Think of a number, subtract 1, repeat, repeat.

Бере число і віднімає 3.


Чи потрібно підтримувати послідовні повтори?
darrylyeo

1
Чи можемо ми використовувати floats, коли це типовий тип мови / якщо він не підтримує цілих чисел?
Райнер П.

@RainerP. лише якщо мова не підтримує цілих чисел / цілого поділу
FlipTack

1
Який очікуваний результат -5/3? Ми обернемось 0до негативної нескінченності чи до неї?
Мартін Ендер

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

Відповіді:


6

05AB1E , 59 56 54 52 байт

„, ¡¦vyDþs.AJá'bK"dmas""/*+-"‡„-f„s-.:«D'rQi®}©}J'rK

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

Мій мозок болить як пекло після цього ... Він видає код 05AB1E наступним чином:

  • Think of a Number видаляється через неявне введення.
  • Subtract From #криють до #s-(підкачки aі bі виконати операцію).
  • Subtract #перетворюється в #-.
  • Add #перетворюється в #+.
  • Multiply by #перетворюється в #*.
  • Divide by #перетворюється в #/.
  • Repeat захоплює те, що востаннє зберігалося в реєстрі, і з'єднує його.

Пояснили:

„, ¡                                                 # Split on ', '.
    ¦                                                # Remove the 'Think of a number'.
     vy                                        }     # Loop through chunks.
       Dþs                                           # Dupe, push only digits, swap.
          .AJá                                       # Acronymify without digits.
              'bK                                    # Remove the `b`.
                 "dmas""/*+-"‡                       # Replace letters with OPs.
                              „-f„s-.:               # Replace '-f' with 's-'.
                                      «              # Concat # with OP.
                                       D'rQ          # Dupe, push 1 if OP='r'.
                                           i®}       # If 'r', push last #OP.
                                              ©      # Store current OP.
                                                J'rK # Join, remove remaining r's.

Приклад:

Вхід:

Think of a number, divide by 2, multiply by 10, add 8, subtract 6, subtract from 9, repeat, repeat, subtract 41.

Вихід:

2/10*8+6-9s-9s-9s-41-

Спробуйте рішення з введенням 10:

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

Подивіться це в google:

Ось посилання на те саме рівняння, яке введено в google.


13

C Препроцесор, 362 байт

Я ВДАЛУЮТЬ це працююче у ПРЕСТОРАЦІ С С, але команда повтору виявляється занадто складною для реалізації. Тому замість цього я використовував препроцесор, щоб перетворити вхід у масив, який потім інтерпретується деяким додатковим кодом.

main(){int c[]={
#define Think 
#define of
#define a
#define number 0
#define add 1,
#define subtract 2,
#define from 0,3,
#define multiply 4,
#define divide 5,
#define by
#define repeat 6, 0
#include "input.wm"
,'$'};int _,l,v;scanf("%d", &_);for(int i=1;c[i]-'$';++i){c[i]!=6?l=c[i],v=c[++i]:++i;l==1?_+=v:l==2?_-=v:l==3?_=v-_:l==4?_*=v:_/=v;}printf("%d",_);}

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

У будь-якому випадку, як тільки ви скидаєте джерело WordMath у input.wm, де компілятор може його знайти, ви повинні мати можливість просто компілювати це, як це є, з попередженнями, щоб створити виконуваний файл, який виконує те, що говорить джерело WordMath.


2
Примітка: це, на жаль, не вдається виконати деякі компілятори, коли ви закінчите з повтором. Це тому, що вони кидають пробіл після 0, а потім бачать період блукання і не знають, що з цим робити.
LambdaBeta

розумний, я вражений.
кіт

7

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

Бо хто б не хотів цього бачити ?!

Я подумав, як приголомшливо було б бачити рішення Retina, і вирішив створити його швидко. Це минуло лише годину. Як завжди, кількість байтів передбачає кодування ISO 8859-1.

S`, 
\.

T.*
.*¶$$*
\;+`(.*)¶rep.*(¶?)
$1¶$1$2
\d+
$*
.*f.* (1*)
1¶x¶$¶$1¶+`x1¶
m.* 
1¶
di.* (1*)
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)
^$1¶
a.* 
^¶
\z
¶1

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

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

Пояснення:

S`,                 # Split input on ", " putting each command on its own line
\.                  # Remove the period

T.*                 # Think of a number -> .*\n$* (replaces input with unary)
.*¶$$*
\;+`(.*)¶rep.*(¶?)  # Loop, replacing "repeat" with the line before it
$1¶$1$2
\d+                 # Replace all numbers with their unary representation
$*
.*f.* (1*)          # Replace "subtract from " with a subtract from program
1¶x¶$¶$1¶+`x1¶
m.*                 # Replace "multiply by " with a multiply program
1¶
di.* (1*)           # Replace "divide by " by my integer division program
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)            # Replace "subtract " with a subtraction program
^$1¶
a.*                 # Replace "add " with an addition program
^¶
\z                  # At the end, add a stage to change unary into decimal
¶1

Математичні програми:

Додати:

Додайте кількість початків. Додати 5:

^
1111

Віднімайте:

Видаліть кількість з початку. Віднімайте 5:

^11111

Відняти:

Замініть вхід 1s на xs. Поставте поруч із фіксованим номером. Неодноразово видаляйте x1. Віднімаємо від 10:

1
x
$
1111111111
+`x1

Помножте на:

Замініть кожного 1на певну їх кількість. Помножте на 3:

1
111

Розділити на:

Для цього використовується моя програма Retina для відділу Integer . Розділити на 2:

^                   # Place the fixed divisor before the dividend
11 
^(.+) (\1)+.*$      # Match the divisor, followed by each occurrence in the dividend.
x$#+                # Replace with the number of matches. Trailing ones are dropped
.+ .*               # If there are still two numbers, the result is zero
x0
x\d+                # Replace result (marked with an 'x') with unary
$*

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

@MartinEnder Я можу виправити віднімання, якщо ви поясните, чому ця спрощена програма дає у виході два. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

Тому що $сірники в самому кінці рядка або перед кінцевим рядком подаються. Вам потрібно, \zякщо ви хочете лише колишнього.
Мартін Ендер

4

GNU awk, 139 байт

BEGIN{RS="[,.]";c="{}{";ORS=";"}
/ad/{c="+="$2}
/c/{c="-="$2}
/om/{c="="$3"-$0"}
/l/{c="*="$3}
/v/{c="=int($0/"$3")"}
!NF{c="}1"}
$0="$0"c

Виклик:

$> awk `awk -f wordmath <<< "Think of a number, add 1, repeat, repeat."` <<< 0
$> 3

Тестові приклади:

$> awk -f wordmath <<< "Think of a number."  
$> $0{}{;$0}1;

$> awk -f wordmath <<< "Think of a number, divide by 5, subtract from 9."
$> $0{}{;$0=int($0/5);$0=9-$0;$0}1;

$> awk -f wordmath <<< "Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
$> $0{}{;$0+=5;$0+=10;$0*=2;$0-=15;$0-=15;$0=int($0/2);$0}1;

4

Haskell, 232 231 байт

Звичайно, функціональний програміст вважає за краще повернути функцію, а не рядок, що представляє програму, але тут ми йдемо:

t l="main=getLine>>=print."++""%words l++"(0+).read"
x%((o:_):f:n:r)|o=='m'=h"*"n r|o=='d'=h"`div`"n r|f=="from"=h"(-)"n r
x%(s:n:r)|s=="add"=h"+"n r|s!!0=='s'=h s(' ':n)r
x%(_:r)=x%r++x
_%_=""
h s n r|x<-'(':s++init n++")."=x%r++x

Зауваження: Ми завжди починаємо з додавання нуля, інакше транспіляція тривіальної програми WordMath не дасть достатньо інформації для висновку про тип, який readвикористовується. subtract from nможе бути реалізований як (n-), але я використовую((-)n) для більшої рівномірності. У випадку, якщо subtract nя копіюю цей subtractвхід, щоб мені не потрібно було його писати, але мені потрібно компенсувати пропущений пробіл наприкінці. repeatвикористовується як операція за замовчуванням; разом із порожньою початковою попередньою операцією це дозволяє легко ігнорувати перші чотири слова.

Приклад використання:

*Main> t "Think of a number. "
"main=getLine>>=print.(0+).read" 

Інші приклади дають такі результати:

"main=getLine>>=print.((-)9).(`div`5).(0+).read"
"main=getLine>>=print.(`div`2).(subtract 15).(subtract 15).(*2).(+10).(+5).(0+).read"  
"main=getLine>>=print.(subtract 1).(subtract 1).(subtract 1).(0+).read"

Що цікаво, як би ви створили функцію для повернення замість рядка?
Кіос

У мові функціонального програмування створення та складання функції не складніше, ніж створення та додавання рядка. hможе виглядати щось на зразок h s n r|x<-s.read.init$n=x%r.xі бути викликаним з першим аргументом на зразок такої функції h(+)n rflipдля отримання правильного порядку оператора потрібно десь бути дещо ), базовий випадок є _%_=id. Основна функція дозволяє уникнути всіх котлів і просто бути t l=id%words l. - Завдяки витримці, це може сприйматися як перекладач, і ця ідея може призвести до більш легкого та / або коротшого рішення.
Крістіан Сіверс

4

Пітон 2, 263 258 260 221 байт

Це, мабуть, все ще може бути набагато коротшим.

def r(s,o="",p=""):c=s.pop(0);c=[c,p]['re'in c];n=c.split()[-1];o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c];return s and r(s,"(%s)"%o,c)or o
lambda s:"print "+r(s.split(','))

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

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

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

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1

Якщо ви зміните цей великий блок ifs oна наступне (що, на мою, має спрацювати):, o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]ви можете зменшити його до 224.
Kade

@Kade Так, це все ще було розбірливим. Не може цього мати.
mbomb007

@Cyoce Ні, сам акт виклику лямбда, можливо, коштуватиме дорожче, ніж економить. Щоб окупитися, потрібно буде заощадити 4 або 5 байт за дзвінок.
mbomb007

4

Befunge, 342 305 байт

>~$1 +:89+`#v_801p
  v_^#`+85~$<
1+>~:5+88+/3-!#v_$
v`"/":~p8p10+1<>>:"/"`!|
 "+"\5+8p4+:1+^:p11:g10<  >:"+"\2+8p:"*"\3+8p:
_$7%:01g\!#v_\2-7g\:1+:01v^p8+1\"5":p8\"5":g10
#8\"\"$#:0#<^v<p8p8\<g80p<>\#+$#12#p
-/+* >:#,_@  #^p8g10<
".@"<^"&"
10<v0<\g8-\g11:<:p1>#1+g11:p10+g
-:^>1g\-8p1-::#^_$8g^  >$$01g11g

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

Вихідні дані

Створений ним код починається з команди &(значення введення) і закінчується командами .(значення виводу) та @(вихід). Між ними у нас є різні обчислення у формі <number><operation>, де операція може бути +(додати), -(відняти), /(ділити на), *(помножити на) і\- (відняти від).

Саме число трохи складніше, тому що Befunge підтримує лише числові літерали в діапазоні від 0 до 9, тому все більше, ніж це, потрібно вручну обчислити. Оскільки ми вже читаємо цифри в символі за символом, ми просто будуємо число, як кожна цифра читається, так, наприклад, 123 стає 155+*2+55+*3+, тобто (((1 * 10) + 2) * 10) + 3.

Приклади

Input:  Think of a number.
Output: &.@

Input:  Think of a number, divide by 5, subtract from 9.
Output: &5/9\-.@

Input:  Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
Output: &5+155+*0++2*155+*5+-155+*5+-2/.@

Input:  Think of a number, subtract 1, repeat, repeat.
Output: &1-1-1-.@

Пояснення

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

Щоб проаналізувати команду, ми просто продовжуємо рахувати символи, поки не досягнемо цифри чи роздільника. Якщо це роздільник, це, мабуть, була команда повтору, яку ми розглядаємо як особливий випадок. Якщо це цифра, ми додаємо її до нашого вихідного буфера і продовжуємо шукати більше цифр. Кожен раз, коли виводиться цифра, ми префіксуємо її 55+*(щоб помножити загальну кількість дотепер на 10) і суфіксом +(додати її до загальної суми). Після закінчення цифр ми додаємо командний символ.

Щодо того, як визначається команда, ми беремо кількість символів до першої цифри по модулю 7. Для додавання це 4 (включаючи наступний пробіл), для віднімання - 2, для ділення на 3 - для множення на 5 , а для віднімання - 0. Для віднімання потрібне трохи додаткового керування, оскільки йому потрібна \-комбінація команд, але інші просто використовують їх значення для пошуку відповідного символу команди в таблиці.

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


3

JavaScript (ES6), 163 байти

w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

Спробуй це:

f=w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

const program = f('Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.')
document.write('<pre>' + program + '</pre>' )

eval(program)

/*
Outputs:

n=+prompt()
n=n+5|0
n=n+10|0
n=n*2|0
n=n-15|0
n=n-15|0
n=n/2.|0
console.log(n)
*/


3

Vim 208 171 168 байт

Додана можливість робити кілька повторень поспіль відповідно до @ Flp.Tkc, але в гольф було достатньо байтів, щоб я міг знизити кількість байтів.

:map s :s;\v
c4wcw="s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(@qq@qx$xA

TryItOnline

Недруковані символи:

:map s :s;\v
c4wcw^V^R=^V^R"^[s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(^[@qq@qx$xA
^V^[^[

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

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline

Здається, це не працює для декількох послідовних повторів.
FlipTack

@ Flp.Tkc виправлено, дякую! Я цього не помічав раніше.
nmjcman101

2

лекс, 246 байт

%{
#define P printf
#define O P("n%s%d;",c,v);
int v;char*c;
%}
%%
T {P("%%%%\n.* {int n=atoi(yytext);");}
ad {c="+=";}
fr {c="=-n+";}
s {c="-=";}
v {c="/=";}
l {c="*=";}
re {O}
[0-9]+ {v=atoi(yytext);O}
\. P("printf(\"%%d\",n);}\n%%%%");
. ;
%%

lex націлює на C, тому компілятору C потрібно буде компілювати його у щось, що виконується. Бібліотека лексерів (ll ) також повинна бути пов'язана. Це може додати байтовий штраф, але я не впевнений, скільки байтів, якщо так.

Програма виводить програму lex (за специфікацією), яка оцінює вираження трансляції wordmath. Код між %{і %}є лише для "транспілера":

#define P printf              /* for brevity */
#define O P("n%s%d;",c,v)     /* expression builder, calls P = printf */
int v;char*c;                 /* v=most recent integer read */
                              /* c=the expression infix */

Між двома %%рядками знаходиться частина регулярного вираження / дії. Першим правилом було б відповідатиT ("Подумайте ..."), яке будує преамбулу (програми lex повинні починати щонайменше містити розділ правил і yytextє останнім відповідним текстом, тому правило, по суті, заряджає акумулятор із введенням користувача ).

У програмі відкидає всі вхідні крім тієї , яка узгоджена, а також інші правила ( ad, frдо re) обробляти вираження wordmath положення з мінімально збіг , наскільки це можливо , щоб бути унікальним. У більшості з них він встановлює cвираз інфіксу, який стає об'єднаним між nі останнім цілим читанням, коли Oйого викликають (так, наприклад, читання "додати 9" встановить інфікс на +=, v до 9, і виклик до Oбуде виводити n+=9;) . (Цікавою стороною є те, що "віднімання від 8" призведе до збігу sі frправил, і правил, але оскільки Oвикликується лише число, правильне правило n=-n+8;є єдиним виразом, що отримує вихід). reПравило для «повторення» тільки дзвінкиOзнову ж таки, який виводить останній створений вираз (і оскільки наступні збіги будуть клобувати yytext, підтримуючи "повторити", тому [0-9]+потрібне перетворення цілого числа в правилі). Нарешті, період спричиняє вихід трейлера програми, який просто видає акумулятор і закривається %%парою, що позначає кінець вихідної програми lex.

Примітка: Ні основна програма-транспілятор, ні вихідна програма не закінчуються. Трубопровідний вхід працюватиме або надає EOF (ctrl-D). Якщо потрібне припинення після першого введення, вихід () s може бути доданий.

Щоб скласти / запустити:

Build the main program:
% lex -o wordmath.yy.c wordmath.l
% cc -o wordmath wordmath.yy.c -ll

Execute to create a specific transpiled program:
% echo "This is a number, add 8, subtract 5, repeat." | ./wordmath > program.l

Build the transpiled program:
% lex -o program.yy.c program.l
% cc -o program program.yy.c -ll

Execute the transpiled program (with input 3, called via a pipe or inline):
% echo 3 | ./program
1
% ./program
3
1
^D
%

Тест 1:

%%
.* {int n=atoi(yytext);printf("%d",n);}
%%

Тест 2:

%%
.* {int n=atoi(yytext);n/=5;n=-n+9;printf("%d",n);}
%%

Тест 3:

%%
.* {int n=atoi(yytext);n+=5;n+=10;n*=2;n-=15;n-=15;n/=2;printf("%d",n);}
%%

Тест 4:

%%
.* {int n=atoi(yytext);n-=1;n-=1;n-=1;printf("%d",n);}
%%

2

Pyth, 69 67 байт

J\QVtcQ\,Iq@N1\r=NZ)=Jjd+@"+-/*"x"asdm"@N1.>,J-ecN)\.qh@cN)1\f=ZN)J

Програма, яка приймає введення "quoted string" та друкує результат.

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

Як це працює

Pyth має оператори префікса, тому основні арифметичні операції виконуються за допомогою (operator)(operand1)(operand2), тоді як попередньо ініціалізована змінна Qдає вхід. Отже, перероблена програма WordMath будується, починаючи з рядка 'Q', і на кожному етапі, попередньо додаючи оператора, а потім попередньо додаючи або додаючи операнд як необхідний.

J\QВстановити Jтранслірований рядок програми в рядок'Q'

tcQ\, Розділіть введення на коми і відкиньте перший елемент (який є ' Think of a number')

V Бо Nв тому, що:

  • Iq@N1\r Якщо символ на N[1]це 'r'(повтор):
    • =NZНабір Nдля Z(попереднє значення N, захід у кінці циклу) для
  • x"asdm"@N1 Знайдіть індекс N[1]в"asdm" (додавання, віднімання, ділення, множення)
  • @"+-/*" Індексуйте з цим в "+-/*", даючи необхідного оператора
  • ,J-eCN)\.Вихід двоелементного списку [J, -eCN)\.], де другий елемент є останнім елементом Nрозбиття на пробіл із '.'видаленими будь-якими символами (операнд)
  • qh@cN)1\f Якщо перший символ другого елемента Nрозбиття на пробіл є 'f'(відняти від):
    • .> Розміняйте елементи списку двоелементів
  • + Об’єднайте список операторів і двоелементних в один список
  • =Jjd Встановіть, Jщо приєдналося на пробіли
  • =ZN набір ZдляN

J Друк J


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

2

Піп , 58 байт

Шкода, що я ще не застосував цього оператора зворотного віднімання.

{p:a:sNa?ap['Y("-y+  y- y// y+ y* "^sa@?Y`\d`)|'qa@y]}Mq^k

Програма приймає скрипт WordMath зі stdin та виводить код Pip у stdout. Код, який виводиться, аналогічно, приймає число від stdin і виводить результат у stdout. Спробуйте в Інтернеті!

Стратегія

Для такого входу:

Think of a number, multiply by 3, add 1.

ми хочемо отримати такий результат:

YqYy*3Yy+1

яка працює наступним чином:

Yq    Yank a line of stdin into y
Yy*3  Compute y*3 and yank result into y
Yy+1  Compute y+1 and yank result into y
      Last expression is autoprinted

Ungolfed + пояснення

{
 p : a : sNa ? a p
 [
  'Y
  ("-y+  y- y// y+ y* "^s a@?Y`\d`) | 'q
  a@y
 ]
} M q^k

Основна структура програми полягає в тому {...}Mq^k, що розбивається q(рядок stdin) на k(пробіл з комами) і Mдодає функцію до кожного елемента.

Всередині функції ми починаємо з обробки repeatсправи. Здається, найкоротший тест у Pip sNa(чи є пробіл у команді). Якщо так, ми хочемо використовувати a; якщо ні, використовуйте p, що зберігає попередню команду. Призначте це значення назад, aа також p(наступному разу).

Для нашого повернутого значення ми використовуємо список, що чудово, оскільки формат виводу за замовчуванням для списків - це об'єднати все разом. Результат завжди починається з Y. Далі нам потрібна таблиця пошуку для операцій.

Зауважте, що довжини add (4), subtract (9), divide by (10), multiply by (12) та subtract from (14) всі виразні. Далі зауважте, що вони все ще відрізняються, коли приймаються мод 7. Таким чином, ми можемо використовувати їх для індексації до семиелементного списку (містить п’ять фрагментів коду та два заповнювачі) для зіставлення кожної команди WordMath у відповідний код Pip (розроблений так, щоб число можна просто об'єднати до кінця):

  • 0: -y+( subtract from)
  • 1: заповнювач
  • 2: y-( subtract)
  • 3: y//( divide by)
  • 4: y+( add)
  • 5: y*( multiply by)
  • 6: заповнювач

Для індексів, ми використовуємо регулярний вираз , щоб отримати індекс першого розряду в команді: a@?`\d`. Ми також використовуємо регулярний вираз yдля подальшого використання. Таблиця пошуку генерується шляхом розбиття рядка "-y+ y- y// y+ y* "наs (пробіл).

Нам ще належить обробити перший запис, який повинен бути перекладений у код Yq. Оскільки Think of a numberне містить жодних цифр, @?оператор повертає нуль. Використання нуля як індексу в таблиці пошуку також повертає нуль. Ніл є хибним, тому все, що нам потрібно зробити, - |'qце використовувати для використання qзамість операції для цього випадку.

Заключним елементом повернутого списку є саме число. Ми отримуємо це за допомогою a@y(знайдіть всі збіги в команді цифрового регулярного вираження, який ми витягували раніше). Це повертає список цифр, але знову ж таки, це не проблема, оскільки всі списки будуть об'єднані при виведенні. Для першого запису a@yне відповідає цифрам і дає порожній список, що нічого не додає до результату.

Наприклад

З введенням

Think of a number, subtract from 20, add 2, repeat.

вираз на карті дає список

[["Y";"q";[]]; ["Y";"-y+";[2;0]]; ["Y";"y+";[2]]; ["Y";"y+";[2]]]

який при з’єднанні виводить

YqY-y+20Yy+2Yy+2

2

Python 2 , 154 153 146 байт

Виправлено та навіть збережено кілька байтів у процесі. ^ __ ^

for c in input()[9:-1].split(","):s=c.rfind(" ");p=o=s and"x="+"-x+ input() x- x// x+ x*".split()[s%7]+c[s:]*(c[0]<"a")or p;print o
print"print x"

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

На основі тієї ж стратегії, що і моя відповідь Піпа . Особливості Python:

  • Think of і закриття .видаляються з рядка перед розщепленням ( input()[9:-1]). Період був надто нудним, щоб обробити його в основному циклі. Видалення перших дев'яти символів допомагає з іншої причини (див. Нижче).
  • Замість того, щоб отримувати довжину кожної команди шляхом пошуку за допомогою регулярного вибору цифри (дорога в Python, тому що import re), ми використовуємо rfind(" ")для пошуку останнього пробілу в команді. Ми також можемо використовувати це для перевірки repeatсправи.
  • У Python немає циклічного індексування Піпа, тому ми повинні чітко прийняти індекс mod 7. З іншого боку, це означає, що ми можемо видалити останнє фіктивне значення з таблиці пошуку, оскільки індекс mod 7 ніколи не дорівнює 6.
  • Перша команда "команда" - a numberце індекс простору 1. Цей індекс зручно заповнює інший отвір таблиці пошуку. Іншою проблемою при обробці вхідного етапу в основному циклі була +c[s:]частина, в результаті якої виникла б x=input() number. Щоб вирішити цю проблему, ми множимо рядок на c[0]<"a": 1для всіх звичайних команд, у яких cпочинається пробіл, але 0для початкової a number.

1

WinDbg, 449 388 байт

as, }@$t1
as. }0;?@$t0
asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
aSa " "
asQ .printf";r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0
as/c add Q +"
aSby " "
as/c divide Q /"
asfrom 0;r$t0=-@$t0+
as/c multiply Q *"
aSnumber " "
aSof " "
asrepeat +1
as/c subtract Q -"
.for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."

-61 байт шляхом визначення псевдоніму для повторного коду

Натхненний LambdaBeta в використанні #define. Цей підхід дещо змінює синтаксис WordMath ( ,і .має бути обмеженим простором, як і інші слова, і ,не слідкувати за цимrepeat ), і створює псевдонім таким, що для зміненого синтаксису WordMath є дійсним код WinDbg. Останній рядок виконує те, що запитання задає, і перетворює, перетворюючи вхід у модифікований синтаксис.

Введення здійснюється за допомогою встановлення рядка на адресу пам'яті та встановлення псевдореєстру $t0на цю адресу. Примітка. Це буде замінено на intat 0x2000000, тому якщо ви запустите рядок там, він буде частково перезаписаний. $t0буде також переписано.

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

Як це працює:

* $t1 is used for repeating and $t0 is used to read the input and hold the accumulator
* Alias , to }@$t1 -- closing do-while loop and allowing repeat
as , }@$t1

* Alias . to }0;?@$t0 -- close do-while loop and evaluate $t0 (accumulator)
as . }0;?@$t0

* Alias Think to (note this is one line)
as Think n10;               * Set base 10
         ed 8<<22;          * Read ints to address 0x2000000. Enter nothing to exit input mode
         r$t0 = dwo(8<<22); * Set $t0 = first int
         r$t1=0;.do{        * Open do-while

* Alias a to nothing
aS a " "

* Alias add to (note one line):
as add ;                       * Close previous statement
       r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
       r$t0=@$t0+              * Add number to $t0

* Alias by to nothing
aS by " "

* Alias divide to (note one line):
as divide ;                       * Close previous statement
          r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
          r$t0=@$t0/              * Divide next number from $t0

* Alias from to (note one line):
as from 0;         * Preceding subtract statement subtracts 0
       r$t0=-@$t0+ * Subtract $t0 from next number

* Alias multiply to (note one line):
as multiply ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0*              * Multiply next number with $t0

* Alias number to nothing
aS number " "

* Alias of to nothing
aS of " "

* Alias repeat to +1 making do-while (once) loops into do-while (once)+1
as repeat +1

* Alias subtract to (note one line):
as subtract ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0-              * Subtract next number from $t0


.for (r$t9=1; by(@$t0); r$t0=@$t0+1) * Enumerate the string
{
    j 44!=by(@$t0)                   * If not comma
        .printf "%c",by(@$t0);       * Print the char
    * implicit else
        .if 116!=by(@$t0-1)          * Else if the previous char is not t
        {
          .printf " , "              * Print the comma with spaces around it
        }
};
.printf "\b ."                       * Replacing ending "." with " ."

Зразок виводу, введення рядка перед запуском цього коду один раз (отримана програма нагадує WordMath):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0

0:000> Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0
base is 10
02000000 6e696854 18
18
02000004 666f206b 

Evaluate expression: 18 = 00000012

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

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0

0:000> n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0
base is 10
02000000 3b30316e 26
26
02000004 3c386465 

Evaluate expression: 26 = 0000001a

Ще кілька зразкових результатів, лише використовуючи трохи змінений синтаксис WordMath:

0:000> Think of a number , add 1 , repeat repeat repeat divide by 3 .
base is 10
02000000 0000001a 3
3
02000004 3c386465 

Evaluate expression: 2 = 00000002


0:000> Think of a number , divide by 5 , subtract from 9 .
base is 10
02000000 00000003 29
29
02000004 3c386465 

Evaluate expression: 4 = 00000004

0

Scala, 338 байт

Спробуйте самі у ideone

s=>{val n=(_:String)filter(_.isDigit)toInt;(Seq("").tail/:s.split(",").tail)((a,&)=> &match{case&if&contains "v"=>a:+"x/="+n(&)
case&if&contains "d"=>a:+"x+="+n(&)
case&if&contains "y"=>a:+"x*="+n(&)
case&if&contains "f"=>a:+"x="+n(&)+"-x"
case&if&contains "s"=>a:+"x-="+n(&)
case p=>a:+a.last})mkString("var x=readInt;",";",";print(x)")}

Пояснення:

// define a function with a parameter s
s => {
    // define a function with a String parameter to extract a number from a string
    val n =
        // filter out the chars that arent't digits
        (_: String) filter (_.isDigit)
        // and parse the number
        toInt;
    // take the tail of a list with an empty string,
    // which is the empty list of type Seq[String].
    // This is the start value for the fold...
    (Seq("").tail /:
        // ... of the tail of the sentence splitted at commas
        s.split(",").tail
    ) (
        // This is the function for the fold.
        // a is the accumulator (the list), and the current element is called &
        (a, &) => & match {
            // if & contains a "v", append "x/=" + n(&) to a.
            case & if & contains "v" => a :+ "x/=" + n(&)
            // the other cases are similar
            case & if & contains "d" => a :+ "x+=" + n(&)
            case & if & contains "y" => a :+ "x*=" + n(&)
            case & if & contains "f" => a :+ "x=" + n(&) + "-x"
            case & if & contains "s" => a :+ "x-=" + n(&)
            // for the repeat, apppend the last value of a to a
            case p                   => a :+ a.last
        }
     )
     // make a string out of the parts by joining them with semicolons,
     // prepending "var x=readInt;" and appending ";print(x)"
     mkString("var x=readInt;", ";", ";print(x)")
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.