Прозрачный 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 в качестве входных данных и переносит его в действительную полную программу - на том же языке, на котором написан ваш код.

Например, если мой код на 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.

FlipTack
источник
Должны ли мы поддерживать последовательные повторы?
Darrylyeo
1
Можем ли мы использовать float, когда это тип языка по умолчанию / если он не поддерживает целые числа?
Райнер П.
@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 байта

Я ПОЛУЧИЛ это, работая только в препроцессоре C, но команда повтора оказывается слишком сложной для реализации. Поэтому вместо этого я использовал препроцессор для преобразования входных данных в массив, который затем интерпретируется некоторым дополнительным кодом.

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.

LambdaBeta
источник
2
Примечание: это, к сожалению, не работает с некоторыми компиляторами, когда вы заканчиваете на repeat. Это потому, что они выбрасывают пробел после 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 Division . Разделите на 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
$*
mbomb007
источник
Боюсь, я не понимаю, как это может работать. Какие бы вводы я ни использовал для команд вычитания, я получаю неправильные результаты (в выводе отсутствуют переводы строки?). Я также не вижу, как это обрабатывает отрицательные входные данные или отрицательные промежуточные результаты.
Мартин Эндер
@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"
Кристиан Сиверс
источник
Просто любопытно, как бы вы сгенерировали функцию для возврата вместо строки?
Cyoce
В функциональном языке программирования создание и составление функции не сложнее, чем создание и добавление строки. hможет выглядеть примерно так h s n r|x<-s.read.init$n=x%r.xи вызываться с первым аргументом как функция h(+)n r(и где-то должна быть какая- flipто часть, чтобы получить правильный порядок операторов), базовый случай есть _%_=id. Основная функция может избежать всего шаблонного и просто быть t l=id%words l. - Благодаря карри, его можно рассматривать как переводчика, и эта идея может привести к более простому и / или более короткому решению.
Кристиан Сиверс
4

Python 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
mbomb007
источник
Если вы измените этот большой блок 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)
*/

darrylyeo
источник
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
nmjcman101
источник
Это не работает для нескольких последовательных повторов.
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 должен будет скомпилировать его в нечто исполняемое. Библиотека lexer ( ll) также должна быть связана. Это может добавить байт-штраф, но я не уверен, сколько байтов, если так.

Программа выводит программу lex (согласно спецификации), которая оценивает переданное выражение словосочетания. Код между %{и только %}для "транспилятора":

#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вызове (так, например, чтение «add 9» установит инфикс равным +=v 9, и вызов Oвызоветn+=9; ) , (Интересно отметить, что «вычитание из 8» приведет к тому, что sи frправила, и правила будут сопоставлены, но, поскольку они Oвызываются только по номеру, правильное правило n=-n+8;- единственное выражение, которое получает выходные данные). reПравило для «повторения» только звонкиOопять же, который выводит последнее созданное выражение (и поскольку последующие совпадения будут сгущаться yytext, поддержка "repeat" является причиной целочисленного преобразования в [0-9]+правиле). Наконец, период вызывает вывод трейлера программы, который просто выводит аккумулятор и замыкается %%парой, обозначающей конец программы вывода lex.

Заметка: ни основная программа транспортера, ни программа вывода не завершатся. Будет работать вход по трубопроводу или обеспечение EOF (ctrl-D). Если после первого ввода требуется завершение, можно добавить exit ().

Чтобы построить / запустить:

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);}
%%
ryounce
источник
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\QSet J, передаваемая строка программы, в строку'Q'

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

V Ибо Nв этом:

  • Iq@N1\r Если символ в N[1]это'r' (повторить):
    • =NZУстановить Nв Z(предыдущее значение N, установить в конце цикла for)
  • x"asdm"@N1 Найти индекс N[1]в"asdm" (сложение, вычитание, деление, умножение)
  • @"+-/*" Индекс с этим в "+-/*", давая требуемый оператор
  • ,J-eCN)\.Получите двухэлементный список [J, -eCN)\.], где второй элемент - это последний элемент Nразбиения на пустом пространстве с '.'удаленными символами (операнд)
  • qh@cN)1\f Если первый символ второго элемента Nразбиения в пробеле равен 'f'(вычесть из):
    • .> Поменяйте местами элементы двухэлементного списка
  • + Объединить оператор и двухэлементный список в один список
  • =Jjd Подбирай Jчто попало на пробелы
  • =ZN Установите ZнаN

J Распечатать J

TheBikingViking
источник
Хороший ответ, человек ... Вдохновил меня попробовать в 05AB1E, что ... было более пугающим, чем предполагалось.
Магическая урна с осьминогом
2

Пип , 58 байт

Жаль, что я еще не реализовал этот оператор обратного вычитания.

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

Программа берет скрипт WordMath из стандартного ввода и выводит код Pip в стандартный вывод. Код, который выводится, аналогично, берет число из 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(строка стандартного ввода) на k(запятая) иM добавляет функцию к каждому элементу.

Внутри функции мы начнем с обработки repeatкейса. Самый короткий тест в Пипе, кажется, 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не содержит никаких цифр, @?оператор возвращает ноль. Использование nil в качестве индекса в таблице поиска также возвращает nil. Nil - это ложь, поэтому все, что нам нужно сделать, это добавить |'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
DLosc
источник
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.
DLosc
источник
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)")
}
corvus_192
источник