Romen Rakamlarında 1'den 100'e kadar sayın


29

Romen Rakamlarında 1 ile 100 arasında sayılan bir program yazın ve bu sayıları standart çıktılara göre yazdırın. Sayıların her biri boşluklarla ayrılmalıdır.

Romen rakamlarına veya harici uygulamalara ya da kütüphanelere dönüştürmek için herhangi bir yerleşik işlevi kullanamazsınız.

İstenilen sonuç

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

Bir kod golf mücadelesi olduğu için en kısa kod kazanır .


4
39, bir X'i kaçırıyor
Thor

@Thor Fixed, teşekkürler;)
Averroes

1
Bunun için INTERCAL'i gerçekten kullanmak istiyorum.
Weijun Zhou

newlines ile ayrılabilir mi? Ayrıca izleyen / çıkan alanlar / yeni hatlar ne olacak?
FantaC

Yanıtlar:


68

Perl 69 bayt

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

Büyü formülü ile çalışır. İfade "32e$&"%72726, her basamağı şu şekilde dönüştürür:
0⇒32, 1⇒320, 2⇒3200, 3⇒32000, 4⇒29096, 5⇒56, 6⇒560, 7⇒5600, 8⇒56000, 9⇒50918

Çeviriyi uyguladıktan sonra y/016/IXV/, bunun yerine şu var:
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

Rakamların geri kalanı ( 2-57-9) kaldırıldı. Bu ifade edilen bir formül kullanılarak tek bir bayt geliştirilebileceğini Not 012yerine 016basitleştirilmesi, /XVI60-9/için /XVI0-9/. Bir tane bulamadım ama belki daha iyi şansın olur.

Bir hane bu şekilde dönüştürüldüğünde, işlem bir sonraki hane için tekrarlanır, sonucu ekler ve önceki XVIs'yi CLXaynı anda çevirir, yeni hane için çeviri gerçekleşir.

Güncelle
Kapsamlı arama daha kısa bir şey ortaya çıkarmadı. Bununla birlikte, alternatif bir 69 baytlık çözüm buldum:

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

Bu , 0-2yerine geçer IXV, ancak bir rakam daha uzun olan bir modulo vardır.


Güncelleme: 66 65 bayt

Bu sürüm oldukça farklı, bu yüzden muhtemelen bu konuda birkaç kelime söylemeliyim. Kullandığı formül aslında bir bayt daha uzun!

Formülü olduğundan daha fazla kısaltamazsam, sahip olduğum golfü seçmeye karar verdim. Eski dostumu hatırlayana kadar uzun sürmedi $\. Bir printrapor verildiğinde $\çıktının sonuna otomatik olarak eklenir. $a[$_]İki byte'lık iyileştirme için garip yapıdan kurtulabildim :

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

Çok daha iyi, ama bu $\=!print$"hala biraz ayrıntılı görünüyordu. Daha sonra 3, rakam dönüşümlerinin hiçbirinde sayı içermeyen alternatif, eşit uzunlukta bir formül olduğunu hatırladım . Bu nedenle, bunun $\=2+printyerine kullanmak mümkün olmalı ve sonuçta 3bir boşluk bırakılmalıdır :

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

Ayrıca 67 byte, printve arasında gerekli boşluk nedeniyle for.

Düzenleme : Bu, öne doğru hareket ettirilerek bir bayt ile iyileştirilebilir print:

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

İkame tam olarak önce değerlendirmek zorunda olduğu için print, atama en $\son gerçekleşecek. Aradaki boşluğun kaldırılması geve forkullanımdan kaldırılması uyarısı verir, ancak aksi takdirde geçerlidir.

Bir kullanmıyordu bir formül olsaydı Ama 1hiçbir yerinde, $\=2+printolur $\=printtasarrufların başka iki bayt değerinde. Bir bayt daha uzun olsa bile, yine de bir gelişme olur.

Görünüşe göre, böyle bir formül var, ancak orijinalinden bir bayt daha uzun ve sonuçta 65 baytlık bir sonuçla sonuçlanıyor :

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

metodoloji

