Hitung mulai dari 1 hingga 100 ... dalam Angka Romawi


29

Tulis program yang menghitung dari 1 hingga 100 dalam Angka Romawi dan cetak angka-angka ini dengan output standar. Masing-masing angka harus dipisahkan dengan spasi.

Anda tidak dapat menggunakan fungsi bawaan untuk mengubah ke angka romawi atau aplikasi eksternal atau pustaka untuk melakukannya.

Hasil yang diinginkan adalah

I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX XX XXI XXII XXIII XXIV XXV XXVI XXVII XXVIII XXIX XXX XXXI XXXII XXXIII XXXIV XXXV XXXVI XXXVII XXXVIII XXXIX XL XLI XLII XLIII XLIV XLV XLVI XLVII XLVIII XLIX L LI LII LIII LIV LV LVI LVII LVIII LIX LX LXI LXII LXIII LXIV LXV LXVI LXVII LXVIII LXIX LXX LXXI LXXII LXXIII LXXIV LXXV LXXVI LXXVII LXXVIII LXXIX LXXX LXXXI LXXXII LXXXIII LXXXIV LXXXV LXXXVI LXXXVII LXXXVIII LXXXIX XC XCI XCII XCIII XCIV XCV XCVI XCVII XCVIII XCIX C

Karena ini adalah tantangan kode golf, kode terpendek menang .


4
39 tidak ada tanda X.
Thor

@ Guru Tetap, terima kasih;)
Averroes

1
Saya benar-benar ingin menggunakan INTERCAL untuk yang satu ini.
Weijun Zhou

dapatkah dipisahkan oleh baris baru? Juga bagaimana dengan trailing / memimpin spasi / baris baru?
FantaC

Jawaban:


68

Perl 69 byte

s;.;y/XVI60-9/CLXVIX/dfor$a[$_].="32e$&"%72726;gefor 1..100;print"@a"

Bekerja dengan formula ajaib. Ekspresi "32e$&"%72726mengubah setiap digit dengan cara berikut:
0⇒32, 1⇒320, 2⇒3200, 3⇒32000, 4⇒29096, 5⇒56, 6⇒560, 7⇒5600, 8⇒56000, 9⇒50918

Setelah menerapkan terjemahan y/016/IXV/, kami memiliki ini sebagai gantinya:
0⇒32, 1⇒32 I , 2⇒32 II , 3⇒32 III , 4⇒29 I 9 V , 5⇒5 V , 6⇒5 VI , 7⇒5 VII , 8⇒5 VIII , 9⇒5 I 9 X 8

Sisa digit ( 2-57-9) dihapus. Perhatikan bahwa ini dapat ditingkatkan dengan satu byte dengan menggunakan formula yang diterjemahkan 012bukan 016, menyederhanakan /XVI60-9/untuk /XVI0-9/. Saya tidak dapat menemukan satu, tapi mungkin Anda akan lebih beruntung.

Setelah satu digit ditransformasi dengan cara ini, proses berulang untuk digit berikutnya, menambahkan hasilnya, dan menerjemahkan sebelumnya XVIke CLXpada saat yang sama terjemahan untuk digit baru terjadi.

Perbarui
Pencarian lengkap tidak mengungkapkan apa pun yang lebih pendek. Namun, saya menemukan solusi 69 byte alternatif:

s;.;y/XVI0-9/CLXIXV/dfor$a[$_].="57e$&"%474976;gefor 1..100;print"@a"

Yang ini menggunakan 0-2substitusi untuk IXV, tetapi memiliki modulo yang satu digit lebih panjang.


Pembaruan: 66 65 byte

Versi ini sangat berbeda, jadi saya mungkin harus mengatakan beberapa kata tentang itu. Rumus yang digunakannya sebenarnya satu byte lebih panjang!

Karena tidak dapat mempersingkat formula, saya memutuskan untuk mengurangi apa yang saya miliki. Tidak lama sampai saya ingat teman lama saya $\. Ketika printstatment dikeluarkan, $\secara otomatis ditambahkan ke akhir output. Saya dapat menyingkirkan $a[$_]konstruksi canggung untuk peningkatan dua byte:

s;.;y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726;ge,$\=!print$"for 1..100

Jauh lebih baik, tapi itu $\=!print$"masih tampak agak bertele-tele. Saya kemudian ingat formula panjang alternatif yang sama yang saya temukan yang tidak mengandung angka 3dalam transformasi digitnya. Jadi, seharusnya bisa digunakan $\=2+printsebagai gantinya, dan gantikan hasilnya 3dengan spasi:

s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;ge,$\=2+print for 1..100

