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.

Freira Furada
fonte
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.

Martin Ender
fonte
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.

Neil
fonte
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"))
coredump
fonte
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.

Masclins
fonte
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!

Mr Public
fonte
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]}"}
Value Ink
fonte
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.

MegaTom
fonte
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
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}

Experimente aqui: https://rextester.com/BJC92885

chau giang
fonte