Converta para numeral romano!


13

Sua tarefa é converter um número inteiro positivo de número arábico para número romano.

As coisas ficam difíceis quando você conta até 4000.

Os romanos fizeram isso adicionando uma linha acima de um símbolo para multiplicá-lo por 1 000. No entanto, as linhas de cima não são exatamente exibidas no ASCII. Além disso, existem linhas duplas para multiplicar um símbolo por 1 000 000e, em seguida, linha tripla para multiplicar um símbolo por 1 000 000 000, etc ...

Portanto, decidi usar parênteses para substituir as linhas excessivas.

Os símbolos podem ser colocados individualmente entre parênteses. Por exemplo, ambos (VI)e (V)(I)são representações válidas de 6 000. (V)Mtambém é uma representação válida de 6000.

(I)é uma maneira válida de representar 1 000.

Casos de teste

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

Pontuação

Isso é . O código mais curto em bytes vence.


1
A justificativa para por que essa não é uma duplicata desorganiza as especificações. Seria melhor sem ele IMO.
Mego

Onde eu adicionaria a justificativa?
Leaky Nun

1
Deixe isso de fora. Se alguém questionar se é ou não uma duplicata, converse nos comentários ou no chat.
Mego

@Mego Done. :-)
Freira gotejante

É (IV)uma representação aceitável de 4000?
187 Neil

Respostas:


9

Mathematica, 67 bytes

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

Evita todos os problemas Mconvertendo a entrada na base 1000 e convertendo cada dígito separadamente com RomanNumeral. Em seguida, dobramos-os inserindo (...)da esquerda.

Infelizmente, o Mathematica representa zeros, Nportanto precisamos nos livrar deles.


1
danem mathematica com seus builtins para tudo> :(
OldBunny2800 17/04

1
@ OldBunny2800 Eu ficaria surpreso se isso não fosse derrotado por qualquer um dos idiomas de golfe de qualquer maneira.
Martin Ender

@ OldBunny2800 E custa dinheiro real para obtê-lo. Isso é ruim.
Erik o Outgolfer

@ MartinBüttner eu pensei que simplesmente RomanNumeralpode fazê-lo?
gotejante Nun

1
@KennyLau Ele produz MMMMpara 4000, ele só começa a trabalhar a especificação em 5000(e, em seguida, você tem o mesmo problema para 4000000etc.). Mesmo assim, ele usa barras superiores em vez de parênteses. Se você está bem com isso, deve dizê-lo na especificação do desafio.
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 abaixo de 4000, repita cada "letra" romana o máximo de vezes possível, usando a lista de "letras" romanas e seus valores decimais. Caso contrário, recursivamente cria a resposta da divisão e do módulo com 1000. Felizmente, repeattrunca para que eu não precise fazer isso sozinho.


3

Lisp comum, 108

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

Ungolfed

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

Testes

Dois testes fornecem resultados diferentes dos da pergunta:

(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"))

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=")")

Não é praticamente a melhor opção, mas acho que a ideia deve ser bastante semelhante a isso.


1

Python, 188194

-6 bytes de se livrar de algum espaço em branco

Esse desafio me trouxe de volta a quando eu estava aprendendo 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

Pode não ser a solução mais curta, mas eu me diverti jogando golfe nesse problema.

Experimente!


1

Ruby, 137 134 130 bytes

Função recursiva que retorna a string. Estou tentando jogar as codificações numéricas um pouco mais, se possível, mas não sei como.

Opa, é praticamente uma porta direta da resposta ES6 do @ Neil agora.

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]}"}

1

Ruby, 185 161 144 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)}

Mais de um ano após o post original, acho que aprendi algo sobre golfe.

Obrigado Value Ink por seus valiosos comentários.


gsubpode usar uma string como o primeiro argumento, removendo a necessidade de substituições em um padrão regex, uma vez s.gsub! x,yque o faz automaticamente. Fora isso, você provavelmente pode simplesmente renunciar à atribuição do seu aarray, pois você o usa apenas uma vez e coloca-o diretamente na each_slicechamada.
Valor Ink

"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...funciona também
Value Ink

Também r[x]é funcionalmente equivalente a r.(x)sempre que estiver envolvido lambdas stabby #
Value Ink

@ValueInk obrigado. Esse r[x]truque será útil para todo o meu futuro golfe recursivo em rubi!
MegaTom

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.