Juga 67 byte, karena spasi yang diperlukan antara printdan for.

Sunting : Ini dapat ditingkatkan dengan satu byte, dengan memindahkan printke depan:

$\=2+print!s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;gefor 1..100

Karena substitusi perlu dievaluasi sepenuhnya sebelum print, penugasan ke $\masih akan terjadi terakhir. Menghapus spasi putih di antara gedan forakan mengeluarkan peringatan penghentian, tetapi sebaliknya valid.

Tetapi, jika ada formula yang tidak menggunakan di 1mana pun, $\=2+printmenjadi $\=printpenghematan dua byte lagi. Bahkan jika itu satu byte lebih lama, itu masih akan menjadi perbaikan.

Ternyata, formula seperti itu memang ada, tetapi satu byte lebih panjang dari aslinya, menghasilkan skor akhir 65 byte :

$\=print!s;.;y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366;gefor 1..100

Metodologi

Pertanyaannya adalah bagaimana orang bisa menemukan formula seperti itu. Secara umum, menemukan formula ajaib untuk menggeneralisasi set data apa pun adalah masalah probabilitas. Artinya, Anda ingin memilih bentuk yang mungkin menghasilkan sesuatu yang mirip dengan hasil yang diinginkan.

Mengeluarkan beberapa angka romawi pertama:

0:
1: I
2: II
3: III
4: IV
5: V
6: VI
7: VII
8: VIII
9: IX

ada beberapa keteraturan untuk dilihat. Khususnya, dari 0-3 dan sekali lagi dari 5-8 , setiap istilah berturut-turut bertambah panjangnya dengan satu angka. Jika kami ingin membuat pemetaan dari angka ke angka, kami ingin memiliki ekspresi yang juga bertambah panjang satu digit untuk setiap istilah berturut-turut. Pilihan logis adalah k • 10 d di mana d adalah digit yang sesuai, dan k adalah konstanta bilangan bulat apa pun.

Ini berfungsi untuk 0-3 , tetapi 4 perlu memutus pola. Apa yang bisa kita lakukan di sini adalah menempel pada modulo:
k • 10 d % m , di mana m berada di antara k • 10 3 dan k • 10 4 . Ini akan membuat rentang 0-3 tidak tersentuh, dan memodifikasi 4 sehingga tidak akan mengandung empat Is. Jika kami juga membatasi algoritma pencarian kami sehingga residu modular 5 , sebut saja j , kurang dari m / 1000 , ini akan memastikan bahwa kami juga memiliki keteraturan dari 5-8 juga. Hasilnya kira-kira seperti ini:

0: k
1: k0
2: k00
3: k000
4: ????
5: j
6: j0
7: j00
8: j000
9: ????

Seperti yang Anda lihat, jika kita ganti 0dengan I, 0-3 dan 5-8 semuanya dijamin akan dipetakan dengan benar! Nilai untuk 4 dan 9 perlu dipaksakan dengan kasar. Secara khusus, 4 harus mengandung satu 0dan satu j(dalam urutan itu), dan 9 perlu mengandung satu 0, diikuti oleh satu digit lain yang tidak muncul di tempat lain. Tentu saja, ada sejumlah formula lain, yang oleh beberapa kebetulan kebetulan dapat menghasilkan hasil yang diinginkan. Beberapa dari mereka bahkan mungkin lebih pendek. Tapi saya tidak berpikir ada yang mungkin berhasil seperti ini.

Saya juga bereksperimen dengan beberapa penggantian untuk Idan / atau Vdengan beberapa keberhasilan. Namun sayang, tidak ada yang lebih pendek dari apa yang sudah saya miliki. Berikut adalah daftar solusi terpendek yang saya temukan (jumlah solusi 1-2 byte lebih berat terlalu banyak untuk dicantumkan):

y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726
y/XVI0-9/CLXIXV/dfor$\.="57e$&"%474976
y/XVI0-9/CLXIVXI/dfor$\.="49e$&"%87971

y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%10606  #
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%15909  # These are all essentially the same
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%31818  #

y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535  # Doesn't contain 3 anywhere

y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366 # Doesn't contain 1 anywhere

3
Bagaimana Anda menemukan formula ajaib?
Ruben Verborgh

1
@RubenVerborgh Saya akan segera memperbarui posting saya dengan informasi lebih lanjut mengenai metodologi ini.
primo

15

HTML + JavaScript + CSS (137)

HTML (9)

<ol></ol>

JavaScript (101)

for(i=1;i<=100;i++){document.getElementsByTagName('ol')[0].appendChild(document.createElement('li'))}

CSS (27)

ol{list-style:upper-roman​}

Keluaran

