10
\$\begingroup\$

Write a program or function that accepts an integer in the range 1..3999 as input and returns the number of line segments required to express that integer in standard Roman numerals (so you would use XL but not VM). Examples:

   1 -> 1
   4 -> 3
   5 -> 2
   9 -> 3
  10 -> 2
  40 -> 4
  50 -> 2
  90 -> 3
 100 -> 1
 400 -> 3
 500 -> 2
 900 -> 5
1000 -> 4

Roman number conversion builtins are permitted, but you can solve the problem without them by repeatedly subtracting the largest remaining number from the above list. Example: 1234 = 4 + 1 + 1 + 2 + 2 + 2 + 3 = 15.

This is , so the shortest program wins.

\$\endgroup\$
  • \$\begingroup\$ Why is 10 two line segments instead of four? When writing X, you'd typically only write two lines, but doesn't the intersection of the lines make it four segments? \$\endgroup\$ – Alex A. Mar 17 '16 at 20:02
  • \$\begingroup\$ @AlexA. The definition of line segment is usually something like: "The set of points following the shortest path between two points". There doesn't seem to be any reason to cut X based on this, you only need two sets of end points to define it. (Assuming Romans primarily wrote on euclidean geometries, I guess) \$\endgroup\$ – FryAmTheEggman Mar 17 '16 at 21:03
  • \$\begingroup\$ @FryAmTheEggman Hm okay. Good to know, thanks. \$\endgroup\$ – Alex A. Mar 17 '16 at 21:05
2
\$\begingroup\$

Pyth, 92 76 70 bytes

KsMc."/9hæ²z³Þ§ªW×Oû[Tnè,O¤"\/WQ=Q-Q=Nef!>TQ%2K aY@KhxKN;sY

Try it here!

Thanks to @FryAmTheEggman for some string packing suggestions which saved me some bytes!

I am still wondering if there is a mathematical way of encoding this list. Will try to figure something out.

Explanation

This uses the given algorithm. K contains the given list with the numbers and the corrosponding number of line segments in alternation. This list gets constructed by splitting a packed string, which gets decoded to 0/0/1/1/4/3/5/2/9/3/10/2/40/4/50/2/90/3/100/1/400/3/500/2/900/5/1000/4, on / and mapping each element to an integer.

KsMc."..."\/WQ=Q-Q=Nef!>TQ%2K aY@KhxKN;sY    # Q = input

   c."..."\/                                 # split the string on /
KsM                                          # map every number to int and assign to K
            WQ                               # while Q != 0
                     f    %2K                # only take every 2nd element of K and filter with T
                      !>TQ                   # T <= Q
                  =Ne                        # Take the last element of that and assign that to N
              =Q-Q                           # Q = Q - N
                                   xKN       # index of the first occurence of N in K
                                  h          # increment that index because we want the line segments
                              aA@K           # get the line segment from that index and append that to Y
                                      ;sY    # end the loop and print the sum of all line segments in Y
\$\endgroup\$
3
\$\begingroup\$

C, 148 129 chars

d,x,n[]={1000,900,500,400,100,90,50,40,10,9,5,4,1,4,5,2,3,1,3,2,4,2,3,2,3,1};f(c){while(d+=(c/n[x])*n[x+13],c%=n[x++]);return d;}

My first code-golf :^). Since the question states I can use a function, I have changed main to a function to trim some chars (most importantly: pass c as parameter rather scanf)

unpacked

d,x,n[]={1000,900,500,400,100,90,50,40,10,9,5,4,1,4,5,2,3,1,3,2,4,2,3,2,3,1};
f(c){
  while(d+=(c/n[x])*n[x+13],
        c%=n[x++]);
  return d;
}
\$\endgroup\$
2
\$\begingroup\$

Mathematica, 80 72 bytes

Tr[Characters[#~IntegerString~"Roman"]/.{"I"|"C"->1,"M"->4,_String->2}]&

Anonymous function that just converts numbers to Roman numerals, replaces each character with its number of segments, and takes the total.

\$\endgroup\$
2
\$\begingroup\$

Retina, 128 bytes

.+
$*
1{1000}
t'
1{900}
td
1{500}
d
1{400}
t
1{100}
'
1{90}
t
1{50}
d
1{40}
t'
1{10}
d
1{9}
t
1{5}
d
1{4}
t
1
'
t
d'
d
''
'+
$.0

Simple replacing until there's nothing left to replace. Then the apostrophes are counted and that's our number of line segments.

If input and output in unary are allowed, it's 115 bytes (although who would want to type 1234 ones?).

Try it online!
Try it online! (unary IO)

\$\endgroup\$
2
\$\begingroup\$

Python 3, 95 bytes

def f(a,b=0):
 for e in'᝴ᔝ஺ॣəȟĮô>9 ':e=ord(e);d=e//6;b+=a//d*(e%6);a%=d
 return b

The Unicode string consists of the code points:

6004 5405 3002 2403 601 543 302 244 62 57 32 27 7
\$\endgroup\$
  • \$\begingroup\$ If you turn that string into a byte literal you can omit e=ord(e); \$\endgroup\$ – xsot Mar 20 '16 at 3:31
  • \$\begingroup\$ I don’t think that works in my case. I need a Unicode string :( i.e. I’m looping over the codepoints in that string, not over the bytes. \$\endgroup\$ – Lynn Mar 20 '16 at 3:34
  • 1
    \$\begingroup\$ Oh, I see. Do you mind providing a hex dump of the string? It isn't displayed properly on my phone. \$\endgroup\$ – xsot Mar 20 '16 at 3:40
1
\$\begingroup\$

Java, 152 bytes

Because, ya know, Java.

n->{int c=0;int[]r={999,4,899,5,499,2,399,3,99,1,89,3,49,2,39,4,9,2,8,3,4,2,3,3,0,1};for(int i=0;i<26;i+=2)while(n>r[i]){n-=r[i]+1;c+=r[i+1];}return c;}

Simple literal implementation of the given algorithm. Array packs the transform information: even indexes are one less than the roman numeral and odd indexes are the count for that numeral.

This is a lambda that takes and returns an int/Integer. This includes IntUnaryOperator or UnaryOperator<Integer>.

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 79 bytes

n=>"0123323453"[[,a,b,c,d]=1e4+n+'',d]-(-"0246424683"[c]-"0123323455"[b])+a*4

The strings represent the number of line segments for the units, tens and hundreds digits. (Thousands is simply four times the thousands digit.) This method seems to be shorter than other options such as the algorithm suggested in the question.

Edit: Saved 2 bytes thanks to @user81655.

\$\endgroup\$
  • \$\begingroup\$ This is a cool algorithm. Rearranging the casts can save 2 bytes as well: n=>"0123323453"[[,a,b,c,d]=1e4+n+'',d]-(-"0246424683"[c]-"0123323455"[b])+a*4 \$\endgroup\$ – user81655 Apr 20 '16 at 3:13
  • \$\begingroup\$ @user81655 Oh, that's nice: simply changing the +s to -s allows me to remove the leading +, but then the grouping saves another byte. \$\endgroup\$ – Neil Apr 20 '16 at 7:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.