Nasıl böyle bir formül bulma konusunda nasıl gidebileceği sorusu soruldu. Genel olarak, herhangi bir veri setini genelleştirmek için sihirli bir formül bulmak olasılık meselesidir. Yani, istenen sonuca benzer bir şey üretmek için mümkün olan bir formu seçmek istiyorsunuz.

İlk birkaç romen rakamını incelemek:

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

Görülmesi gereken bazı düzenlilik var. Spesifik olarak, 0-3 arasında ve daha sonra yine 5-8 arasında , her ardışık terimin uzunluğu bir rakamla artar. Biz rakamlarıyla karakter arası bir eşleme yaratmak istedik, biz bir ifade var isteyeyim da birbirini izleyen her dönem için bir hane uzunluğunda arttırır. Mantıksal bir seçim k • 10 d'dir ; d , d , karşılık gelen hanedir ve k , herhangi bir tamsayı sabitidir.

Bu 0-3 için çalışır , ancak 4 desen kırmak gerekiyor. Burada yapabileceğimiz şey, bir modulo üzerine yapışmaktır:
k • 10 d % m , burada m k • 10 3 ve k • 10 4 arasında bir yerdedir . Bu, 0-3 aralığını el değmeden bırakacak ve 4 değerini dört Is içermeyecek şekilde değiştirecektir . Size bunun dışında modüler kalıntı bizim arama algoritması sınırlamak durumunda 5 , hadi diyoruz j az olduğu m / 1000 , bu da gelen düzenlilik yaşamanızı sağlayacaktır 5-8 sıra. Sonuç şöyle bir şeydir:

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

Gördüğünüz gibi, biz değiştirirseniz 0ile I, 0-3 ve 5-8 tüm doğru biçimde eşlenmesi garanti edilir! 4 ve 9 değerlerinin kaba olsa da zorlanması gerekir. Spesifik olarak, 4'ün bir 0ve bir j(bu sırada) içermesi gerekir ve 9'un bir içermesi gerekir 0, ardından başka bir yerde görünmeyen başka bir rakam gelir. Kuşkusuz, bir tesadüf eseri bir şans eseri arzu edilen sonucu üretebilecek bazı başka formüller vardır. Bazıları daha kısa bile olabilir. Fakat bunun kadar başarılı olabileceğini düşünmüyorum.

Ayrıca Ive / veya bir Vmiktar başarı ile yapılan birden fazla değişiklikle denedim. Ama ne yazık ki, sahip olduklarımdan daha kısa hiçbir şey. İşte bulduğum en kısa çözümlerin bir listesi (1-2 bayt daha ağır olan çözümlerin sayısı listelenemeyecek kadar çok):

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
Sihirli formülü nasıl buldunuz?
Ruben Verborgh

1
@RubenVerborgh Yakında metodoloji ile ilgili daha fazla bilgiyi yayınlamam
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​}

Çıktı

Romen rakamları ile numaralandırılmış liste

...

JSBin'de Demo


1
81 bayt JS okunur sürümü: document.write('<ol>'+"<li style='list-style:upper-roman'/>".repeat(100)+'</ol>')(ES6)
Paperjam

veya 66'da 66document.write("<li style='list-style:upper-roman'/>".repeat(100))
Slai

10

Python 116

scleaver'ın cevabının daha iyi golf kuralları:

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

Daha kısa çözümler var, ama C'de yok, işte benim denemem.

Yeni çözüm, öncekinden tamamen farklı:

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");
}

Önceki çözüm (160 karakter):

Mantık:
1. f, 1 ile 10 arasında bir sayı yazdırır. cKullanılan rakam, IVXveya olabilir XLC. Onlar için bir kez onlar için bir kez denir.
2. Eğer n%5==0- hiçbir şey yazdırmayın veya c[n/5]hangisi Iveya V(veya Lveya C).
3. n%4==4- 4veya 9- yazdırır I(veya X), ile n+1.
4. Eğer n>4- sonra 5(yani Vveya L) yazdırın n-5.
5. Eğer n<4- Isonra yazdırın n-1(örneğin, nzamanlar 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

Daha uzun bir versiyondan esinlendiğim bir Polonyalı haber grubunda (en azından Chrome'un Polonyalı olduğunu düşündüğü) karşılaştım.

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

S ( 81 80)

2. kesim:

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

1. kesim:

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]),