Daftar bernomor dengan angka romawi

...

Demo di JSBin


1
81 byte versi JS-only: document.write('<ol>'+"<li style='list-style:upper-roman'/>".repeat(100)+'</ol>')(ES6)
Paperjam

atau 66 di Chromedocument.write("<li style='list-style:upper-roman'/>".repeat(100))
Slai

10

Python 116

kode golf yang lebih baik dari jawaban scleaver:

r=lambda a,b,c:('',a,2*a,3*a,a+b,b,b+a,b+a+a,b+3*a,a+c);print' '.join(i+j for i in r(*'XLC')for j in r(*'IVX'))+' C'

8

Python, 139

print' '.join(' '.join(i+j for  j in ' _I_II_III_IV_V_VI_VII_VIII_IX'.split('_'))for i in ' _X_XX_XXX_XL_L_LX_LXX_LXXX_XC'.split('_'))+' C'

6

C, 177 160 147 karakter

Ada solusi yang lebih pendek, tetapi tidak ada dalam C, jadi inilah upaya saya.

Solusi baru, sangat berbeda dari yang sebelumnya:

char*c;
f(n){
    printf("%.*s",n%5>3?2:n%5+n/5,c+=n%5>3?n%4*4:2-n/5);
}
main(i){
        for(;i<100;putchar(32))
                c="XLXXXC",f(i/10),
                c="IVIIIX",f(i++%10);
        puts("C");
}

Solusi sebelumnya (160 karakter):

Logika:
1. fmencetak angka dari 1 hingga 10. cadalah angka yang digunakan, yang dapat berupa IVXatau XLC. Dipanggil satu kali untuk puluhan satu kali untuk yang satu.
2. Jika n%5==0- tidak mencetak apa pun atau c[n/5]yang Iatau V(atau Latau C).
3. Jika n%4==4- 4atau 9- cetak I(atau X), oleh n+1.
4. Jika n>4- cetak 5(yaitu Vatau L) lalu n-5.
5. Jika n<4- cetak Ilalu n-1(yaitu nwaktu I).

char*c;
p(c){putchar(c);}
f(n){
        n%5?
                n%5>3?
                        f(1),f(n+1):
                        n>4?
                                f(5),f(n-5):
                                f(n-1,p(*c)):
                n&&p(c[n/5]);
}
main(i){
        for(;++i<101;p(32))
                c="XLC",f(i/10),
                c="IVX",f(i%10);
        p(10);
}

137:f(c,n){printf("%.*s",n%5>3?2:n%5+n/5,"XLXXXCIVIIIX "+c+(n%5>3?n%4*4:2-n/5));}main(i){for(;i<100;f(12,4))f(0,i/10),f(6,i++%10);puts("C");}
gastropner

5

JavaScript, 123

Terinspirasi oleh versi yang lebih panjang, saya menemukan di newsgroup Polandia (setidaknya, Chrome pikir itu Polandia).

for(i=100,a=[];n=i--;a[i]=r)
  for(r=y='',x=5;n;y++,x^=7)
    for(m=n%x,n=n/x^0;m--;)
      r='IVXLC'[m>2?y+n-(n&=-2)+(m=1):+y]+r;
alert(a)

5

Q ( 81 80)

2nd cut:

1_,/'[($)``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX],"C"

1st cut:

1_,/'[$:[``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX]],"C"

4

Python, 168

r=lambda n,l,v:(r(n,l[1:],v[1:])if n<v[0]else l[0]+r(n-v[0],l,v))if n else''
for i in range(1,101):print r(i,'C XC L XL X IX V IV I'.split(),[100,90,50,40,10,9,5,4,1]),

Penjelasan

Dengan menggunakan nilai-nilai ini, ambil nilai terbesar yang tidak lebih besar dari n dan kurangi dari n. Ulangi sampai n adalah 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1

1
r=lambda n,l,v:n and(n<v[0]and r(n,l[1:],v[1:])or l[0]+r(n-v[0],l,v))or""menyimpan dua karakter. Kalau tidak, sangat bagus.
cemper93

4

Ruby 1.9, 140 132

r=" "
100.times{r+=?I
0while[[?I*4,"IV"],["VIV","IX"],[?X*4,"XL"],["LXL","XC"],[/(.)((?!\1)[^I])\1/,'\2']].any?{|q|r.sub! *q}
$><<r}

Ini secara harfiah dihitung dari 1 hingga 100 dalam angka Romawi. Mulai dengan string kosong, kemudian loop melalui menambahkan "I" dan kemudian berulang kali menerapkan serangkaian aturan substitusi, secara efektif menambahkan 1.

