Convertissez en chiffre romain!

13

Votre tâche consiste à convertir un entier positif donné du chiffre arabe en chiffre romain.

Les choses deviennent difficiles quand on compte jusqu'à 4000.

Les romains l'ont fait en ajoutant une ligne au-dessus d'un symbole pour multiplier ce symbole par 1 000. Cependant, les surlignages ne sont pas exactement affichables en ASCII. En outre, il existe des doubles surlignages pour multiplier un symbole par 1 000 000, puis un triple surlignage pour multiplier un symbole par 1 000 000 000, etc.

Par conséquent, j'ai décidé d'utiliser des parenthèses pour remplacer les surlignages.

Les symboles peuvent être placés individuellement entre parenthèses. Par exemple, les deux (VI)et (V)(I)sont des représentations valides de 6 000. (V)Mest également une représentation valide de 6000.

(I)est une façon valable de représenter 1 000.

Cas de test

Input: 1
Output: I
Input: 2
Output: II
Input: 3
Output: III
Input: 4
Output: IV
Input: 15
Output: XV
Input: 40
Output: XL
Input: 60
Output: LX
Input: 67
Output: LXVII
Input: 400
Output: CD
Input: 666
Output: DCLXVI
Input: 3000
Output: MMM
Input: 3999
Output: MMMCMXCIX
Input: 4000
Output: M(V)
Input: 4999
Output: M(V)CMXCIX
Input: 6000
Output: (VI)
Input: 6000000
Output: ((VI))
Input: 6006000
Output: ((VI)VI)
Input: 6666666666
Output: (((VI)DCLXVI)DCLXVI)DCLXVI

Notation

C'est du . Le code le plus court en octets gagne.

Leaky Nun
la source
1
La justification de pourquoi ce n'est pas un doublon encombre la spécification. Ce serait mieux sans l'OMI.
Mego
Où ajouter la justification?
Leaky Nun
1
Laisser de côté. Si quelqu'un se demande s'il s'agit d'un doublon, discutez-en dans les commentaires ou dans le chat.
Mego
@Mego Done. :-)
Leaky Nun
Est (IV)une représentation acceptable de 4000?
Neil

Réponses:

9

Mathematica, 67 octets

