Hinzufügen, die altmodische Art und Weise

8

Überblick
Die alten Römer entwickelten ein Zahlensystem mit lateinischen Buchstaben, das ihnen gute Dienste leistete und das von der modernen Zivilisation immer noch verwendet wird, wenn auch in viel geringerem Maße. In der Zeit seiner Verwendung hätten die Römer lernen müssen, diese Zahlen zu verwenden und zu manipulieren, um für viele Anwendungen von großem Nutzen zu sein. Wenn zum Beispiel ein Mann 35 Ochsen besaß und 27 weitere beschaffte, wie würde er dann die neue Summe kennen, außer sie alle zu zählen? ( Ok, das und mit einem Abakus ... ) Wenn die Römer es könnten, könnten wir es sicherlich auch herausfinden.

Ziel
Schreiben Sie den kürzesten Algorithmus / die kürzeste Funktion / das kürzeste Programm, mit dem zwei römische Ziffern addiert werden , und geben Sie das Ergebnis aus, ohne die Zeichenfolgendarstellung einer der Eingaben in eine Zahl umzuwandeln.

Regeln / Einschränkungen
Aufgrund historischer / vormittelalterlicher Inkonsistenzen bei der Formatierung werde ich einige nicht standardmäßige (für die moderne Verwendung) Regeln für die Rechtschreibung skizzieren. Siehe die unten stehende Wertanleitung als Beispiel.

  • Die Buchstaben I, X, C und M können bis zu vier Mal hintereinander wiederholt werden, jedoch nicht mehr. D, L und V können niemals wiederholt werden.
  • Der Buchstabe unmittelbar rechts von einem anderen Buchstaben in der römischen Darstellung hat den gleichen oder einen geringeren Wert als der links davon.
    • Mit anderen Worten, VIIII == 9aber IX != 9und ist ungültig / nicht erlaubt.
  • Alle Eingabewerte betragen 2.000 (MM) oder weniger. Für Zahlen größer als M ist keine Darstellung erforderlich.
  • Alle Eingabewerte sind eine gültige römische Ziffer gemäß den obigen Regeln.
  • Sie dürfen im Rahmen Ihrer Lösung keine Zahlen in Dezimal-, Binär- oder andere Zahlensysteme konvertieren (Sie können gerne eine solche Methode verwenden, um Ihre Ergebnisse zu überprüfen ).
  • Dies ist Code Golf, also gewinnt der kürzeste Code.

Werteführer

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

Beispiele

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

Wenn weitere Erläuterungen erforderlich sind, fragen Sie bitte.

Gaffi
quelle
2
XXXXIIII -> 44 oder XIIII -> 14?
Paul Richter
1
Ich denke, er bezieht sich auf einen Fehler in der Wertermittlung.
Grc
@grc Oh. Blöd mich ... behoben.
Gaffi
1
Warum sollte jemand auf eine andere Basis konvertieren wollen? Wollten Sie eigentlich verbieten, die Zeichenfolge auf eine Zahl zu analysieren?
Peter Taylor
@ PeterTaylor Ja, das ist richtig.
Gaffi

Antworten:

5

APL ( 59 56)

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

Eingabe in einer Zeile (dh XII + XIIobwohl dies +nicht erforderlich ist).

Bearbeiten: Verschiebung geändert, um zu drehen, um drei Zeichen zu speichern - es ist nur wichtig, wenn die Antwort ≥ 5000 ist, was niemals passieren sollte, da die Frage besagt, dass die Eingabewerte immer ≤ 2000 sind. Der einzige Effekt ist, dass es jetzt bei 5000 "überläuft", was ergibt 5000 = 1, 5001 = 2 usw.

(Ich glaube nicht, dass die Römer es so gemacht haben ... APL ist eher etwas für alte Ägypter, denke ich :))