Sunting: Menambahkan nomor versi, karena ?Ihanya berfungsi di 1.9, dan menggunakan perubahan @ Howard untuk memangkas beberapa karakter.


Anda dapat menyimpan dua karakter: r while-> 0while, r.sub!(*q)-> r.sub! *q. Anda juga dapat menarik cetakan di dalam lingkaran dan menggunakan 100.times{...}alih-alih pernyataan peta.
Howard

(%w[IIII VIV XXXX LXL]<</(.)((?!\1)[^I])\1/).zip(%w(IV IX XL XC)<<'\2')menghemat 7 karakter.
steenslag

4

Ruby 112 chars

101.times{|n|r=' ';[100,90,50,40,10,9,5,4,1].zip(%w(C XC L XL X IX V IV I)){|(k,v)|a,n=n.divmod k;r<<v*a};$><<r}

Pada dasarnya menggunakan to_romanmetode yang dijelaskan di sini , tetapi menggunakan array zip untuk singkatnya.


4

Mathematica 159 150 142

c = {100, 90, 50, 40, 10, 9, 5, 4, 1};
Table["" <> Flatten[ConstantArray @@@ Thread@{StringSplit@"C XC L XL X IX V IV I", 
  FoldList[Mod, k, Most@c]~Quotient~c}], {k, 100}]

angka Romawi


Built-in solusi : IntegerString, 38 chars

IntegerString[k, "Roman"]~Table~{k, 100}

2

perl 205

@r = split //, "IVXLC";
@n = (1, 5, 10, 50, 100);

for $num (1..100) {
  for($i=@r-1; $i>=0; $i--) {
    $d = int($num / $n[$i]);
    next if not $d;
    $_ .= $r[$i] x $d;
    $num -= $d * $n[$i];
  }
  $_ .= " ";
}
s/LXXXX/XC/g;
s/XXXX/XL/g;
s/VIIII/IX/g;
s/IIII/IV/g;
print;

Golf:

@r=split//,"IVXLC";@n=(1,5,10,50,100);for$num(1..100){for($i=@r-1;$i>=0;$i--){$d=int($num/$n[$i]);next if!$d;$_.=$r[$i]x$d;$num-=$d*$n[$i];}$_.=" ";}s/LXXXX/XC/g;s/XXXX/XL/g;s/VIIII/IX/g;s/IIII/IV/g;print;

2

MUMPS 184

S V(100)="C",V(90)="XC",V(50)="L",V(40)="XL",V(10)="X",V(9)="IX",V(5)="V",V(4)="IV",V(1)="I" F I=1:1:100 S S=I,N="" F  Q:'S  S N=$O(V(N),-1) I S&(S'<N ) S S=S-N W V(N) S N="" w:'S " "

Algoritma yang sama dengan @cardboard_box, dari siapa saya telah mengambil penjelasan kata demi kata -

Penjelasan

Dengan menggunakan nilai-nilai ini, ambil nilai terbesar yang tidak lebih besar dari n dan kurangi dari n. Ulangi sampai n adalah 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1

2

R , 85 byte

R=.romans
for(r in 1:100){while(r>0){cat(names(R[I<-R<=r][1]))
r=r-R[I][1]}
cat(" ")}

Cobalah online!

Menggunakan utilsvariabel paket acak .romansuntuk mendapatkan nilai - nilai angka romawi, tetapi melakukan konversi dengan sendirinya; pendekatan bawaan adalah 20 byte:cat(as.roman(1:100))


Anehnya, pendekatan built-in yang Anda sebutkan tidak bekerja seperti ... seseorang harus mengetik cat(paste(as.roman(1:100)))atau hanya as.roman(1:100). Aneh.
JayCe

@JayCe aneh; Saya pasti tidak benar-benar mengujinya ... dokumen untuk catmenunjukkan bahwa ia melakukan lebih sedikit konversi daripada printdan hanya berfungsi pada atomicvektor - jadi itu menjelaskan hal ini!
Giuseppe

1

APL 128

Saya mencoba solusi pengindeksan di APL:

r←⍬                                                                             
i←1                                                      
l:r←r,' ',('   CXI LV CX'[,⍉((1+(4 4 2 2⊤0 16 20 22 24 32 36 38 39 28)[;1+(3⍴10)⊤i])×3)-4 3⍴2 1 0])~' '
→(100≥i←i+1)/l                                                                  
r              

Ini bisa menjadi 4 byte lebih pendek dalam asal indeks 0 bukannya 1 tetapi ruang nyata babi adalah generasi dari matriks indeks melalui:

4 4 2 2⊤0 16 20 22 24 32 36 38 39 28

Sejauh ini saya belum bisa menghasilkan indeks dengan cepat!


