Wszyscy widzieliśmy te „hax matematyki” online, które wyglądają tak:
Think of a number, divide by 2, multiply by 0, add 8.
I, magicznie, wszyscy kończą na cyfrze 8!
Język
Zdefiniujmy język programowania, który wykorzystuje składnię powyższego tekstu, zwany „WordMath”. Skrypty WordMath są zgodne z tym szablonem:
Think of a number, <commandlist>.
Co w zasadzie oznacza: weź liczbę (jako dane wejściowe ze STDIN) jako akumulator początkowy, wykonaj na nim wszystkie polecenia i wyślij wynik.
Polecenia są rozdzielane separatorem ,
(przecinek + spacja). Prawidłowe polecenia to (uwaga, która #
reprezentuje nieujemną liczbę całkowitą :) :
add #
/subtract #
- Dodaj / odejmij wartość z akumulatora.divide by #
/multiply by #
- floordiv / pomnóż akumulator przez podaną wartość.subtract from #
- Podobne dosubtract
, ale robiacc = # - acc
zamiastacc = acc - #
repeat
- ponownie wykonaj ostatnie polecenie. To nie może być pierwsze polecenie, ale musisz obsługiwać wiele kolejnych powtórzeń.
Wyzwanie
Twoim zadaniem jest utworzenie programu lub funkcji, która pobiera prawidłowy skrypt WordMath jako dane wejściowe i transponuje go do prawidłowego pełnego programu - w tym samym języku, w którym znajduje się kod.
Na przykład, jeśli mój kod znajduje się w języku Python 2, a skrypt to:
Think of a number, subtract from 10, add 10, multiply by 2.
Wyprowadzanym programem może być:
a = input()
a = 10 - a
a += 10
a *= 2
print(a)
Lub alternatywnie:
print(((10-input())+10)*2)
Tak długo, jak jest to pełny program, który pobiera dane wejściowe STDIN
i drukuje STDOUT
, lub najbliższe odpowiedniki języka.
Zasady
- Twój oryginalny program może założyć, że dane wejściowe są zawsze prawidłowym skryptem WordMath.
- Transponowane programy nie muszą obsługiwać błędów matematycznych, takich jak dzielenie przez 0.
- Transpilowane programy mogą zakładać, że dane wejściowe reprezentują prawidłową liczbę całkowitą ze znakiem, w standardowym zakresie liczb całkowitych w języku użytkownika.
- To jest golf golfowy , więc wygrywa najkrótsze rozwiązanie (w bajtach).
- Liczy się tylko liczba bajtów oryginalnego programu - kod wyjściowy może być tak długi, jak chcesz!
Przykładowe skrypty
Przykład 1:
Think of a number.
Wejdź, nic nie rób, wyświetl: program cat WordMatha.
Przykład 2:
Think of a number, divide by 5, subtract from 9.
Pamiętaj, że „podział” to podział podłogi, więc w przypadku tego programu 6 -> 8
i 29 -> 4
.
Przykład 3:
Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
Rozszerzony program dla kotów!
Przykład 4:
Think of a number, subtract 1, repeat, repeat.
Pobiera liczbę i odejmuje 3.
-5/3
? Czy zaokrąglamy w0
kierunku ujemnej nieskończoności?Odpowiedzi:
05AB1E ,
59565452 bajtówWypróbuj online!
Po tym mój mózg boli jak diabli ... Wyprowadza kod 05AB1E w następujący sposób:
Think of a Number
jest usuwany ze względu na domniemane dane wejściowe.Subtract From #
coverts do#s-
(zamianaa
ib
i wykonywania operacji).Subtract #
konwertuje na#-
.Add #
konwertuje na#+
.Multiply by #
konwertuje na#*
.Divide by #
konwertuje na#/
.Repeat
pobiera to, co ostatnio zapisano w rejestrze i łączy je.Wyjaśnił:
Przykład:
Wkład:
Wydajność:
Wypróbuj rozwiązanie z wejściem 10:
Wypróbuj online!
Zobacz w Google:
Oto link do tego samego równania wpisanego w google.
źródło
Preprocesor C, 362 bajtów
PRAWIE mam to działa w JUST preprocesorze C, ale polecenie powtarzania okazuje się zbyt trudne do wdrożenia. Zamiast tego użyłem preprocesora do przekształcenia danych wejściowych w tablicę, która jest następnie interpretowana przez jakiś dodatkowy kod.
Dane wejściowe należy podać w pliku „input.wm” lub po prostu zrzucić do źródła w tym wierszu. Uwzględniłem jego bajty, ponieważ uważam, że jest nieco zuchwały i nieco niezgodny z regułami wyzwania, więc pasuje tylko.
W każdym razie, gdy zrzucisz źródło WordMath do input.wm, gdzie kompilator może go znaleźć, powinieneś być w stanie po prostu skompilować to, tak jak jest, z ostrzeżeniami, aby stworzyć plik wykonywalny, który robi to, co mówi źródło WordMath.
źródło
Siatkówka, 170 bajtów
Bo kto nie chciałby tego zobaczyć ?!
Pomyślałem o tym, jak wspaniale byłoby zobaczyć rozwiązanie Retina i postanowiłem go szybko stworzyć. Zajęło to tylko godzinę. Jak zwykle liczba bajtów zakłada kodowanie ISO 8859-1.
Wypróbuj online
Dane wyjściowe mają końcowy znak nowej linii, którego nie należy kopiować podczas testowania wynikowego programu. Program nie obsługuje negatywów, ponieważ standardowy zakres liczb całkowitych Retiny (w jedności) nie.
Wyjaśnienie:
Programy matematyczne:
Dodaj:
Dodaj liczbę jedynek na początku. Dodaj 5:
Odejmować:
Usuń liczbę jedynek od początku. Odejmij 5:
Odejmij od:
Zamień wejścia
1
s nax
s. Umieść obok stałego numeru. Wielokrotnie usuwajx1
. Odejmij od 10:Pomnożyć przez:
Zastąp każdy
1
określoną liczbą. Pomnóż przez 3:Podzielić przez:
To używa mojego programu Retina dla Integer Division . Podziel przez 2:
źródło
$
dopasowuje się na samym końcu łańcucha lub przed końcowym podawaniem linii. Potrzebujesz,\z
jeśli chcesz tylko tego pierwszego.GNU awk, 139 bajtów
Wezwanie:
Przypadki testowe:
źródło
Haskell,
232231 bajtówOczywiście funkcjonalny programista wolałby zwracać funkcję niż ciąg znaków reprezentujący program, ale proszę bardzo:
Uwagi: Zawsze zaczynamy od dodania zera, w przeciwnym razie transpozycja trywialnego programu WordMath nie dałaby wystarczających informacji, aby wywnioskować, z jakiego typu
read
jest on używany.subtract from n
może być wdrożony jako(n-)
, ale używam((-)n)
dla większej jednolitości. W przypadkusubtract n
kopiowaniasubtract
z wejścia, więc nie muszę go pisać, ale muszę wyrównać brakujące miejsce na końcu.repeat
jest używany jako operacja domyślna; wraz z pustą początkową poprzednią operacją pozwala to na łatwe zignorowanie pierwszych czterech słów.Przykład użycia:
Inne przykłady dają następujące wyniki:
źródło
h
może wyglądać jakh s n r|x<-s.read.init$n=x%r.x
i być wywoływana z pierwszym argumentem jak funkcjah(+)n r
(i musi byćflip
gdzieś, aby uzyskać prawidłową kolejność operatorów), podstawową sprawą jest_%_=id
. Główna funkcja pozwala uniknąć całej płyty kotła i po prostu byćt l=id%words l
. - Dzięki curry może to być interpretowane jako tłumacz, a ten pomysł może prowadzić do łatwiejszego i / lub krótszego rozwiązania.Python 2,
263258260221 bajtówMoże to prawdopodobnie nadal być znacznie krótszy.
Wypróbuj online
Używam
//
zamiast/
, ponieważ ostatnia instrukcja będzie miała.
na końcu, dzięki czemu dowolna liczba będzie liczbą zmiennoprzecinkową. Aby zachować spójność podziału, używam podziału na liczby całkowite.Dane wyjściowe przypadków testowych:
źródło
if
So
do następującego (co moim zdaniem powinno działać)o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]
, można je dostać w dół do 224.Befunge,
342305 bajtówWypróbuj online!
Wydajność
Generowany przez niego kod zaczyna się od polecenia
&
(wartość wejściowa), a kończy na poleceniu.
(wartość wyjściowa) i@
(wyjście). W międzyczasie mamy różne obliczenia w formie<number><operation>
, w której operacją może być+
(dodawanie),-
(odejmowanie),/
(dzielenie przez),*
(mnożenie przez) i\-
(odejmowanie od).Sama liczba jest nieco skomplikowana, ponieważ Befunge obsługuje tylko literały liczbowe w zakresie od 0 do 9, więc wszystko większe niż to musi zostać obliczone ręcznie. Ponieważ czytamy już cyfry znak po znaku, po prostu budujemy liczbę, gdy każda cyfra jest odczytywana, więc na przykład 123 staje się
155+*2+55+*3+
, tj(((1 * 10) + 2) * 10) + 3
.Przykłady
Wyjaśnienie
Befunge nie ma możliwości manipulowania ciągami jako takimi, więc większość parsowania jest obsługiwana przez liczenie znaków. Zaczynamy od pominięcia pierwszych 18 znaków, co pozwala nam przejść przez myśl o liczbie wyrażenia (plus przecinek lub kropka). Następnie, jeśli następny znak jest jakąś formą nowego wiersza lub EOF, przechodzimy od razu do procedury wyjściowej, w przeciwnym razie kontynuujemy wyszukiwanie listy poleceń.
Aby przeanalizować polecenie, po prostu zliczamy znaki, aż dojdziemy do cyfry lub separatora. Jeśli jest to separator, musi to być polecenie powtarzania, które traktujemy jako specjalny przypadek. Jeśli jest to cyfra, dodajemy ją do bufora wyjściowego i kontynuujemy wyszukiwanie kolejnych cyfr. Za każdym razem, gdy wypisywana jest cyfra, poprzedzamy ją znakiem
55+*
(aby pomnożyć dotychczasową liczbę całkowitą przez 10) i+
dodajemy przyrostek za pomocą (aby dodać ją do sumy). Po zakończeniu cyfr dodajemy znak polecenia.Jeśli chodzi o sposób określania polecenia, bierzemy liczbę znaków do pierwszej cyfry modulo 7. Aby dodać to jest 4 (łącznie z następną spacją), do odejmowania to 2, do dzielenia przez to 3, do mnożenia przez to 5 , i dla odejmowania od jego 0. Odejmowanie od wymaga nieco dodatkowej obsługi, ponieważ wymaga
\-
kombinacji komend, ale inni po prostu używają ich wartości, aby wyszukać odpowiedni znak polecenia w tabeli.Ten proces powtarza się dla każdego polecenia, tworząc wynik w postaci wcześniej utworzonego ciągu w linii 8. Za każdym razem, gdy dodawane jest dodatkowe polecenie, dodajemy również cudzysłów zamykający do łańcucha, aby upewnić się, że jest on zawsze poprawnie zakończony. Następnie, kiedy w końcu osiągamy koniec naszych danych wejściowych, po prostu „wykonujemy” ten ciąg, aby wypchnąć go na stos, a następnie postępujemy zgodnie ze standardową sekwencją wyjściową, aby zapisać to wszystko.
źródło
JavaScript (ES6), 163 bajty
Spróbuj:
źródło
Vim
208171168 bajtówDodano możliwość wykonywania wielu powtórzeń z rzędu zgodnie z @ Flp.Tkc, ale grało w golfa wystarczającą liczbę bajtów, żebym mógł nadal zmniejszyć liczbę bajtów.
TryItOnline
Znaki niedrukowalne:
Dane wyjściowe przypadków testowych:
cw^R=^R" ^[
TryItOnlinecw^R=((^R" /5) *-1+9) ^[
TryItOnlinecw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[
TryItOnlineźródło
leksykon, 246 bajtów
leksykon celuje na C, więc kompilator C musiałby skompilować go w coś wykonywalnego. Biblioteka Lexer (
ll
) również musiałaby zostać połączona. Może to dodać karę bajtową, ale nie jestem pewien, ile bajtów, jeśli tak.Program generuje program leksykalny (według specyfikacji), który ocenia przełożone wyrażenie matematyczne. Kod pomiędzy „
%{
i%}
” dotyczy tylko „transpilatora”:Pomiędzy dwiema
%%
liniami znajduje się część wyrażenia regularnego / akcji. Pierwszą zasadą, którą należy dopasować, byłabyT
(„Pomyśl ...”), która buduje preambułę (programy lex muszą zacząć zawierać przynajmniej sekcję reguł, iyytext
jest ostatnim pasującym tekstem, więc reguła zasadniczo zapełnia akumulator danymi wejściowymi użytkownika ).Odrzuty zaprogramować wszystkie wejścia z wyjątkiem tego, co jest dopasowany, i inne zasady (
ad
,fr
maksymalniere
) obsługują klauzule ekspresji wordmath z jako minimalny mecz, jak to możliwe, aby być unikatowa. W większości z nich ustawiac
się na przyrostek wyrażenia, który jest konkatenowany międzyn
ostatnią liczbą całkowitą odczytaną poO
wywołaniu (tak więc na przykład czytanie „dodaj 9” spowoduje ustawienie przyrostka na+=
, v na9
i wywołanieO
wyjścien+=9;
) . (Ciekawostką jest to, że „odejmowanie od 8” spowoduje dopasowanie zarówno reguł, jaks
ifr
reguł, ale ponieważO
jest wywoływane tylko pod numerem, odpowiednia regułan=-n+8;
jest jedynym wyrażeniem, które otrzymuje dane wyjściowe). There
Zasada „Repeat” połączeń tylkoO
ponownie, który wyprowadza ostatnio utworzone wyrażenie (a ponieważ kolejne dopasowania będą się zapychaćyytext
, obsługa „powtórz” jest powodem, dla której[0-9]+
wymagana jest konwersja liczb całkowitych w regule). W końcu kropka powoduje wyświetlenie zwiastuna programu, który po prostu wysyła akumulator i zamyka się z%%
parą oznaczającą koniec programu lex wyjścia.Uwaga: Ani główny program transpilatora, ani program wyjściowy nie zostaną zakończone. Pipingowanie wejścia działałoby lub dostarczanie EOF (ctrl-D). Jeśli zakończenie jest wymagane po pierwszym wejściu, można dodać exit () s.
Aby zbudować / uruchomić:
Test 1:
Test 2:
Test 3:
Test 4:
źródło
Pyth,
6967 bajtówProgram, który pobiera dane wejściowe
"quoted string"
i wypisuje wynik.Zestaw testowy
Jak to działa
Pyth ma operatory przedrostkowe, więc podstawowe operacje arytmetyczne są wykonywane przy użyciu
(operator)(operand1)(operand2)
, podczas gdy wstępnie zainicjalizowana zmiennaQ
podaje dane wejściowe. Dlatego transpilowany program WordMath jest konstruowany, zaczynając od łańcucha'Q'
i na każdym etapie, przygotowując operatora, a następnie przygotowując lub dołączając operand, jeśli jest to konieczne.J\Q
ZestawJ
transpilowany ciąg programu na ciąg'Q'
tcQ\,
Podziel dane wejściowe przecinkami i odrzuć pierwszy element (czyli „Think of a number'
)V
WN
tym:Iq@N1\r
Jeśli znak atN[1]
to'r'
(powtórz):=NZ
UstawN
naZ
(poprzednia wartośćN
, ustawiona na końcu pętli for)x"asdm"@N1
Znajdź indeksN[1]
w"asdm"
(dodawanie, odejmowanie, dzielenie, mnożenie)@"+-/*"
Zindeksuj to"+-/*"
, podając wymaganego operatora,J-eCN)\.
Daje listę dwuelementową[J, -eCN)\.]
, w której drugi element jest ostatnim elementemN
podziału na białe znaki z'.'
usuniętymi dowolnymi znakami (operand)qh@cN)1\f
Jeśli pierwszym znakiem drugiego elementuN
podziału na białych znakach jest'f'
(odejmij od):.>
Zamień elementy listy dwuelementowej+
Scal listę operatorów i listę dwóch elementów w jedną listę=Jjd
UstawJ
to połączone na spacje=ZN
UstawZ
naN
J
WydrukowaćJ
źródło
Pypeć , 58 bajtów
Szkoda, że nie wdrożyłem jeszcze operatora odwrotnego odejmowania.
Program pobiera skrypt WordMath ze standardowego wejścia i wysyła kod Pip na standardowe wyjście. Podobnie kod wyjściowy pobiera liczbę ze standardowego wejścia i przekazuje wynik na standardowe wyjście. Wypróbuj online!
Strategia
Dla takich danych wejściowych:
chcemy, aby dane wyjściowe wyglądały tak:
który działa w następujący sposób:
Niegolfowane + wyjaśnienie
Podstawową strukturą programu jest
{...}Mq^k
podziałq
(linia standardowego) nak
(przecinek-spacja) iM
zastosowanie funkcji do każdego elementu.Wewnątrz funkcji zaczynamy od obsługi
repeat
skrzynki. Najkrótszy test w Pipie wydaje się byćsNa
(czy w poleceniu jest spacja). Jeśli tak, chcemy użyća
; jeśli nie, użyjp
, która przechowuje poprzednie polecenie. Przypisz tę wartość z powrotem do,a
a także dop
(na następny raz).Do naszej wartości zwracanej używamy listy, co jest w porządku, ponieważ domyślnym formatem wyjściowym list jest konkatenacja wszystkiego razem. Wynik zawsze zaczyna się od
Y
. Następnie potrzebujemy tabeli przeglądowej dla operacji.Zauważ, że długości
add
(4),subtract
(9),divide by
(10),multiply by
(12) isubtract from
(14) są różne. Ponadto zauważ, że nadal są one odrębne, gdy weźmiesz mod 7. Zatem możemy ich użyć do indeksowania do listy siedmiu elementów (zawierającej pięć fragmentów kodu i dwa symbole zastępcze), aby zamapować każdą komendę WordMath na odpowiedni kod Pip (zaprojektowany tak, aby liczba można po prostu połączyć do końca):-y+
(subtract from
)y-
(subtract
)y//
(divide by
)y+
(add
)y*
(multiply by
)Dla indeksów, używamy regex, aby uzyskać indeks pierwszej cyfry polecenia:
a@?`\d`
. Wciągamy również wyrażenie regularne doy
wykorzystania w przyszłości. W tabeli odnośników są generowane przez dzielenie ciąg"-y+ y- y// y+ y* "
nas
(spację).Nadal musimy obsłużyć pierwszy wpis, który powinien przełożyć się na kod
Yq
. OdThink of a number
nie zawiera żadnych cyfr,@?
operator zwraca zero. Użycie wartości zero jako indeksu w tabeli odnośników również zwraca wartość zero. Brak jest fałszem, więc wszystko, co musimy zrobić, to dodać|'q
do użyciaq
zamiast operacji w tym przypadku.Ostatnim elementem zwracanej listy jest sama liczba. Otrzymujemy to poprzez
a@y
(znajdź wszystkie dopasowania w poleceniu wyrażenia regularnego, który wcześniej szarpaliśmy). Zwraca to listę cyfr, ale znowu nie stanowi to problemu, ponieważ wszystkie listy zostaną połączone podczas wyjścia. Dla pierwszego wpisua@y
nie pasuje do żadnych cyfr i daje pustą listę, która nie dodaje niczego do wyniku.Na przykład
Z wejściem
wyrażenie mapy daje listę
które po połączeniu zostają wydane
źródło
Python 2 ,
154153146 bajtówNaprawiono, a nawet zapisano kilka bajtów. ^ __ ^
Wypróbuj online!
Oparty na tej samej strategii, co moja odpowiedź Pip . Funkcje specyficzne dla języka Python:
Think of
a zamknięcie.
jest usuwane z łańcucha przed podziałem (input()[9:-1]
). Okres był zbyt nieznośny, aby poradzić sobie w głównej pętli. Usunięcie pierwszych dziewięciu znaków pomaga z innego powodu (patrz poniżej).import re
), używamyrfind(" ")
do znalezienia ostatniej przestrzeni w poleceniu. Możemy również użyć tego do sprawdzeniarepeat
sprawy.a number
, w którym znajduje się indeks przestrzeni1
. Ten indeks dogodnie wypełnia drugą dziurę w tabeli odnośników. Innym problemem związanym z przetwarzaniem stopnia wejściowego w głównej pętli była+c[s:]
część, w wyniku którejx=input() number
. Aby rozwiązać ten problem, mnożymy ciąg znaków przezc[0]<"a"
:1
dla wszystkich zwykłych poleceń, w którychc
zaczyna się spacją, ale0
dla początkowegoa number
.źródło
WinDbg,
449388 bajtów-61 bajtów poprzez zdefiniowanie aliasu dla powtarzającego się kodu
Zainspirowany LambdaBeta za stosowania
#define
. To podejście nieznacznie modyfikuje składnię WordMath (,
i.
musi być oddzielone spacjami, jak inne słowa, i,
nie następujerepeat
), i tworzy alias taki, że zmodyfikowana składnia WordMath jest poprawnym kodem WinDbg. Ostatni wiersz robi to, o co pyta i transponuje, konwertując dane wejściowe na zmodyfikowaną składnię.Wprowadzanie odbywa się poprzez ustawienie ciągu pod adresem pamięci i ustawienie pseudorejestru
$t0
na ten adres. Uwaga: spowoduje to zastąpienieint
at0x2000000
, więc jeśli zaczniesz tam swój ciąg, zostanie on częściowo nadpisany.$t0
zostaną również zastąpione.Ponieważ tworzy aliasy, w zależności od tego, czy ten kod działał przed czy po ustawieniu ciągu znaków, kod wyjściowy będzie inny (alias lub nie). Niestety nie znalazłem sposobu, aby aliasy były poprawnie rozwijane bez ograniczania białych znaków (co oznacza, że skrypt WordMath nie mógł zostać wykonany bezpośrednio bez uprzedniej transformacji).
Jak to działa:
Przykładowe dane wyjściowe, wprowadzanie ciągu znaków przed jednokrotnym uruchomieniem tego kodu (wynikowy program przypomina WordMath):
Przykładowe dane wyjściowe, wprowadzanie ciągu po jednorazowym uruchomieniu tego kodu (aliasy są rozszerzane podczas wprowadzania ciągu, więc wynikowy program nie jest tak ładny):
Jeszcze więcej przykładowych danych wyjściowych, używając tylko nieznacznie zmodyfikowanej składni WordMath:
źródło
Scala, 338 bajtów
Wypróbuj sam w ideone
Wyjaśnienie:
źródło