| Bytes | Lang | Time | Link |
|---|---|---|---|
| 030 | vemf | 240610T211201Z | taswelll |
| 062 | R | 240608T070703Z | int 21h |
| 079 | JavaScript ES6 | 160412T100041Z | Neil |
| 095 | Python 3 | 160320T003352Z | lynn |
| 070 | Pyth | 160317T211734Z | Denker |
| 129 | C | 160318T170446Z | STDQ |
| 152 | Java | 160318T174710Z | CAD97 |
| 128 | Retina | 160317T214348Z | daavko |
| 072 | Mathematica | 160317T210837Z | LegionMa |
vemf, 30 bytes
éΦ╒¡(4↕;æ1╘*1214╛+╞405‼╕,335)+
Function that takes an integer.
The goal of the big parenthesis is to generate the table digit->segment. For every position, there are three symbols that we need to account for. We are going to try to generate the digits 0-8, and leave 9 until the end.
Notice the amount of "I"s:
_ I II III IV V VI VII VIII
=> 0 1 2 3 1 0 1 2 3
which is 0 1 2 3, or 4↕, joined to itself ; with a one 1. This pattern follows with M, C, V, I with 4 1 2 1 segments respectively. We only need the first 4 elements for M, but we will keep them there.
)9 4↕;æ1╘*1214
((0 1 2 3 1 0 1 2 3)
(0 2 4 6 2 0 2 4 6)
(0 1 2 3 1 0 1 2 3)
(0 4 8 12 4 0 4 8 12))
Accounting for V, L, D is easy because all of them have 2 segments:
_ I II III IV V VI VII VIII
=> 0 0 0 0 2 2 2 2 2
Easy! Just add 405‼. Or 45‼¼ or even doing it like ╒+├≥4¼ works. (That Each Trim should probably not be necessary, but whatever.)
For the 9s places I had a very nice solution at first where the next digit would add to the earlier list with some fill magic but it turns out that just adding the segment counts for IX, XC and CM manually is much easier. The null at the end is outside of the domain of the problem.
)9 4↕;æ1╘*1214╛+╞405‼╕,335
((0 1 2 3 3 2 3 4 5 3)
(0 2 4 6 4 2 4 6 8 3)
(0 1 2 3 3 2 3 4 5 5)
(0 4 8 12 6 2 6 10 14 ■))
The reason we found this table in reverse order is because éΦ conveniently returns the elements in little-endian order, so the digits are in the right place no matter how many digits the number has. this means that we can just each index to get the results (╕¡ happens to work as well because of fill, but ╒¡ does less work. also I kind of like that I managed to fit all the ╒╕╘╛ glyphs once). The + at the end sums the digits.
R, 62 bytes
\(x)sum(utf8ToInt(chartr("MXVDLIC","4222211",as.roman(x)))-48)
This is code-golf, and here is the shortest answer (as for today).
A function which inputs a number and outputs the total number of segments.
This solution is based on the builtin function as.roman, the roman digits are replaced with the respective number of the lines and the total sum of lines is output.
The number with the most lines (30) is MMMDCCCLXXXVIII or 3888.
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.
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
Pyth, 92 76 70 bytes
KsMc."/9hæ²z³Þ§ªW×Oû[Tnè,O¤"\/WQ=Q-Q=Nef!>TQ%2K aY@KhxKN;sY
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
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;
}
Java, 152 bytes
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>.
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?).
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.