Le défi consiste à créer un code valide en chiffres romains dans la langue de votre choix.
Ils ne doivent pas apparaître à l'intérieur de chaînes ou quoi que ce soit de similaire, mais fonctionnent comme tout autre jeton, littéral tel que des nombres, des caractères ou des chaînes (en arabe ); ou identificateurs de variable / méthode / fonction, etc.
Par exemple, en Java, les éléments suivants doivent être compilés et exécutés comme s'ils avaient i
été initialisés 42
:
int i = XLII;
L’analyse des chiffres est secondaire, vous pouvez donc utiliser une bibliothèque si vous le souhaitez, mais c’est un concours de popularité qui encourage la créativité.
Vous ne pouvez utiliser aucune langue qui utilise réellement des chiffres romains, s'il en est une.
Bonne chance.
Process
ast
pour analyser le source. Insérez au sommet de l'AST la définition des chiffres romains compris entre 1 et 3999. Compilez le tout et exécutez-le. C'est ennuyeux d'écrire le code pour gérer le processus.Réponses:
C
Il n'y a que peu de chiffres romains, car 4000 et plus n'ont pas de notation standard et le préprocesseur est un outil de décompression formidable, surtout si vous n'avez pas de problème avec le comportement indéfini du code.
This defines all Roman numerals from
I
toMMMCMXCIX
as enumeration constants, plus_
(which can be replaced by anything you like) as zero.la source
scanf
too :) @klingt.net I'm not sure what sort of example you're looking for. A fairly simple one would beint main() { return MMMCMXCIX - M - M - M - CM - XC - IX; }
Ruby
Any (uppercase) Roman numerals will now be parsed like their decimal equivalents. The only issue is that they're still assignable: you can do
X = 9
, but not10 = 9
. I don't think there's a way to fix that.la source
JavaScript (ES6)
Use
Proxy
to catch roman numerals.Testable in Firefox (latest) on JSFiddle.
Not testable in Chrome (with Traceur) since
Proxy
implementation is broken.Usage:
la source
C & C++ (Updated Answer)
As observed in a comment, my original solution had two problems:
Since I wanted my code to be as generic as possible to work on older platforms, I decided to take another stab at it. It is longer than it was before, but it works on compilers and preprocessors set to C89/C90 compatibility mode. All macros are passed an appropriate number of arguments in the source code, though sometimes those macros "expand" into nothing.
Visual C++ 2013 (aka version 12) emits warnings about missing parameters, but neither mcpp (an open source preprocessor that claims high compliance with the standard) nor gcc 4.8.1 (with -std=iso9899:1990 -pedantic-errors switches) emit warnings or errors for those macro invocations with an effectively empty argument list.
After reviewing the relevant standard (ANSI/ISO 9899-1990, 6.8.3, Macro Replacement), I think there is sufficient ambiguity that this should not be considered non-standard. "The number of arguments in an invocation of a function-like macro shall agree with the number of parameters in the macro definition...". It does not seem to preclude an empty argument list as long as the needed parentheses (and commas in the case of multiple parameters) are in place to invoke the macro
As for the trailing comma problem, that is resolved by adding an extra identifier to the enumeration (in my case, MMMM which seems as reasonable as anything for the identifier to follow 3999 even if it doesn't obey the accepted rules of Roman numeral sequencing exactly).
A slightly cleaner solution would involve moving the enum and supporting macros to a separate header file as was implied in a comment elsewhere, and using undef of the macro names immediately after they were used so as to avoid polluting the namespace. Better macro names should undoubtedly be chosen as well, but this is adequate for the task at hand.
My updated solution, followed by my original solution:
The original answer (which received the first six upvotes, so if no one ever upvotes this again, you shouldn't think my updated solution got the upvotes):
In the same spirit as an earlier answer, but done in a way that should be portable using only defined behavior (though different environments don't always agree on some aspects of the preprocessor). Treats some parameters as optional, ignores others, it should work on preprocessors that don't support the
__VA_ARGS__
macro, including C++, it uses indirect macros to ensure parameters are expanded before token pasting, and finally it is shorter and I think easier to read (though it is still tricky and probably not easy to read, just easier):la source
__VA_ARGS__
.Common Lisp
The following is a rather lengthy explanation of how I made a macro that you can use like this:
When a macro is called in Common Lisp, it basically acts like a function, only that the arguments are received before they are evaluated. Actually, since in Common Lisp code is just data, what we receive is a (nested) list representing an unparsed syntax tree that we can do whatever we want with, and it's done in compile-time.
Helper functions
The first step of the plan is to take this tree and scan it for anything that looks like Roman Numerals. This being Lisp and all, let's try to do it somewhat functionally: We need a function that will do a deep traversal of a tree and return every object for which a provided function
searchp
returns true. This one is even (semi) tail-recursive.Then some code for parsing the roman numerals, courtesy of Rosetta Code:
The actual macro
We take the syntax tree (
body
), search it with our deep-find-all procedure and somehow make the roman numerals that we find, available.So, what is
1 + 2 + 3 + (4 * (5 + 6)) + 7
?And to see what actually happened when the macro was invoked:
la source
Lua
Simply a fallback __index for the global table. The actual conversion using gsub turned out much prettier than I imagined it to be.
la source
Postscript
I tried to follow the C one but I didn't understand it. So I did it this way:
Postscript doesn't have
enum
but we can construct a dictionary with sequential integer values and fold them into an array. This reduces the problem to generating all the strings in sequence, which is done by concatenating in 4 nested loops. So it generates all the strings, then interleaves each string with an increasing counter value, resulting in a long series of <string> <int> pairs on the stack which are wrapped in<<
...>>
to produce a dictionary object.The program constructs and installs a dictionary mapping all names for the roman numerals to their corresponding value. So mentioning the names in source text invokes the automatic name-lookup and yields the integer value on the stack.
prints
la source
Smalltalk (Smalltalk/X) (87/101 chars)
of course we could easily modify the parser's tokenizer (as it is part of the class library, and as such open for modification, and always present), but a challenge is to affect only evaluations in a given context, so that the rest of the system works as usual.
Version 1:
define a number of variables in the evaluation namespace. So this will affect interactive doIts (aka evals):
then I can do (in a doIt, but not in compiled code):
-> 2019
Notice: the 101 chars includes whitespace; actually it can be done with 87 chars.
Also notice, when define in the global Smalltalk namespace, I'd see those constants also in compiled code.
Version 2:
Use a methodWrapper hook, which allows for any existing code to be wrapped without recompiling. The following wraps the Parser's tokenizer to look for a roman identifier to be scanned and makes it an integer. The tricky part is to dynamically detect if the calling context is from the roman empire or not. This is done using a query signal (which is technically a proceedable exception):
define the query:
So we can ask at any time ("InRomanScope query") to get false by default.
Then wrap the scanner's checkIdentifier method:
Now the scanner works as usual, unless we are in the roman empire:
-> 2525
we can even compile code:
nice try; but this fails with a syntax error (which is exactly what we want). However, in the roman empire, we CAN compile:
and now, we can ask any integer (sending that message) from inside and outside of Rome:
-> 2525
la source
Haskell, using meta-programming in Template Haskell and roman-numerals:
Haskell reserves identifiers starting with upper case letters for constructors, so I used lower-case.
la source
J - 78 char
This only goes up to MMMCMXCIX = 3999, as with the other solutions.
Breaking it down (recall J is usually read from right to left, unless superseded by parentheses):
M`CDM`XLC`IVX
- Four boxes of letters. We're going to use numeric arrays into index into these letters and build up subwords of Roman numerals.841,3#79bc5yuukh
- This is the numeric data, tightly encoded.*(_1,~3#.inv])
- This will decode the above data, by expanding in ternary and appending -1.('';&;:(...){' ',[)&.>
- Pairing up the numbers on the left with the boxes on the right (&.>
), decode the arrays of numbers and use them to index into the letters. We treat 0 as space by prepending a space character to the letter lists. This procedure builds lists of words likeI II III IV V VI VII VIII IX
andM MM MMM
.{
- Take the Cartesian product of these four boxes full of words. Now we have a 4D array of all the Roman numerals.}.,;L:1
- Run all that into a single 1D list of Roman numerals, and remove the empty string at the front because it would create an error. (L:
is a rare sight in J golf! Usually there are not this many levels of boxing involved.)}.i.4e3
- The integers from 0 to 4000, excluding the endpoints.=:
. J allows you to have a boxed list of names on the LHS, as a form of computed multiple assignment, so this works out fine.Now the J namespace is full of variables representing Roman numerals.
* I need the number 2933774030998 to later be read in base 3. It so happens that I can express it in base 79 using digits no greater than 30, which is good because J can only understand digits up to 35 (0-9 and then a-z). This saves 3 characters over decimal.
la source
Python
The Idea is simple as the other answers. But Just to be neat and not to pollute the global namespace, a context manager is used. This also imposes the restriction, that you need to declare before hand, the extent of Roman numerical you are planning to use.
Note Just to keep it simple, and not to reinvent the wheel, I have utilized the Roman python package
Implementation
Demo
la source
Python
This is possibly the simplest solution using Python:
la source
globals()[var] = value
thanexec()
.D
using D's compile time function evaluation
la source
APL (Dyalog APL), 77 bytes
Prompts for Roman numeral maximum length and defines all variables.
t←
t gets'IVXLCDM',
Roman chars followed by⊂
an enclosed⍬
empty listt[
…]
index t with…⍉
the transposed (to get the right order)8⊥⍣¯1
appropriate width base-eight representation of⍳
the first n indices, where n is¯1+
one less than8*⎕
eight to the power of numeric input,/
flatten rows (each representation){
…}¨
apply the following anonymous function on each representation…(
…)[t⍳⍵]
corresponding to the positions of the argument's items in t, select from…∊
the enlisted1 5∘ר
one and five times each of10*
ten to the power of⍳4
zero through three0,⍨
append zero2(…)/
on each length-two sliding window, apply the following anonymous function train…⊣×
the left argument times¯1*
negative one to the power of<
whether the left argument is less than the right argument+/
sum⍵'←',
prepend the argument (the Roman numeral) and an assignment arrow⍕
format (to flatten and convert the number to text)⍎
execute that (makes the assignment outside the anonymous function)Try it online! (using max-length 5)
la source
PHP
There a several rules for valid roman numbers
Write the greatest value befor the lower values
Subtract only
[I,X,C]
before the next 2 greater valuesSubtract double
[I,X,C]
before the next 2 greater valuesSubtract double
[I,X,C]
before the greater valuesCombine 4+5
Online Version
Step 1 Create the rules
is the JSON output for all valid roman numbers
Step 2 Make lists for all rules till 3999
Step 3 Create constants
Combine all lists and define constants
Output
In the example mutiply two valid versions of the number 8
la source
Rebol
Example
Output:
Disclaimer: I'm sure there are other (and probably better!) ways of doing this in Rebol as well.
PS. My
roman-to-integer
function is a transliteration of histocrat's nice Ruby algorithm for converting Roman Numeral string into a number. Returned with thanks! +1la source
Lua
This effects the metatable of the global table, giving it a new index function. When a global variable which only contains roman numerals is asked for, eg
XVII
, it parses it.Easy to test;
Try it online!
la source
VBA, 204 bytes
A declared subroutine which takes no input, and when run, creates the
public
ly accessibleEnum
,R
, which contains all of the Roman Numeral values. These values may be used directly, without referencing the Enum.Enum hold values from 1 to 3999.
Note: Terminal
"
s on lines 3 and 7 are included for syntax highlighting only, and do not contribute to the bytecountUngolfed and Explained
la source