Menambahkan, cara kuno

8

Gambaran Umum
Bangsa Romawi kuno merancang sistem angka menggunakan huruf Latin, yang melayani mereka dengan baik, dan yang masih digunakan oleh peradaban modern, meskipun pada tingkat yang jauh lebih kecil. Pada saat penggunaannya, orang Romawi harus belajar menggunakan dan memanipulasi angka-angka ini agar banyak digunakan untuk banyak aplikasi. Misalnya, jika seseorang memiliki 35 ekor sapi, dan ia memperoleh 27 ekor lagi, bagaimana ia bisa mengetahui jumlah total yang baru selain menghitung semuanya? ( Ok, itu dan menggunakan sempoa ... ) Jika orang-orang Romawi bisa melakukannya, tentunya kita juga bisa mengetahuinya.

Tujuan
Tulis algoritma / fungsi / program terpendek yang akan menambahkan dua angka Romawi bersama-sama dan menghasilkan hasilnya tanpa mengubah representasi string dari salah satu input menjadi angka.

Aturan / Kendala
Karena inkonsistensi historis / pra-abad pertengahan dalam format, saya akan menguraikan beberapa aturan non-standar (per penggunaan modern) untuk ortografi. Lihat panduan nilai di bawah ini sebagai contoh.

  • Huruf I, X, C, dan M dapat diulang hingga empat kali berturut-turut, tetapi tidak lebih. D, L, dan V tidak pernah bisa diulang.
  • Surat yang berada tepat di sebelah kanan surat lain dalam representasi Romawi akan memiliki nilai yang sama atau lebih rendah daripada di sebelah kirinya.
    • Dengan kata lain, VIIII == 9tetapi IX != 9dan tidak valid / tidak diizinkan.
  • Semua nilai input akan 2.000 (MM) atau kurang; tidak diperlukan representasi untuk angka yang lebih besar dari M.
  • Semua nilai input akan menjadi angka Romawi yang valid, sesuai dengan aturan di atas.
  • Anda tidak boleh mengonversi angka apa pun menjadi desimal, biner, atau sistem angka lainnya sebagai bagian dari solusi Anda (Anda boleh menggunakan metode seperti itu untuk MEMERVERIFIKASI hasil Anda).
  • Ini kode golf, jadi kode terpendek menang.

Panduan Nilai

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

Contohnya

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

Jika diperlukan klarifikasi lebih lanjut, silakan tanyakan.

Gaffi
sumber
2
XXXXIIII -> 44 atau XIIII -> 14?
Paul Richter
1
Saya pikir dia mengacu pada kesalahan dalam panduan nilai.
grc
@ grc Oh. Konyol saya ... Diperbaiki.
Gaffi
1
Mengapa ada orang yang ingin mengonversi ke basis yang berbeda? Apakah Anda benar-benar bermaksud melarang penguraian string ke nomor?
Peter Taylor
@PeterTaylor Ya, itu benar.
Gaffi

Jawaban:

5

APL ( 59 56)

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

Input pada satu baris (yaitu XII + XII, meskipun +tidak perlu).

Sunting: perubahan shift ke rotate untuk menyimpan tiga karakter - itu hanya masalah ketika jawaban ≥ 5000, yang seharusnya tidak pernah terjadi karena pertanyaan mengatakan nilai input akan selalu ≤ 2000. Satu-satunya efeknya sekarang "meluap" pada 5000, memberikan 5000 = 1, 5001 = 2, dll.

(Saya tidak benar-benar berpikir orang Romawi melakukannya dengan cara ini ... APL lebih merupakan sesuatu untuk orang Mesir Kuno saya pikir :))