1

LaTeX (138)

\documentclass{minimal}
\usepackage{forloop}
\begin{document}
\newcounter{i}
\forloop{i}{1}{\value{i} < 101}{\roman{i}\par}
\end{document}

1
-1: pertanyaannya mengatakan "Anda tidak dapat menggunakan fungsi
bawaan

1

Python, 125

' '.join(i+j for i in['']+'X XX XXX XL L LX LXX LXXX XC C'.split()for j in['']+'I II III IV V VI VII VIII IX'.split())[1:-38]


1

VBA (Excel), 245 byte

Fungsi dibuat untuk Pengulangan dan Ganti - 91 byte

Function s(a,b):s=String(a,b):End Function Function b(x,y,z):b=Replace(x,y,z):End Function

menggunakan jendela langsung ( 154 byte )

p="I":for x=1to 100:?b(b(b(b(b(b(b(b(s(x,p),s(100,p),"C"),s(90,p),"XC"),s(50,p),"L"),s(40,p),"XL"),s(10,p),"X"),s(9,p),"IX"),s(5,p),"V"),s(4,p),"IV"):next


0

Java (OpenJDK 8) , 152 byte

a->{String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");for(int i=1;i<100;i++){a+=t[i/10]+t[i%10+10]+" ";}return a+"C";}

Cobalah online!

Penjelasan:

String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");
//Create an array of numerals, first half represents tens place, second half represents ones place
    for(int i=1;i<100;i++){             
//Loop 99 times
        a+=t[i/10]+t[i%10+10]+" ";   
//Add tens place and ones place to the string
    }return a+"C";                         
//Add numeral for 100 and return the string

0

TeX, 354 byte

\let~\let~\d\def~\a\advance~\b\divide~\x\expandafter~\f\ifnum{~~\newcount~\n~\i~\j~\k~\u~\v}~~\or\d\p#1{\ifcase#1C~2~L~5~X~2~V~5~I\fi}\d\q#1{\p{#1~}}\d\r{\j0
\v100\d\m{\d\w{\f\n<\v\else\p\j\a\n-\v\x\w\fi}\w\f\n>0\k\j\u\v\d\g{\a\k2\b\u\q\k}\g\f\q\k=2\g\fi\a\n\u\f\n<\v\a\n-\u\a\j2\b\v\q\j\else\p\k\fi\x\m\fi}\m}\i1\d\c{
\f\i<101 \n\i\r\a\i1 \x\c\fi}\c\bye

Beberapa penjelasan: TeX menyediakan perintah \romannumeralbawaan untuk mengonversi angka menjadi angka Romawi. Karena pertanyaan tidak memungkinkan untuk menggunakan fungsi-fungsi bawaan, kode di atas adalah versi golf dari algoritma yang sama yang digunakan oleh compiler TeX asli Knuth untuk \romannumeral(lihat TeX: Program , § 69, print_roman_int) diimplementasikan kembali di TeX.

Karena ia ingin meninggalkan kegembiraan karena bingung bagaimana kode ini bekerja untuk pembaca, Knuth menolak untuk memberikan penjelasan tentang bagian kode ini. Jadi saya akan mengikuti dan memberikan versi yang tidak diubah dan sedikit dimodifikasi, yang lebih dekat ke aslinya daripada kode di atas:

\newcount\n
\newcount\j
\newcount\k
\newcount\u
\newcount\v

\def\chrnum#1{\ifcase#1m\or 2\or d\or 5\or c\or 2\or l\or 5\or x\or 2\or v\or 5\or i\fi}
\def\chrnumM#1{\chrnum{#1\or}}

\def\roman#1{%
    \n=#1\relax
    \j=0\relax
    \v=1000\relax
    \def\mainloop{%
        \def\while{%
            \ifnum\n<\v
            \else
                \chrnum\j
                \advance\n -\v
                \expandafter\while
            \fi
        }\while
        \ifnum\n>0\relax
            \k=\j \advance\k 2\relax
            \u=\v \divide\u \chrnumM\k
            \ifnum\chrnumM\k=2\relax
                \advance\k 2\relax
                \divide\u \chrnumM\k
            \fi
            \advance\n \u
            \ifnum\n<\v
                \advance\n -\u
                \advance\j 2\relax
                \divide\v \chrnumM\j
            \else
                \chrnum\k
            \fi
            \expandafter\mainloop
        \fi
    }\mainloop
}

\newcount\i \i=1
\def\countloop{%
    \ifnum\i<100\relax
        \roman\i\ 
        \advance\i 1
        \expandafter\countloop
    \fi
}\countloop
\bye
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.