Agregando, la manera pasada de moda

8

Resumen
Los antiguos romanos idearon un sistema numérico usando letras latinas, que les sirvió bien, y que todavía es utilizado por la civilización moderna, aunque en un grado mucho menor. En el momento de su uso, los romanos habrían tenido que aprender a usar y manipular estos números para ser de gran utilidad en muchas aplicaciones. Por ejemplo, si un hombre poseía 35 bueyes y adquirió 27 más, ¿cómo conocería el nuevo total además de contarlos a todos? ( Ok, eso y usar un ábaco ... ) Si los romanos pudieran hacerlo, seguramente también podemos resolverlo.

Objetivo
Escribir el algoritmo / función / programa más corto que agregará dos números romanos y generará el resultado sin convertir la representación de cadena de cualquier entrada en un número.

Reglas / restricciones
Debido a las inconsistencias históricas / pre-medievales en el formato, voy a describir algunas reglas no estándar (por uso moderno) para la ortografía. Consulte la guía de valores a continuación como ejemplo.

  • Las letras I, X, C y M se pueden repetir hasta cuatro veces seguidas, pero no más. D, L y V nunca pueden repetirse.
  • La letra inmediatamente a la derecha de otra letra en la representación romana tendrá el mismo valor o menor que el de la izquierda.
    • En otras palabras, VIIII == 9pero IX != 9y es inválido / no permitido.
  • Todos los valores de entrada serán 2,000 (MM) o menos; no es necesaria una representación para números mayores que M.
  • Todos los valores de entrada serán un número romano válido, de acuerdo con las reglas anteriores.
  • No puede convertir ningún número a decimal, binario o cualquier otro sistema de números como parte de su solución (puede usar dicho método para VERIFICAR sus resultados).
  • Este es el código de golf, por lo que gana el código más corto.

Guía de valor

Symbol        Value
I             1
II            2
III           3
IIII          4
V             5
VIIII         9
X             10
XIIII         14
XXXXIIII      44
L             50
LXXXXVIIII    99
C             100
D             500
M             1,000

Ejemplos

XII + VIII = XX (12 + 8 = 20)
MCCXXII + MCCXXII = MMCCCCXXXXIIII (1,222 + 1,222 = 2,444)
XXIIII + XXXXII = LXVI (24 + 42 = 66)

Si necesita más aclaraciones, por favor pregunte.

Gaffi
fuente
2
XXXXIIII -> 44 o XIIII -> 14?
Paul Richter
1
Creo que se refiere a un error en la guía de valores.
grc
@grc Oh. Yo tonto ... arreglado.
Gaffi
1
¿Por qué alguien querría convertir a una base diferente? ¿Realmente quisiste prohibir analizar la cadena a un número?
Peter Taylor
@PeterTaylor Sí, eso es correcto.
Gaffi

Respuestas:

5

APL ( 59 56)

,/N⍴⍨¨{∨/K←⍵≥D←7⍴5 2:∇⍵+(1⌽K)-K×D⋄⍵}⊃+/(N←'MDCLXVI')∘=¨⍞

Entrada en una línea (es decir XII + XII, aunque +no es necesario).

Editar: cambio de turno para rotar para guardar tres caracteres: solo importa cuando la respuesta ≥ 5000, lo que nunca debería suceder ya que la pregunta dice que los valores de entrada siempre serán ≤ 2000. El único efecto es que ahora "se desborda" en 5000, dando 5000 = 1, 5001 = 2, etc.

(Realmente no creo que los romanos lo hicieran de esta manera ... APL es más algo para los antiguos egipcios, creo :))

