¡Convierte a número romano!

13

Su tarea es convertir un entero positivo dado de un número arábigo a un número romano.

Las cosas se ponen difíciles cuando cuentas hasta 4000.

Los romanos hicieron esto agregando una línea sobre un símbolo para multiplicar ese símbolo por 1 000. Sin embargo, los overlines no son exactamente visibles en ASCII. Además, hay dobles líneas para multiplicar un símbolo por 1 000 000, y luego tres líneas para multiplicar un símbolo por 1 000 000 000, etc.

Por lo tanto, decidí usar paréntesis para reemplazar los overlines.

Los símbolos se pueden colocar individualmente entre paréntesis. Por ejemplo, ambos (VI)y (V)(I)son representaciones válidas de 6 000. (V)MTambién es una representación válida de 6000.

(I)Es una forma válida de representar 1 000.

Casos de prueba

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

Puntuación

Este es el . El código más corto en bytes gana.

Monja permeable
fuente
1
La justificación de por qué esto no es un duplicado desordena la especificación. Sería mejor sin ella OMI.
Mego
¿Dónde agregaría la justificación?
Leaky Nun
1
Déjalo afuera. Si alguien cuestiona si es un duplicado o no, tenga la discusión en comentarios o en el chat.
Mego
@Mego hecho. :-)
Leaky Nun
¿Es (IV)una representación aceptable de 4000?
Neil

Respuestas:

9

Mathematica, 67 bytes

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

Evita todos los problemas Mal convertir la entrada a la base 1000 y convertir cada dígito por separado con RomanNumeral. Luego los doblamos insertando (...)desde la izquierda.

Desafortunadamente, Mathematica representa ceros, Npor lo que debemos deshacernos de ellos.

Martin Ender
fuente
1
maldita Mathica con sus incorporados para todo> :(
OldBunny2800
1
@ OldBunny2800 Sin embargo, me sorprendería si esto no fuera superado por ninguno de los idiomas de golf.
Martin Ender
@ OldBunny2800 Y cuesta dinero real obtenerlo. Eso es malo.
Erik the Outgolfer
@ MartinBüttner ¿Pensé que simplemente RomanNumeralpodía hacerlo?
Leaky Nun
1
@KennyLau Produce MMMMpara 4000, solo comienza a trabajar para especificar en 5000(y luego obtiene el mismo problema para 4000000etc.). Incluso entonces, usa barras superpuestas en lugar de paréntesis. Si está de acuerdo con eso, debe decirlo en la especificación de desafío.
Martin Ender
7

JavaScript (ES6), 136 bytes

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

Para números menores de 4000, repite cada "letra" romana tantas veces como sea posible, utilizando la lista de "letras" romanas y sus valores decimales. De lo contrario, acumula recursivamente la respuesta de la división y el módulo con 1000. Afortunadamente, se repeattrunca para que no tenga que hacerlo yo mismo.

Neil
fuente
3

Lisp común, 108

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

Sin 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))))))

Pruebas

Dos pruebas dan resultados diferentes a los de la pregunta:

(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"))
volcado de memoria
fuente
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=")")

No es la mejor opción, pero creo que la idea debería ser bastante similar a esta.

Masclins
fuente
1

Pitón, 188 194

-6 bytes de deshacerse de algunos espacios en blanco

Este desafío me devolvió a cuando estaba aprendiendo a programar ...

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

Puede que no sea la solución más corta, pero me divertí jugando al golf este problema.

¡Pruébalo!

Señor público
fuente
1

Rubí, 137 134 130 bytes

Función recursiva que devuelve la cadena. Estoy tratando de descifrar las codificaciones numéricas un poco más si es posible, pero no estoy seguro de cómo.

Vaya, es prácticamente un puerto directo de la respuesta ES6 de @ Neil ahora.

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]}"}
Tinta de valor
fuente
1

Ruby, 185161144 bytes

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)}

Más de un año después de la publicación original, creo que aprendí algo sobre el golf.

Gracias Value Ink por sus valiosos comentarios.

MegaTom
fuente
gsubpuede tomar una cadena como primer argumento, eliminando la necesidad de sustituciones en un patrón regex ya s.gsub! x,yque lo hace automáticamente. Aparte de eso, probablemente pueda renunciar a la asignación de su amatriz, ya que solo la usa una vez y la coloca directamente en la each_slicellamada.
Value Ink el
"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...también funciona
Value Ink
También r[x]es funcionalmente equivalente a r.(x)cuando están involucradas lambdas stabby
Value Ink
@ValueInk gracias. ¡Ese r[x]truco va a ser útil para todo mi golf recursivo en Ruby!
MegaTom
1

TCL 134 bytes

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}

Pruébelo aquí: https://rextester.com/BJC92885

chau giang
fuente