Fold["("<>#<>")"<>#2&,RomanNumeral[#~IntegerDigits~1000]/."N"->""]&

Évite tout problème avec la Mconversion de l'entrée en base 1000 et la conversion de chaque chiffre séparément avec RomanNumeral. Nous les replions ensuite en les insérant (...)par la gauche.

Malheureusement, Mathematica représente des zéros Net nous devons donc nous en débarrasser.

Martin Ender
la source
1
sacrément mathématique avec ses fonctions intégrées pour tout> :(
OldBunny2800
1
@ OldBunny2800 Je serais surpris si cela n'était pas battu par aucune des langues de golf de toute façon.
Martin Ender
@ OldBunny2800 Et cela coûte vraiment de l'argent pour l'obtenir. C'est mauvais.
Erik the Outgolfer
@ MartinBüttner Je pensais simplement RomanNumeralpouvoir le faire?
Leaky Nun
1
@KennyLau Il produit MMMMpour 4000, il ne commence à travailler que sur spec 5000(et vous obtenez le même problème pour 4000000etc.). Même dans ce cas, il utilise des barres supérieures au lieu de parenthèses. Si cela vous convient, vous devez le dire dans la spécification du défi.
Martin Ender
7

JavaScript (ES6), 136 octets

f=n=>n<4e3?"M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".replace(/(\D+)(\d+)/g,(_,r,d)=>r.repeat(n/d,n%=d)):`(${f(n/1e3)})`+f(n%1e3)

Pour les nombres inférieurs à 4000, répète chaque "lettre" romaine autant de fois que possible, en utilisant la liste des "lettres" romaines et leurs valeurs décimales. Sinon, construit récursivement la réponse de la division et du module avec 1000. Heureusement repeattronque donc je n'ai pas à le faire moi-même.

Neil
la source
3

Lisp commun, 108

(defun p(n)(if(> n 0)(if(< n 4000)(format()"~@R"n)(format()"(~A)~@[~A~]"(p(floor n 1000))(p(mod n 1000))))))

Non golfé

(defun p(n)
  (if (> n 0)
      (if (< n 4000)

          ;; Built-in Roman formatter (between 1 and 3999)
          (format () "~@R" n)

          ;; Divide N by 1000, as 1000*Q + R.
          ;; First print (p Q) in parentheses (recursively)
          ;; Then, if it is not NIL, the remainder R.
          (format () "(~A)~@[~A~]"
                  (p (floor n 1000))
                  (p (mod n 1000))))))

Les tests

Deux tests donnent des résultats différents de ceux de la question:

(loop for (in out) in '((1 "I")
                        (2 "II")
                        (3 "III")
                        (4 "IV")
                        (15 "XV")
                        (40 "XL")
                        (60 "LX")
                        (67 "LXVII")
                        (400 "CD")
                        (666 "DCLXVI")
                        (3000 "MMM")
                        (3999 "MMMCMXCIX")
                        (4000 "M(V)")
                        (4999 "M(V)CMXCIX")
                        (6000 "(VI)")
                        (6000000 "((VI))")
                        (6006000 "((VI)VI)")
                        (6666666666 "(((VI)DCLXVI)DCLXVI)DCLXVI"))
   for computed = (p in)
   unless (string= out computed)
   collect (list in out computed))

=> ((4000 "M(V)" "(IV)")
    (4999 "M(V)CMXCIX" "(IV)CMXCIX"))
coredump
la source
2

R, 134

m=1000;x=scan();while(x[1]>=m)x=c(floor(x[1]/m),x[1]%%m,x[-1]);cat(rep("(",length(x)),sep="");cat(as.character(as.roman(x)),sep=")")

Ce n'est pas la meilleure option, mais je pense que l'idée devrait être assez similaire à cela.

Masclins
la source
1

Python, 188 194

-6 octets pour se débarrasser de certains espaces

Ce défi m'a ramené à la première fois que j'ai appris à programmer ...

def f(x,s=zip("M CM D CD C XC L XL X IX V IV I".split(),[1e3,900,500,400,100,90,50,40,10,9,5,4,1])):
 r=""if x<4e3else"("+f(x/1e3)+")";x%=1e3
 for a,b in s:
    while x>=b:r+=a;x-=b
 return r

Ce n'est peut-être pas la solution la plus courte, mais je me suis amusé à jouer à ce problème.

Essaye le!

Mr Public
la source
1

Rubis, 137 134 130 octets

Fonction récursive qui renvoie la chaîne. J'essaie de jouer un peu plus sur les encodages numériques si possible, mais je ne sais pas comment.

Oups, c'est pratiquement un port direct de la réponse ES6 de @ Neil maintenant.

f=->x{(x<t=1e3)?"CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".gsub(/(\D+)(\d+)/){v=$2.to_i;s=x/v;x%=v;$1*s}:"(#{f[x/t]})#{f[x%t]}"}
Encre de valeur
la source
1

Rubis, 185161144 octets

r=->i{i>(t=1e3)? "(#{r[i/t]})"+r[i%t]:(s=?I*i;"IVXXLCCDM".scan(/(.)(.)(.)/){|x,y,z|{x*5=>y,x*4=>x+y,y*2=>z,y+x+y=>x+z}.map{|x,y|s.gsub!x,y}};s)}

Plus d'un an après la publication originale, je pense avoir appris quelque chose sur le golf.

Merci Value Ink pour vos précieux commentaires.

MegaTom
la source
gsubpeut prendre une chaîne comme premier argument, supprimant le besoin de substitutions dans un modèle d'expression régulière car s.gsub! x,yil le fait automatiquement. En dehors de cela, vous pouvez probablement simplement renoncer à l'affectation de votre atableau puisque vous ne l'utilisez qu'une seule fois et le placez directement dans l' each_sliceappel.
Value Ink
"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...fonctionne aussi
Value Ink
Est également r[x]fonctionnellement équivalent à r.(x)chaque fois que des lambdas stabby sont impliqués
Value Ink
@ValueInk merci. Cette r[x]astuce va être utile pour tout mon futur golf récursif en rubis!
MegaTom
1

TCL 134 octets

proc f r {
set map {M 1000+ CM 900+ D 500+ CD 400+ C 100+ XC 90+ L 50+ XL 40+ X 10+ IX 9+ V 5+ IV 4+ I 1+}
expr [string map $map $r]0}

Essayez-le ici: https://rextester.com/BJC92885

chau giang
la source