แปลงเป็นเลขโรมัน!


13

งานของคุณคือการแปลงจำนวนเต็มบวกที่กำหนดจากเลขอารบิกเป็นตัวเลขโรมัน

ทุกอย่างยากขึ้นเมื่อคุณนับถึง 4,000

1 000ชาวโรมันทำอย่างนี้โดยการเพิ่มบรรทัดข้างต้นสัญลักษณ์การคูณสัญลักษณ์โดยที่ อย่างไรก็ตามการซ้อนทับไม่สามารถแสดงได้อย่างแน่นอนใน ASCII นอกจากนี้ยังมีการโอเวอร์ไลน์สองครั้งเพื่อทวีคูณสัญลักษณ์โดย1 000 000และจากนั้นสามโอเวอร์ไลน์เพื่อคูณสัญลักษณ์โดย1 000 000 000ฯลฯ ...

ดังนั้นฉันจึงตัดสินใจใช้วงเล็บเพื่อแทนที่การวางซ้อน

สัญลักษณ์สามารถวางแยกกันในวงเล็บ ยกตัวอย่างเช่นทั้งสอง(VI)และเป็นตัวแทนที่ถูกต้อง(V)(I) ยังเป็นตัวแทนที่ถูกต้องของ 60006 000(V)M

(I)1 000เป็นวิธีที่ถูกต้องที่จะเป็นตัวแทน

Testcases

Input: 1
Output: I
Input: 2
Output: II
Input: 3
Output: III
Input: 4
Output: IV
Input: 15
Output: XV
Input: 40
Output: XL
Input: 60
Output: LX
Input: 67
Output: LXVII
Input: 400
Output: CD
Input: 666
Output: DCLXVI
Input: 3000
Output: MMM
Input: 3999
Output: MMMCMXCIX
Input: 4000
Output: M(V)
Input: 4999
Output: M(V)CMXCIX
Input: 6000
Output: (VI)
Input: 6000000
Output: ((VI))
Input: 6006000
Output: ((VI)VI)
Input: 6666666666
Output: (((VI)DCLXVI)DCLXVI)DCLXVI

เกณฑ์การให้คะแนน

นี่คือรหัสกอล์ฟรหัสที่สั้นที่สุดในหน่วยไบต์ชนะ


1
การให้เหตุผลว่าทำไมนี่จึงไม่ใช่สเปคที่ซ้ำกัน มันจะดีกว่าถ้าไม่มี IMO
Mego

ฉันจะเพิ่มความชอบธรรมได้ที่ไหน
Leun Nun

1
ทิ้งมันไว้ หากมีคนถามว่าเป็นการซ้ำหรือไม่ให้มีการอภิปรายในความคิดเห็นหรือในการแชท
Mego

@Mego เรียบร้อยแล้ว :-)
แม่ชี Leaky

คือ(IV)การแสดงที่ได้รับการยอมรับของ 4000?
Neil

คำตอบ:


9

Mathematica, 67 ไบต์

