Wyzwanie polega na tym, aby wszystkie cyfry rzymskie były poprawne w wybranym języku.
Powinny one nie pojawiają się wewnątrz ciągi lub coś podobnego, ale działają podobnie jak wszelkie inne tokeny, literały takich jak ( arabskich ), liczb, znaków lub ciągów; lub identyfikatory zmiennej / metody / funkcji itp.
Na przykład w Javie następujące elementy musiałyby się skompilować i uruchomić tak, jakby i
były zainicjowane 42
:
int i = XLII;
Rzeczywista analiza liczb jest drugorzędna, więc możesz użyć biblioteki, jeśli chcesz, ale jest to konkurs popularności, więc zachęca się do kreatywności.
Nie możesz używać żadnego języka, który faktycznie używa cyfr rzymskich, jeśli istnieje coś takiego.
Powodzenia.
Process
ast
do analizy źródła. Wstaw na górze AST definicję cyfr rzymskich od 1 do 3999. Skompiluj całość i uruchom ją. Pisanie kodu do obsługi procesu jest nudne.Odpowiedzi:
do
Jest tylko tyle cyfr rzymskich, ponieważ 4000 i wyższe nie mają standardowej notacji, a preprocesor jest wspaniałym narzędziem do dekompresji, szczególnie jeśli nie masz problemów z faktem, że kod ma nieokreślone zachowanie.
To definiuje wszystkie cyfry rzymskie od
I
doMMMCMXCIX
jako stałe wyliczenia, plus_
(który można zastąpić czymkolwiek chcesz) jako zero.źródło
scanf
też :) @ klingt.net Nie jestem pewien, jakiego rodzaju przykładu szukasz. Dość prosty byłbyint main() { return MMMCMXCIX - M - M - M - CM - XC - IX; }
Rubin
Wszelkie (wielkie litery) cyfry rzymskie będą teraz analizowane jak ich dziesiętne odpowiedniki. Jedynym problemem jest to, że nadal można je przypisać: możesz to zrobić
X = 9
, ale nie10 = 9
. Nie sądzę, żeby można to naprawić.źródło
JavaScript (ES6)
Użyj,
Proxy
aby złapać cyfry rzymskie.Testowany w Firefoksie (najnowszy) na JSFiddle .
Nie można przetestować w Chrome (z Traceur), ponieważ
Proxy
implementacja jest zepsuta.Stosowanie:
źródło
C i C ++ (zaktualizowana odpowiedź)
Jak zauważono w komentarzu, moje oryginalne rozwiązanie miało dwa problemy:
Ponieważ chciałem, aby mój kod był tak ogólny, jak to tylko możliwe, do pracy na starszych platformach, postanowiłem spróbować go w inny sposób. Jest dłuższy niż wcześniej, ale działa na kompilatorach i preprocesorach ustawionych na tryb zgodności C89 / C90. Wszystkie makra przekazują odpowiednią liczbę argumentów w kodzie źródłowym, choć czasami te makra „rozwijają się” w nicość.
Visual C ++ 2013 (aka wersja 12) emituje ostrzeżenia o brakujących parametrach, ale ani mcpp (preprocesor open source, który twierdzi, że jest zgodny ze standardem), ani gcc 4.8.1 (z przełącznikami -std = iso9899: 1990 -antantic-error) ostrzeżenia lub błędy dla tych wywołań makr ze skutecznie pustą listą argumentów.
Po przejrzeniu odpowiedniej normy (ANSI / ISO 9899-1990, 6.8.3, Makropolecenie) uważam, że istnieje wystarczająca dwuznaczność, że nie należy tego uważać za niestandardowy. „Liczba argumentów w wywołaniu makra podobnego do funkcji musi być zgodna z liczbą parametrów w definicji makra ...”. Wydaje się, że nie wyklucza pustej listy argumentów, dopóki potrzebne są nawiasy (i przecinki w przypadku wielu parametrów) do wywołania makra
Jeśli chodzi o problem z przecinkiem końcowym, ten problem rozwiązuje się poprzez dodanie dodatkowego identyfikatora do wyliczenia (w moim przypadku MMMM, który wydaje się równie rozsądny, jak cokolwiek, aby identyfikator podążał za 3999, nawet jeśli nie przestrzega przyjętych reguł sekwencjonowania cyfr rzymskich dokładnie).
Nieco czystsze rozwiązanie wymagałoby przeniesienia wyliczenia i obsługi makr do osobnego pliku nagłówka, co sugerowano w komentarzu w innym miejscu, i użycie undef nazw makr natychmiast po ich użyciu, aby uniknąć zanieczyszczenia przestrzeni nazw. Bez wątpienia należy również wybrać lepsze nazwy makr, ale jest to wystarczające do danego zadania.
Moje zaktualizowane rozwiązanie, a następnie moje oryginalne rozwiązanie:
Oryginalna odpowiedź (która otrzymała pierwsze sześć głosów pozytywnych, więc jeśli nikt nigdy więcej nie głosuje ponownie, nie powinieneś myśleć, że moje zaktualizowane rozwiązanie uzyskało pozytywne głosy):
W tym samym duchu, co wcześniejsza odpowiedź, ale wykonane w sposób, który powinien być przenośny przy użyciu tylko określonych zachowań (chociaż różne środowiska nie zawsze zgadzają się co do niektórych aspektów preprocesora). Traktuje niektóre parametry jako opcjonalne, ignoruje inne, powinien działać na preprocesorach, które nie obsługują
__VA_ARGS__
makra, w tym C ++, używa makr pośrednich, aby zapewnić, że parametry zostaną rozszerzone przed wklejeniem tokena, a na koniec jest krótszy i myślę, że łatwiej go odczytać ( choć nadal jest trudny i prawdopodobnie niełatwy do odczytania, po prostu łatwiejszy):źródło
__VA_ARGS__
.Common Lisp
Poniżej znajduje się dość długie wyjaśnienie, w jaki sposób utworzyłem makro, którego można użyć w następujący sposób:
Kiedy makro jest wywoływane w Common Lisp, to w zasadzie działa jak funkcja, tyle że argumenty są odbierane wcześniej ich oceną. W rzeczywistości, ponieważ we wspólnym kodzie Lisp są tylko dane, otrzymujemy (zagnieżdżoną) listę reprezentującą nieprzetworzone drzewo składniowe, z którym możemy zrobić, co chcemy, i odbywa się to w czasie kompilacji.
Funkcje pomocnicze
Pierwszym krokiem planu jest wzięcie tego drzewa i zeskanowanie go w poszukiwaniu czegoś, co wygląda jak cyfry rzymskie. Ponieważ jest to Lisp i tak dalej, spróbujmy zrobić to nieco funkcjonalnie: potrzebujemy funkcji, która wykona głębokie przejście do drzewa i zwróci każdy obiekt, dla którego podana funkcja
searchp
zwraca wartość true. Ten jest nawet (pół) rekurencyjny.Następnie kod do parsowania cyfr rzymskich, dzięki uprzejmości Rosetta Code :
Rzeczywiste makro
Bierzemy drzewo składniowe (
body
), przeszukujemy go za pomocą naszej procedury głębokiego znajdowania i w jakiś sposób udostępniamy znalezione cyfry rzymskie.Więc co to jest
1 + 2 + 3 + (4 * (5 + 6)) + 7
?I aby zobaczyć, co faktycznie się stało, gdy wywołano makro:
źródło
Lua
Po prostu rezerwowy __index dla tabeli globalnej. Rzeczywista konwersja za pomocą gsub okazała się znacznie ładniejsza niż się spodziewałem.
źródło
Postscriptum
Próbowałem podążać za C, ale nie rozumiałem tego. Zrobiłem to w ten sposób:
Postscript nie ma,
enum
ale możemy zbudować słownik z sekwencyjnymi wartościami całkowitymi i złożyć je w tablicę. Zmniejsza to problem generowania wszystkich ciągów w sekwencji, co odbywa się poprzez konkatenację w 4 zagnieżdżonych pętlach. Tak więc generuje wszystkie ciągi, a następnie przeplata każdy ciąg ze wzrastającą wartością licznika, w wyniku czego powstaje długa seria par <ciąg> <int> na stosie, które są owinięte w<<
...>>
celu utworzenia obiektu słownikowego.Program konstruuje i instaluje słownik mapujący wszystkie nazwy cyfr rzymskich na odpowiadające im wartości. Więc wzmianka o nazwach w tekście źródłowym wywołuje automatyczne wyszukiwanie nazw i zwraca wartość całkowitą na stosie.
odbitki
źródło
Smalltalk (Smalltalk / X) (87/101 znaków)
oczywiście moglibyśmy łatwo zmodyfikować tokenizer analizatora składni (ponieważ jest on częścią biblioteki klas i jako taki jest otwarty na modyfikacje i zawsze obecny), ale wyzwaniem jest wpływanie tylko na oceny w danym kontekście, tak aby reszta system działa jak zwykle.
Wersja 1:
zdefiniuj liczbę zmiennych w przestrzeni nazw oceny. Wpłynie to na interaktywne doIts (inaczej evals):
wtedy mogę zrobić (w doIt, ale nie w skompilowanym kodzie):
-> 2019
Uwaga: 101 znaków zawiera białe znaki; w rzeczywistości można to zrobić za pomocą 87 znaków.
Zauważ też, że kiedy zdefiniujesz w globalnej przestrzeni nazw Smalltalk, zobaczyłbym te stałe również w skompilowanym kodzie.
Wersja 2:
Użyj metody hookWrapper, która pozwala na zawijanie dowolnego istniejącego kodu bez ponownej kompilacji. Poniżej otacza tokenizator parsera, aby wyszukać rzymski identyfikator, który ma zostać zeskanowany, i czyni go liczbą całkowitą. Trudną częścią jest dynamiczne wykrywanie, czy kontekst wywołania pochodzi z imperium rzymskiego, czy nie. Odbywa się to za pomocą sygnału zapytania (który technicznie jest wyjątkowym postępowaniem):
zdefiniuj zapytanie:
Możemy więc w dowolnym momencie poprosić („zapytanie InRomanScope”) o domyślną wartość false.
Następnie zawiń metodę checkIdentifier skanera:
Teraz skaner działa jak zwykle, chyba że jesteśmy w imperium rzymskim:
-> 2525
możemy nawet skompilować kod:
Niezła próba; ale kończy się to błędem składniowym (dokładnie tego chcemy). Jednak w imperium rzymskim MOŻEMY skompilować:
a teraz możemy zapytać o dowolną liczbę całkowitą (wysyłającą tę wiadomość) z wewnątrz i spoza Rzymu:
-> 2525
źródło
Haskell, używając metaprogramowania w szablonie Haskell i cyfrach rzymskich :
Haskell rezerwuje identyfikatory zaczynające się od wielkich liter dla konstruktorów, więc użyłem małych liter.
źródło
J - 78 znaków
To idzie tylko do MMMCMXCIX = 3999, jak w przypadku innych rozwiązań.
Podział (pamiętaj, że J jest zwykle odczytywany od prawej do lewej, chyba że zostanie zastąpiony nawiasami):
M`CDM`XLC`IVX
- Cztery skrzynki z literami. Użyjemy tablic numerycznych do indeksowania tych liter i zbudujemy podmowy cyfr rzymskich.841,3#79bc5yuukh
- To są dane numeryczne, ściśle zakodowane. *(_1,~3#.inv])
- To zdekoduje powyższe dane, rozszerzając trójskładnikowe i dodając -1.('';&;:(...){' ',[)&.>
- Parując liczby po lewej stronie z polami po prawej stronie (&.>
), odkoduj tablice liczb i użyj ich do indeksowania liter. 0 traktujemy jako spację, dodając znak spacji do list liter. Ta procedura tworzy listy słów takich jakI II III IV V VI VII VIII IX
iM MM MMM
.{
- Weź kartezjański produkt z tych czterech pudeł pełnych słów. Teraz mamy tablicę 4D wszystkich cyfr rzymskich.}.,;L:1
- Uruchom to wszystko na pojedynczą listę 1D cyfr rzymskich i usuń pusty ciąg z przodu, ponieważ spowoduje to błąd. (L:
jest rzadkim widokiem w golfie J! Zwykle nie ma tak wielu poziomów boksu.)}.i.4e3
- Liczba całkowita od 0 do 4000, z wyłączeniem punktów końcowych.=:
. J pozwala ci mieć listę LHS z nazwami w ramkach, jako formę obliczonego wielokrotnego przypisania, więc to działa dobrze.Teraz przestrzeń nazw J jest pełna zmiennych reprezentujących cyfry rzymskie.
* Potrzebuję numeru 2933774030998, aby później odczytać go w bazie 3. Zdarza się, że mogę wyrazić go w bazie 79 za pomocą cyfr nie większych niż 30, co jest dobre, ponieważ J może zrozumieć cyfry do 35 (0-9, a następnie az). To oszczędza 3 znaki po przecinku.
źródło
Pyton
Pomysł jest prosty, podobnie jak inne odpowiedzi. Aby jednak zachować porządek i nie zanieczyszczać globalnej przestrzeni nazw, używany jest menedżer kontekstu. Nakłada to również ograniczenie, które należy wcześniej zadeklarować, zakres cyfr rzymskich, którego planujesz użyć.
Uwaga Aby zachować prostotę i nie wymyślać na nowo koła, skorzystałem z pakietu Roman Python
Realizacja
Próbny
źródło
Pyton
Jest to prawdopodobnie najprostsze rozwiązanie z użyciem Pythona:
źródło
globals()[var] = value
niżexec()
.re
za pomocą oceny funkcji czasu kompilacji D.
źródło
APL (Dyalog APL) , 77 bajtów
Monituje o maksymalną długość cyfr rzymskich i definiuje wszystkie zmienne.
t←
t dostaje'IVXLCDM',
Rzymskie znaki, po których następuje⊂
zamknięty⍬
pusta listat[
…]
Indeks t z…⍉
transponowane (aby uzyskać właściwą kolejność)8⊥⍣¯1
odpowiednia szerokość podstawowa ósemkowa reprezentacja⍳
pierwsze n wskaźników, gdzie n jest¯1+
jeden mniej niż8*⎕
osiem do mocy wprowadzania numerycznego,/
spłaszcz wiersze (każda reprezentacja){
…}¨
Zastosuj następującą anonimową funkcję do każdej reprezentacji…(
…)[t⍳⍵]
Odpowiadające pozycjom argumentów wt , wybierz z…∊
zaciągnął się1 5∘ר
jeden i pięć razy każdy10*
dziesięć do potęgi⍳4
od zera do trzech0,⍨
dołącz zero2(…)/
na każdym przesuwanym oknie o długości dwóch zastosuj następujący ciąg funkcji anonimowych…⊣×
czasy lewych argumentów¯1*
negatywny do potęgi<
czy lewy argument jest mniejszy niż prawy argument+/
suma⍵'←',
wstaw argument (cyfra rzymska) i strzałkę przypisania⍕
format (spłaszczyć i przekonwertować liczbę na tekst)⍎
wykonaj to (powoduje przypisanie poza funkcję anonimową)Wypróbuj online! (przy użyciu maksymalnej długości 5)
źródło
PHP
Istnieje kilka zasad prawidłowych liczb rzymskich
Napisz największą wartość przed niższymi wartościami
Odejmuj tylko
[I,X,C]
przed następnymi 2 większymi wartościamiOdejmij dwukrotnie
[I,X,C]
przed następnymi 2 większymi wartościamiOdejmij dwukrotnie
[I,X,C]
przed większymi wartościamiPołącz 4 + 5
Wersja online
Krok 1 Utwórz reguły
jest wyjściem JSON dla wszystkich prawidłowych liczb rzymskich
Krok 2 Zrób listę wszystkich reguł do 3999
Krok 3 Utwórz stałe
Połącz wszystkie listy i zdefiniuj stałe
Wydajność
W przykładzie wzajemnie dwie poprawne wersje liczby 8
źródło
Rebol
Przykład
Wydajność:
Oświadczenie: Jestem pewien, że istnieją inne (i prawdopodobnie lepsze!) Sposoby, aby to zrobić również w Rebol.
PS. Moją
roman-to-integer
funkcją jest transliteracja ładnego algorytmu Ruby od histocrata do konwersji łańcucha cyfr rzymskich na liczbę. Wrócił z podziękowaniami! +1źródło
Lua
Wpływa to na metatable tabeli globalnej, nadając jej nową funkcję indeksu. Kiedy jest wymagana zmienna globalna, która zawiera tylko cyfry rzymskie, np
XVII
. Analizuje ją.Łatwy do przetestowania;
Wypróbuj online!
źródło
VBA, 204 bajty
Zadeklarowany podprogram, który nie przyjmuje danych wejściowych, a po uruchomieniu tworzy
public
dostępnyEnum
,R
, który zawiera wszystkie wartości rzymska. Wartości tych można użyć bezpośrednio, bez odwoływania się do Enum.Wartości zatrzymania wyliczenia wynoszą od 1 do 3999.
Uwaga: Zaciski
"
w liniach 3 i 7 zostały uwzględnione wyłącznie w celu wyróżnienia składni i nie mają wpływu na liczbę bajtówNieoznakowany i wyjaśniony
źródło