Explicación:

  • : obtener la entrada del usuario
  • (N←'MDCLXVI')∘=¨: almacena 'MDCLXVI' en N. Devuelve, para cada carácter de la cadena de entrada, un vector con un 1 en el lugar donde el carácter corresponde a uno de 'MDCLXVI', y 0 en caso contrario.
  • ⊃+/: Suma los vectores y desencapsula. Ahora tenemos un vector con información sobre cuántos de cada número romano tenemos. Es decir, si la entrada fue XXII XIIII, ahora tenemos:
     MDCLXVI
     0 0 0 0 3 0 6
  • Tenga en cuenta que esto no está convirtiendo los valores.
  • {... :... ... }es una función con una construcción if-else.
  • D←7⍴5 2: Des el vector 5 2 5 2 5 2 5. Esta es la cantidad de números romanos que no están permitidos. Es decir, si tiene 5 Is, son demasiados, y si tiene 2 Vs, también son demasiados. Este vector también es el factor de multiplicación para cada número romano, es decir, a Vvale 5 Isy an Xvale 2 Vs.

  • ∨/K←⍵≥D: Kes el vector donde hay un 1 si tenemos demasiados números romanos de cierto tipo. ∨/O este vector juntos.

  • Si este vector no es todo ceros:
  • K×D: Multiplica K por D. Este vector tiene ceros donde no tenemos demasiados números romanos, y la cantidad de números romanos donde los tenemos.
  • ⍵+(1⌽K): Gire K hacia la izquierda en 1 y agréguelo a la entrada. Para cada número romano que tenemos demasiados, esto agregará uno del siguiente más alto.
  • ⍵+(1⌽K)-K×D: Resta esto del otro vector. El efecto es, por ejemplo, si tiene 6 Is, agregará uno Vy eliminará 4 Is.
  • : Recurse.
  • ⋄⍵: Pero si Ktodos fueron ceros, entonces ⍵ representa un número romano válido, así que devuelve ⍵.
  • N⍴⍨¨: Para cada elemento del vector resultante, cree muchos de los números romanos correspondientes.
  • ,/: Une estos vectores para deshacerse de los espacios feos en la salida.
marinus
fuente
5

Python, 100

s="IVXLCDM"
r=raw_input()
a=""
i=2
u=0
for c in s:r+=u/i*c;i=7-i;u=r.count(c);a+=u%i*c
print a[::-1]

Toma una cadena de entrada (p . Ej. VIII + XIIO VIII + XII =).

grc
fuente
3

Perl, 132 caracteres

sub s{@a=VXLCDM=~/./g;@z=(IIIII,VV,XXXXX,LL,CCCCC,DD);$r=join"",@_;
$r=~s/$a[-$_]/$z[-$_]/gfor-5..0;$r=~s/$z[$_]/$a[$_]/gfor 0..5;$r}

Declara la función sque toma cualquier número de argumentos y los suma. Bastante sencillo: agrega la entrada, reduce todo a Isy luego restaura inmediatamente los números romanos. (¡Espero que esto no cuente como usar el sistema de números unarios!)

caja de pan
fuente
3

Ruby, 85 82 caracteres

gets;r=0;v=5;puts"IVXLCDM".gsub(/./){|g|r+=$_.count g;t=r%v;r/=v;v^=7;g*t}.reverse

Esta versión toma la entrada en STDIN como una sola cadena (por ejemplo XXIIII + XXXXII) e imprime la salida en STDOUT.

f=->*a{r=0;v=5;"IVXLCDM".gsub(/./){|g|r+=(a*'').count g;t=r%v;r/=v;v^=7;g*t}.reverse}

El segundo es una implementación como una función. Toma dos (o más) cadenas y devuelve los valores sumados. Uso:

puts f["XXIIII", "XXXXII"]     # -> LXVI
Howard
fuente
3

GNU Sed, 131 caracteres

:;s/M/DD/;s/D/CCCCC/;s/C/LL/;s/L/XXXXX/;s/X/VV/;s/V/IIIII/;t;s/\W//g;:b;s/IIIII/V/;s/VV/X/;s/XXXXX/L/;s/LL/C/;s/CCCCC/D/;s/DD/M/;tb
Hasturkun
fuente
1

Python, 174 caracteres

Un algoritmo muy simple: cuente cada dígito, bucle para manejar el desbordamiento al siguiente, imprimir.
Lee desde la entrada estándar. Algo así XVI + CXXfuncionaría (ignora cualquier cosa excepto los números, por lo +que no se necesita realmente).

x="IVXLCDM"
i=raw_input()
d=dict((c,i.count(c))for c in x)
for c in x:
    n=2+3*(c in x[::2])
    if d[c]>=n:d[c]-=n;d[x[x.find(c)+1]]+=1
print"".join(c*d[c]for c in reversed(x))
Ugoren
fuente
1

Scala 150

val c="IVXLCDM"
def a(t:String,u:String)=((t+u).sortBy(7-c.indexOf(_))/:c.init)((s,z)=>{val i=c.indexOf(z)+1
s.replaceAll((""+z)*(2+i%2*3),""+c(i))})

invocación:

a("MDCCCCLXXXXVIIII", "MDCCCCLXXXXVIIII")

Versión sin golf:

val c = "IVXLCDM"
def add (t:String, u:String) = (
  (t+u).  // "MDCCCCLXXXXVIIIIMDCCCCLXXXXVIIII"
  sortBy(7-c.indexOf(_)) // MMDDCCCCCCCCLLXXXXXXXXVVIIIIIIII
  /: // left-fold operator to be used: (start /: rest) ((a,b)=> f (a,b)) 
  c.init) /* init is everything except the rest, so c.init = "IVXLCD"
    (because M has no follower to be replaced with */
  ((s, z) => { /* the left fold produces 2 elements in each step, 
    and the result is repeatedly s, on initialisation 
    MMDDCCCCCCCCLLXXXXXXXXVVIIIIIIII 
    and z is the iterated element from c.init, namely I, V, X, L, C, D
    in sequence */
    val i = c.indexOf (z) + 1 // 1, 2, ..., 7
    /* i % 2 produces 1 0 1 0 1 0
       *3 => 3 0 3 0 
       +2 => 5 2 5 2 
       (""+ 'I') * 5 is "IIIII", ("" + 'V') * 2 is "VV", ...
       ""+c(i) is "V", "X", ...
    */ 
    s.replaceAll (("" + z) * (2+i%2*3), "" + c (i))
    }
  )
usuario desconocido
fuente
1

JavaScript 195 179

Mi sistema es bastante rudimentario, reduzco todos los números romanos a una serie de Iambos números, unirlos y luego revertir el proceso convirtiendo ciertos bloques Ien sus respectivas versiones más grandes ...

Iteración 1 a="IIIII0VV0XXXXX0LL0CCCCC0DD0M".split(0);d=b=>x.replace(g=RegExp((c=z)>b?a[c][0]:a[c],"g"),c>b?a[b]:a[b][0]);x=prompt().replace("+","");for(z=6;0<z;z--)x=d(z-1);for(z=0;6>z;z++)x=d(z+1);alert(x)

Iteración 2 a="IIIII0VV0XXXXX0LL0CCCCC0DD0M".split(0);x=prompt().replace("+","");for(z=-6;6>z;z++)b=0>z?-z:z,c=0>z?~z:z+1,x=x.replace(g=RegExp(b>c?a[b][0]:a[b],"g"),b>c?a[c]:a[c][0]);alert(x)

caracteristicas:

  • Cadena de matriz delimitada por cero, más rápido que configurar una matriz de cadena.
  • Redujo las dos recursiones a la una y recalculó los parámetros para la expresión regular específica.
  • ¡Más operadores ternarios de los que puedes meter!

La entrada se ingresa mediante un indicador en forma de <first roman number>+<second roman number>(sin espacios), la salida en forma de alerta.

p.ej

XVI+VII // alert shows XXIII, correct!
MCCXXXIIII+DCCLXVI // alert shows MM, also correct!
WallyWest
fuente
1

VBA, 187 caracteres

Function c(f,s)
a=Split("I,V,X,L,C,D,M",",")
z=f & s
For i=0 To 6
x=Replace(z,a(i),"")
n=Len(z)-Len(x)+m
r=IIf(i Mod 2,2,5)
o=n Mod r
m=Int(n/r)
c=String(o,a(i)) & c
z=x
Next
End Function
Gaffi
fuente
Como osolo se usa una vez, puede ahorrar 3 bytes eliminando la asignación y evaluación de la misma y conectándose n Mod rdirectamente a la String(llamada de función
Taylor Scott
1

JavaScript, 190

x=prompt(r=[]);p=RegExp;s="MDCLXVI";for(i=-1;++i<7;){u=x.match(new p(s[i],'g'));if(u)r=r.concat(u)};for(r=r.join("");--i>0;){r=r.replace(new p(s[i]+'{'+(i%2==0?5:2)+'}','g'),s[i-1])}alert(r)

¡Poner algunas instrucciones dentro de la tercera ranura del foroperador me permite guardar algunos puntos y comas!

Cuando se solicita la entrada, inserta los dos números (los +espacios y no son necesarios, pero si los coloca no obtiene un error). Entonces la alerta te muestra la suma.

Antonio Ragagnin
fuente
0

C ++, 319 caracteres

#define A for(j=0;j<
#define B .length();j++){ 
#define C [j]==a[i]?1:0);}
#include <iostream>
int main(){std::string x,y,s,a="IVXLCDM";int i,j,k,l,m=0,n;std::cin>>x>>y;for(i=0;i<7;i++){k=0;l=0;A x B k+=(x C A y B l+=(y C n=k+l+m;m=(n)%(i%2?2:5);for(j=0;j<m;j++){s=a[i]+s;}m=(n)/(i%2?2:5);}std::cout<<s<<"\n";return 0;}
Gaffi
fuente
0

PHP, 136 bytes

for($r=join($argv);$c=($n=IVXLCDM)[$i];$r.=$p($n[++$i],$z/$d))$t=($p=str_repeat)($c,($z=substr_count($r,$c))%($d="52"[$i&1])).$t;echo$t;

Pruébalo en línea!

Jörg Hülsermann
fuente