Penjelasan:

  • : dapatkan input pengguna
  • (N←'MDCLXVI')∘=¨: store 'MDCLXVI' di N. Return, untuk setiap karakter string input, vektor dengan 1 di tempat karakter sesuai dengan salah satu dari 'MDCLXVI', dan 0 sebaliknya.
  • ⊃+/: Jumlahkan vektor dan de-encapsulate. Kami sekarang memiliki vektor dengan informasi tentang berapa banyak setiap angka Romawi yang kita miliki. Yaitu, jika inputnya adalah XXII XIIII, kita sekarang memiliki:
     MDCLXVI
     0 0 0 0 3 0 6
  • Perhatikan bahwa ini tidak mengubah nilai.
  • {... :... ... }adalah fungsi dengan konstruksi if-else.
  • D←7⍴5 2: Dadalah vektor 5 2 5 2 5 2 5. Ini adalah berapa banyak angka Romawi yang tidak diizinkan. Yaitu jika Anda memiliki 5 Is, itu terlalu banyak, dan jika Anda memiliki 2 Vs itu juga terlalu banyak. Vektor ini juga merupakan faktor penggandaan untuk setiap angka Romawi, yaitu a Vbernilai 5 Idetik dan Xbernilai 2 Vdetik.

  • ∨/K←⍵≥D: Kadalah vektor di mana ada 1 jika kita memiliki terlalu banyak angka Romawi dari jenis tertentu. ∨/ATAU vektor ini bersama-sama.

  • Jika vektor ini tidak semuanya nol:
  • K×D: Kalikan K dengan D. Vektor ini memiliki nol di mana kita tidak memiliki terlalu banyak angka Romawi, dan jumlah angka Romawi di mana kita melakukannya.
  • ⍵+(1⌽K): Putar K ke kiri sebanyak 1, dan tambahkan ke input. Untuk setiap angka Romawi yang kita miliki terlalu banyak, ini akan menambah satu dari yang berikutnya lebih tinggi.
  • ⍵+(1⌽K)-K×D: Kurangi ini dari vektor lainnya. Efeknya adalah, misalnya jika Anda memiliki 6 Is, itu akan menambah satu Vdan menghapus 4 Is.
  • : Perulangan.
  • ⋄⍵: Tetapi jika Ksemuanya nol, maka ⍵ mewakili angka Romawi yang valid, jadi kembalilah ⍵.
  • N⍴⍨¨: Untuk setiap elemen dari vektor yang dihasilkan, buat banyak angka Romawi yang sesuai.
  • ,/: Gabungkan vektor-vektor ini bersama-sama untuk menghilangkan spasi jelek di output.
marinus
sumber
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]

Mengambil satu string dari input (mis. VIII + XIIAtau VIII + XII =).

grc
sumber
3

Perl, 132 karakter

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}

Deklarasikan fungsi syang mengambil sejumlah argumen dan menjumlahkannya. Cukup mudah: menambahkan input, mengurangi segalanya menjadi Is dan kemudian segera mengembalikan angka Romawi. (Semoga ini tidak dihitung dengan menggunakan sistem angka unary!)

kotak roti
sumber
3

Ruby, 85 82 karakter

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

Versi ini mengambil input pada STDIN sebagai string tunggal (misalnya XXIIII + XXXXII) dan mencetak output ke STDOUT.

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

Yang kedua adalah implementasi sebagai fungsi. Mengambil dua (atau lebih) string dan mengembalikan nilai yang dijumlahkan. Pemakaian:

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

GNU Sed, 131 karakter

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

Python, 174 karakter

Algoritma yang sangat sederhana - hitung setiap digit, loop untuk menangani overflow ke yang berikutnya, cetak.
Membaca dari input standar. Sesuatu seperti itu XVI + CXXakan berfungsi (mengabaikan apa pun kecuali angka, sehingga +tidak benar-benar diperlukan).

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

doa:

a("MDCCCCLXXXXVIIII", "MDCCCCLXXXXVIIII")

Versi ungolfed:

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))
    }
  )
Pengguna tidak diketahui
sumber
1

JavaScript 195 179

Sistem saya cukup sederhana, mengurangi semua angka Romawi menjadi serangkaian Iuntuk kedua angka, bergabung dengan mereka dan kemudian membalikkan proses mengubah blok tertentu Imenjadi masing-masing versi yang lebih besar ...

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

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

Fitur:

  • String array yang dibatasi nol, lebih cepat daripada mengatur string array.
  • Mengurangi dua rekursi menjadi satu, dan menghitung ulang parameter untuk regex spesifik.
  • Lebih banyak operator ternary daripada yang bisa Anda coba!

Input dimasukkan melalui prompt dalam bentuk <first roman number>+<second roman number>(tanpa spasi), output dalam bentuk peringatan.

misalnya

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

VBA, 187 karakter

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
sumber
Seperti ohanya digunakan sekali, Anda dapat menyimpan 3 byte dengan menghapus tugas dan evaluasi dan menghubungkannya n Mod rlangsung ke String(pemanggilan fungsi
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)

Menempatkan beberapa instruksi di dalam slot ketiga dari foroperator biar saya simpan beberapa titik koma!

Saat input diminta, Anda memasukkan dua angka ( +dan spasi tidak diperlukan, tetapi jika Anda memasukkannya, Anda tidak mendapatkan kesalahan). Lalu peringatan menunjukkan jumlah.

Antonio Ragagnin
sumber
0

C ++, 319 karakter

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

Cobalah online!

Jörg Hülsermann
sumber