Erläuterung:

  • : Benutzereingaben abrufen
  • (N←'MDCLXVI')∘=¨: 'MDCLXVI' in N speichern. Für jedes Zeichen der Eingabezeichenfolge einen Vektor mit einer 1 an der Stelle zurückgeben, an der das Zeichen einem von 'MDCLXVI' entspricht, andernfalls 0.
  • ⊃+/: Summiere die Vektoren und entkapsele sie. Wir haben jetzt einen Vektor mit Informationen darüber, wie viele von jeder römischen Ziffer wir haben. Dh wenn die Eingabe war XXII XIIII, haben wir jetzt:
     MDCLXVI
     0 0 0 0 3 0 6
  • Beachten Sie, dass hierdurch die Werte nicht konvertiert werden.
  • {... :... ... }ist eine Funktion mit einem if-else-Konstrukt.
  • D←7⍴5 2: Dist der Vektor 5 2 5 2 5 2 5. So viele römische Ziffern sind nicht erlaubt. Das heißt, wenn Sie 5 Is haben, sind das zu viele, und wenn Sie 2 Vs haben, sind das auch zu viele. Dieser Vektor ist zufällig auch der Multiplikationsfaktor für jede römische Ziffer, dh a Vist 5 Is wert und an Xist 2 Vs wert .

  • ∨/K←⍵≥D: Kist der Vektor, in dem es eine 1 gibt, wenn wir zu viele römische Ziffern einer bestimmten Art haben. ∨/ODERs diesen Vektor zusammen.

  • Wenn dieser Vektor nicht alle Nullen ist:
  • K×D: Multipliziere K mit D. Dieser Vektor hat Nullen, bei denen wir nicht zu viele römische Ziffern haben, und die Anzahl der römischen Ziffern, bei denen wir dies tun.
  • ⍵+(1⌽K): Drehen Sie K um 1 nach links und fügen Sie es dem Eingang hinzu. Für jede römische Zahl, die wir zu viele haben, wird eine der nächsthöheren hinzugefügt.
  • ⍵+(1⌽K)-K×D: Subtrahiere dies vom anderen Vektor. Der Effekt ist, wenn Sie beispielsweise 6 Is haben, wird eine hinzugefügt Vund 4 Is entfernt.
  • : Rekurs.
  • ⋄⍵: Wenn Kaber alle Nullen waren, dann steht ⍵ für eine gültige römische Ziffer, also geben Sie ⍵ zurück.
  • N⍴⍨¨: Erstellen Sie für jedes Element des resultierenden Vektors so viele der entsprechenden römischen Ziffern.
  • ,/: Verbinden Sie diese Vektoren miteinander, um die hässlichen Leerzeichen in der Ausgabe zu entfernen.
Marinus
quelle
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]

Nimmt eine Zeichenfolge von der Eingabe (z . B. VIII + XIIoder VIII + XII =).

grc
quelle
3

Perl, 132 Zeichen

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}

Deklariert eine Funktion, sdie eine beliebige Anzahl von Argumenten akzeptiert und summiert. Ziemlich einfach: Es hängt die Eingabe an, reduziert alles auf Is und stellt dann sofort die römischen Ziffern wieder her. (Hoffentlich zählt dies nicht als Verwendung des unären Zahlensystems!)

Brot-Box
quelle
3

Ruby, 85 82 Zeichen

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

Diese Version nimmt die Eingabe in STDIN als einzelne Zeichenfolge (z. B. XXIIII + XXXXII) auf und druckt die Ausgabe in STDOUT.

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

Die zweite ist eine Implementierung als Funktion. Nimmt zwei (oder mehr) Zeichenfolgen und gibt die summierten Werte zurück. Verwendungszweck:

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

GNU Sed, 131 Zeichen

:;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
quelle
1

Python, 174 Zeichen

Ein sehr einfacher Algorithmus - zählen Sie jede Ziffer, Schleife, um den Überlauf zur nächsten zu verarbeiten, drucken Sie.
Liest von der Standardeingabe. So etwas XVI + CXXwürde funktionieren (ignoriert alles außer Ziffern, daher wird das +nicht wirklich benötigt).

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

Aufruf:

a("MDCCCCLXXXXVIIII", "MDCCCCLXXXXVIIII")

ungolfed Version:

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))
    }
  )
Benutzer unbekannt
quelle
1

JavaScript 195 179

Mein System ist ziemlich rudimentär, reduzieren Sie alle römischen Ziffern auf eine Reihe von Ifür beide Zahlen, verbinden Sie sie und kehren Sie dann den Prozess um, indem Sie bestimmte Blöcke Iin ihre jeweiligen größeren Versionen verwandeln ...

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

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

Eigenschaften:

  • Null-begrenzte Array-Zeichenfolge, schneller als das Einrichten eines Zeichenfolgen-Arrays.
  • Reduzierte die beiden Rekursionen auf die eine und berechnete die Parameter für den spezifischen regulären Ausdruck neu.
  • Mehr ternäre Operatoren, als Sie sich vorstellen können!

Die Eingabe erfolgt über eine Eingabeaufforderung in Form von <first roman number>+<second roman number>(keine Leerzeichen), die Ausgabe in Form einer Warnung.

z.B

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

VBA, 187 Zeichen

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
quelle
Da oes nur einmal verwendet wird, können Sie 3 Bytes sparen, indem Sie die Zuordnung und Auswertung entfernen und n Mod rdirekt in den String(Funktionsaufruf einstecken
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)

Wenn Sie eine Anweisung in den dritten Steckplatz des forOperators einfügen, kann ich einige Semikolons speichern!

Wenn Sie zur Eingabe aufgefordert werden, geben Sie die beiden Zahlen ein (die +Leerzeichen und sind nicht erforderlich, aber wenn Sie sie eingeben, wird kein Fehler angezeigt). Dann zeigt Ihnen der Alarm die Summe.

Antonio Ragagnin
quelle
0

C ++, 319 Zeichen

#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
quelle
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;

Probieren Sie es online aus!

Jörg Hülsermann
quelle