Fold["("<>#<>")"<>#2&,RomanNumeral[#~IntegerDigits~1000]/."N"->""]&

หลีกเลี่ยงปัญหาทั้งหมดที่มีMโดยการแปลงการป้อนข้อมูลไปยังฐาน 1000 RomanNumeralและการแปลงแต่ละหลักแยกต่างหากกับ จากนั้นเราก็พับขึ้นโดยใส่(...)จากด้านซ้าย

น่าเสียดายที่ Mathematica แทนค่าศูนย์Nดังนั้นเราต้องกำจัดมันทิ้ง


1
darn mathematica พร้อม builtins สำหรับทุกสิ่ง> :(
OldBunny2800

1
@ OldBunny2800 ฉันจะแปลกใจถ้ามันไม่ถูกตีด้วยภาษากอล์ฟใด ๆ
Martin Ender

@ OldBunny2800 และมีค่าใช้จ่ายเงินจริงที่จะได้รับ เลวร้าย.
Erik the Outgolfer

@ MartinBüttnerฉันคิดว่าRomanNumeralสามารถทำได้หรือไม่
Leun Nun

1
@ KennyLau เอาท์พุทMMMMสำหรับ4000มันจะเริ่มทำงานเพื่อสเป็คที่5000(แล้วคุณจะได้รับปัญหาเดียวกันสำหรับ4000000ฯลฯ ) ถึงอย่างนั้นมันก็ใช้โอเวอร์บาร์แทนวงเล็บ หากคุณไม่เป็นไรคุณควรพูดอย่างนั้นในสเปคการท้าทาย
Martin Ender

7

JavaScript (ES6), 136 ไบต์

f=n=>n<4e3?"M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".replace(/(\D+)(\d+)/g,(_,r,d)=>r.repeat(n/d,n%=d)):`(${f(n/1e3)})`+f(n%1e3)

สำหรับตัวเลขที่ต่ำกว่า 4000 ให้ทำซ้ำ "ตัวอักษร" โรมันซ้ำหลาย ๆ ครั้งให้มากที่สุดโดยใช้รายการ "ตัวอักษร" โรมันและค่าทศนิยม มิฉะนั้นจะสร้างคำตอบซ้ำจากการหารและโมดูโลที่มี 1,000 ซ้ำการrepeatตัดทอนโชคดีดังนั้นฉันจึงไม่ต้องทำเอง


3

เสียงกระเพื่อมสามัญ 108

(defun p(n)(if(> n 0)(if(< n 4000)(format()"~@R"n)(format()"(~A)~@[~A~]"(p(floor n 1000))(p(mod n 1000))))))

Ungolfed

(defun p(n)
  (if (> n 0)
      (if (< n 4000)

          ;; Built-in Roman formatter (between 1 and 3999)
          (format () "~@R" n)

          ;; Divide N by 1000, as 1000*Q + R.
          ;; First print (p Q) in parentheses (recursively)
          ;; Then, if it is not NIL, the remainder R.
          (format () "(~A)~@[~A~]"
                  (p (floor n 1000))
                  (p (mod n 1000))))))

การทดสอบ

การทดสอบสองครั้งให้ผลลัพธ์ที่แตกต่างจากคำถาม:

(loop for (in out) in '((1 "I")
                        (2 "II")
                        (3 "III")
                        (4 "IV")
                        (15 "XV")
                        (40 "XL")
                        (60 "LX")
                        (67 "LXVII")
                        (400 "CD")
                        (666 "DCLXVI")
                        (3000 "MMM")
                        (3999 "MMMCMXCIX")
                        (4000 "M(V)")
                        (4999 "M(V)CMXCIX")
                        (6000 "(VI)")
                        (6000000 "((VI))")
                        (6006000 "((VI)VI)")
                        (6666666666 "(((VI)DCLXVI)DCLXVI)DCLXVI"))
   for computed = (p in)
   unless (string= out computed)
   collect (list in out computed))

=> ((4000 "M(V)" "(IV)")
    (4999 "M(V)CMXCIX" "(IV)CMXCIX"))

2

R, 134

m=1000;x=scan();while(x[1]>=m)x=c(floor(x[1]/m),x[1]%%m,x[-1]);cat(rep("(",length(x)),sep="");cat(as.character(as.roman(x)),sep=")")

มันค่อนข้างจะไม่ใช่ตัวเลือกที่ดีที่สุด แต่ฉันคิดว่าแนวคิดควรจะคล้ายกันกับสิ่งนี้


1

Python, 188 194

-6 ไบต์จากการกำจัด whitespace

ความท้าทายนี้ทำให้ฉันย้อนกลับไปเมื่อฉันเรียนรู้โปรแกรมครั้งแรก ...

def f(x,s=zip("M CM D CD C XC L XL X IX V IV I".split(),[1e3,900,500,400,100,90,50,40,10,9,5,4,1])):
 r=""if x<4e3else"("+f(x/1e3)+")";x%=1e3
 for a,b in s:
    while x>=b:r+=a;x-=b
 return r

มันอาจไม่ใช่ทางออกที่สั้นที่สุด แต่ฉันสนุกกับการเล่นกอล์ฟปัญหานี้

ลอง!


1

ทับทิม, 137 134 130 ไบต์

ฟังก์ชั่นวนซ้ำที่ส่งคืนสตริง ฉันกำลังพยายามตีกอล์ฟลงรหัสอีกเล็กน้อยถ้าเป็นไปได้ แต่ฉันไม่แน่ใจ

อ๊ะมันเป็นพอร์ตโดยตรงของคำตอบ ES6 ของ @ Neil ในขณะนี้

f=->x{(x<t=1e3)?"CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".gsub(/(\D+)(\d+)/){v=$2.to_i;s=x/v;x%=v;$1*s}:"(#{f[x/t]})#{f[x%t]}"}

1

Ruby, 185 161 144 ไบต์

r=->i{i>(t=1e3)? "(#{r[i/t]})"+r[i%t]:(s=?I*i;"IVXXLCCDM".scan(/(.)(.)(.)/){|x,y,z|{x*5=>y,x*4=>x+y,y*2=>z,y+x+y=>x+z}.map{|x,y|s.gsub!x,y}};s)}

กว่าหนึ่งปีหลังจากโพสต์ต้นฉบับฉันคิดว่าฉันเรียนรู้บางอย่างเกี่ยวกับการเล่นกอล์ฟ

ขอบคุณ Value Ink สำหรับความคิดเห็นที่มีค่าของคุณ


gsubสามารถใช้สตริงเป็นอาร์กิวเมนต์แรกโดยไม่จำเป็นต้องใช้การแทนที่ในรูปแบบ regex เนื่องจากs.gsub! x,yทำโดยอัตโนมัติ นอกเหนือจากนั้นคุณสามารถละทิ้งการมอบหมายaอาร์เรย์ของคุณเนื่องจากคุณใช้เพียงครั้งเดียวและวางลงในeach_sliceสายโดยตรง
หมึกมูลค่า

"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...ใช้งานได้ดี
Value Ink

นอกจากนี้ยังr[x]สามารถใช้งานได้เทียบเท่ากับr.(x)ทุกครั้งที่แกะ lambdas เกี่ยวข้อง
Value Ink

@ValueInk ขอบคุณ ว่าr[x]เคล็ดลับที่จะเป็นประโยชน์สำหรับทุก futer ของฉันกอล์ฟ recursive ในทับทิม!
MegaTom

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.