açıklama

Bu değerleri kullanarak, n'den büyük olmayan en büyük değeri alın ve n'den çıkarın. N 0 olana kadar tekrarlayın.

'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""iki karakter kaydeder. Aksi takdirde çok güzel.
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}

Bu kelimenin tam anlamıyla Romen rakamlarında 1 ile 100 arasındadır. Boş bir dizeyle başlar, daha sonra "I" eklenir ve ardından bir dizi ikame kuralı uygulayarak etkin bir şekilde 1 eklenir.

Düzenleme: Sürüm numarası eklendi, çünkü ?Isadece 1.9'da çalışıyor ve @ Howard'ın bazı karakterleri kırpmak için kullandığı değişiklikleri kullandı.


İki karakter kaydedebilirsiniz: r while-> 0while, r.sub!(*q)-> r.sub! *q. Yazdırmayı döngünün içine sürükleyebilir 100.times{...}ve map ifadesi yerine kullanabilirsiniz .
Howard,

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

4

Yakut 112 karakter

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}

Temel olarak burada açıklananto_roman yöntemi kullanmak , ancak kısaltmak için sıkıştırılmış bir dizi kullanmak.


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}]

Roma rakamları


Dahili çözüm :, IntegerString38 karakter

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;

golfed:

@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 " "

Açıklama gibi ben açıklama aldım kim @ cardboard_box ile aynı algoritma -

açıklama

Bu değerleri kullanarak, n'den büyük olmayan en büyük değeri alın ve n'den çıkarın. N 0 olana kadar tekrarlayın.

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

2

R , 85 bayt

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

Çevrimiçi deneyin!

Romen rakamlarının değerlerini elde etmek için rastgele utilspaket değişkenini kullanır , ancak dönüştürmeyi kendisi yapar; yerleşik yaklaşım 20 bayt olacaktır:.romanscat(as.roman(1:100))


Şaşırtıcı bir şekilde, bahsettiğiniz yerleşik yaklaşım, birinin yazması cat(paste(as.roman(1:100)))ya da basit olması gerektiği gibi çalışmaz as.roman(1:100). Tuhaf.
JayCe,

@JayCe garip; Aslında test etmemeliydim ... dokümanlar , vektörlerden catdaha az dönüşüm gerçekleştirdiğini printve yalnızca atomicvektörler üzerinde çalıştığını gösteriyor - bu da bunu açıklıyor!
Giuseppe

1

APL 128

APL'de bir indeksleme çözümü denedim:

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              

İndeks kökenli 0'da 1 yerine 4 bayt daha kısa olabilir, ancak asıl alan domu, endeks matrisinin şu şekilde üretilmesidir:

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

Şimdiye kadar anında endeksleri üretemedim!


1

LaTeX (138)

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

1
-1: soru "Romen rakamlarına dönüştürmek için herhangi bir yerleşik işlevi kullanamazsınız" diyor
izabera

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 bayt

Tekrarlama ve Değiştirme Fonksiyonu yaratıldı - 91 bayt

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

acil pencereyi kullanarak ( 154 bayt )

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 bayt

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";}

Çevrimiçi deneyin!

Açıklama:

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 bayt

\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

Bazı açıklamalar: TeX, \romannumeralsayıları Romen rakamlarına dönüştürmek için yerleşik bir komut sunar . Sorusu kullanmak için izin vermez gibi yerleşik işlevleri, yukarıdaki kod aynı algoritmanın bir golfed versiyonu için Knuth'un orijinal TeX derleyici kullandığı \romannumeral(bkz TEX'i: Program , § 69, print_roman_int) TeX yeniden uyguladı.

Bu kodun okuyucunun işleyiş şeklini şaşırtmanın mutluluğunu bırakmak istediğinden, Knuth kodun bu kısmının bir açıklamasını yapmayı reddetmektedir. Bu yüzden ben de takım elbisesini izleyeceğim ve sadece aslıya yukarıdaki koddan daha yakın olan bir çirkin ve hafifçe değiştirilmiş versiyonu vereceğim:

\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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.