# Count Like a Babylonian

## Challenge

Given an ASCII representation of a Babylonian number as input, output the number in Western Arabic numerals.

## Babylonian Numeral System

How did the Babylonians count? Interestingly, they used a Base 60 system with an element of a Base 10 system. Let's first consider the unit column of the system:

The Babylonians had only three symbols: T (or, if you can render it: 𒐕) which represented 1, and < (or, if you can render it: 𒌋) which represented 10, and \ (or, if you render it: 𒑊) which represented zero.

Note: Technically, \ (or 𒑊) isn't zero (because the Babylonians did not have a notion of 'zero'). 'Zero' was invented later, so \ was a placeholder symbol added later to prevent ambiguity. However, for the purposes of this challenge, it's enough to consider \ as zero

So, in each column you just add up the value of the symbols, e.g.:

<<< = 30
<<<<TTTTTT = 46
TTTTTTTTT = 9
\ = 0


There will never be more than five < or more than nine T in each column. \ will always appear alone in the column.

Now, we need to extend this to adding more columns. This works exactly the same as any other base sixty, where you multiply the value of the rightmost column by $60^0$, the one to the left by $60^1$, the one to the left by $60^2$ and so on. You then add up the value of each to get the value of the number.

Columns will be separated by spaces to prevent ambiguity.

Some examples:

<< <TT = 20*60 + 12*1 = 1212
<<<TT \ TTTT = 32*60^2 + 0*60 + 4*1 = 115204


## Rules

• You are free to accept either ASCII input (T<\) or Unicode input (𒐕𒌋𒑊)
• The inputted number will always be under $10^7$
• The <s will always be to the left of the Ts in each column
• \ will always appear alone in a column

## Winning

Shortest code in bytes wins.

• @TaylorScott Yes, you may – Beta Decay Aug 13 '18 at 11:17
• In case it helps: Max that needs to be handled is 4 columns: <<<<TTTTTT <TTTTTTT <<<<TTTTTT <<<< – Wernisch Aug 13 '18 at 11:40
• Are columns always separated by exactly one space each? I notice answers relying on it. – KRyan Aug 14 '18 at 2:44
• Foreign types with the hookah pipes say Ay oh whey oh, ay oh whey oh - Count like a Babylonian. Great. Now it's stuck in my head. – cobaltduck Aug 14 '18 at 20:50
• "How did the Babylonians count? Interestingly, they used a Base 60 system with an element of a Base 10 system." Which is still in use today; the Babylonian number system is exactly what we use for clocks. Two decimal digits each for seconds, minutes, and hours, 60 seconds to the minute, 60 minutes to the hour. – Ray Aug 14 '18 at 21:20

# JavaScript (ES6), 44 bytes

Takes input as an array of ASCII characters.

a=>a.map(c=>k+=c<1?k*59:c<'?'?10:c<{},k=0)|k


Try it online!

### How?

The Babylonian Numeral System can be seen as a 4-instruction language working with a single register -- let's call it the accumulator.

Starting with $k=0$, each character $c$ in the input array $a$ modifies the accumulator $k$ as follows:

• space: multiply $k$ by $60$ (implemented as: add $59k$ to $k$)
• <: add $10$ to $k$
• T: increment $k$
• \: do nothing; this is the NOP instruction of this language (implemented as: add $0$ to $k$)

# C (gcc), 140138 136 bytes

B,a,b,y;l(char*o){y=B=0,a=1;for(char*n=o;*n;n++,B++[o]=b,a*=60)for(b=0;*n&&*n-32;n++)b+=*n-84?*n-60?:10:1;for(B=a;B/=60;y+=*o++*B);B=y;}


Try it online!

• +1 Taking "count like a babylonian" to the next level :D – Beta Decay Aug 13 '18 at 13:55

# Perl 6, 39 bytes

-3 bytes thanks to nwellnhof

{:60[.words>>.&{sum .ords X%151 X%27}]}


Try it online!

Uses the cuneiform characters.

### Explanation:

{                                     }   # Anonymous code block
.words  # Split input on spaces
>>.&{                    }  # Convert each value to
sum   # The sum of:
.ords # The codepoints
X%151 X%27   # Converted to 0,1 and 10 through modulo
:60[                                ]  # Convert the list of values to base 60

• You beat me by a couple of minutes. Here's what I came up with: {:60[.words>>.&{sum (.ords X%151)X%27}]} (40 bytes) – nwellnhof Aug 13 '18 at 10:23
• @nwellnhof Very well done! How did you find the mod values? – Jo King Aug 13 '18 at 10:31
• Simply by brute force. – nwellnhof Aug 13 '18 at 10:34

# Jelly,  13  12 bytes

ḲO%7C%13§ḅ60


A monadic link accepting a list of characters which yields an integer.

Try it online!

### How?

ḲO%7C%13§ḅ60 - Link: list of characters   e.g. "<<<TT \ TTTT"
Ḳ            - split at spaces                 ["<<<TT", "\", "TTTT"]
O           - cast to ordinals                [[60,60,60,84,84],,[84,84,84,84]]
%7         - modulo by seven (vectorises)    [[4,4,4,0,0],,[0,0,0,0]]
C        - compliment (1-X)                [[-3,-3,-3,1,1],,[1,1,1,1]]
%13     - modulo by thirteen              [[10,10,10,1,1],,[1,1,1,1]]
§    - sum each                        [32,0,4]
ḅ60 - convert from base sixty         115204


Another 12: ḲO⁽¡€%:5§ḅ60 (⁽¡€ is 1013, so this modulos 1013 by the Ordinal values getting 53, 5, and 1 for <, T, \ respectively then performs integer division, : by 5 to get 10, 1 and 0)

• Lol, I've deleted my answer exactly because of this, since I remembered I could use base conversion but was literally too lazy to find out how. +1 – Mr. Xcoder Aug 13 '18 at 11:49

# 05AB1E, 13 bytes

8740|Ç%4/O60β


Try it online!

To make up for how lazy I've been with my Jelly answer, here is a submission in 05AB1E xD.

• Help 05AB1E-ers out there, wasn't there a way to compress numbers like 8740? – Mr. Xcoder Aug 13 '18 at 12:28
• codegolf.stackexchange.com/a/166851/52210 Unfortunately it wouldn't be shorter: •Yη• (4 bytes) – Kevin Cruijssen Aug 13 '18 at 12:29
• @KevinCruijssen Thank you! That answer is very useful, I'll totally use it in the future – Mr. Xcoder Aug 13 '18 at 12:30
• Glad the tip is of use. :) I figured these things out after seeing some answers using them. The dictionary part was explained here. And the compression of other strings or large integers I figured out myself after seeing the linked example answers for "goose" and 246060. – Kevin Cruijssen Aug 13 '18 at 12:35
• 1|Ç7%-13%O60β is also 13 - is it golfable? – Jonathan Allan Aug 13 '18 at 19:25

# Python 2, 969387 85 bytes

lambda s:sum(60**i*sum(8740%ord(c)/4for c in v)for i,v in enumerate(s.split()[::-1]))


Try it online!

Saved:

• -1 byte, thanks to Mr. Xcoder
• -4 bytes, thanks to Poon Levi
• -2 bytes, thanks to Matthew Jensen
• 95: (ord(c)%5/2or 11)-1 – Mr. Xcoder Aug 13 '18 at 10:03
• @Mr.Xcoder Thanks :) – TFeld Aug 13 '18 at 10:32
• 87: 8740%ord(c)/4 – Poon Levi Aug 13 '18 at 11:23
• -2 by removing the parentheses around the second sum()Try it online! – Matthew Jensen Sep 26 '19 at 21:49
• @MatthewJensen Thanks :) – TFeld Sep 27 '19 at 8:38

# Excel VBA, 121 bytes

Restricted to 32-Bit Office as ^ serves as the LongLong type literal in 64-Bit versions

Takes input from cell A1 and outputs to the vbe immediate window.

a=Split([A1]):u=UBound(a):For i=0 To u:v=a(i):j=InStrRev(v,"<"):s=s+(j*10-(InStr(1,v,"T")>0)*(Len(v)-j))*60^(u-i):Next:?s


### Ungolfed and Commented

a=Split([A1])       '' Split input into array
u=UBound(a)         '' Get length of array
For i=0 To u        '' Iter from 0 to length
v=a(i)              '' Get i'th column of input
j=InStrRev(v,"<")   '' Get count of <'s in input
'' Multiply count of <'s by 10; check for any T's, if present
t=t+(j*10-(InStr(1,v,"T")>0)*(Len(v)-j))
*60^(u-i)       '' Multiply by base
Next                '' Loop
?s                  '' Output to the VBE immediate window


# Dyalog APL, 33 30 bytes

{+/(⌊10*⍵-3)×60*+\2=⍵}'\ T<'⍳⌽


Try it online!

Edit: -3 bytes thanks to ngn

'\ T<'⍳ replaces the characters with numbers (their position in the string constant), and ⌽ reverses the input so most significant 'digits' are last. This allows +\2= to keep a running count of the desired power of 60 (applied by 60*) by counting the number of times a space (index 2 in the string constant) is encountered.

⌊10*⍵-3 gives the desired power of ten for each character. The order of characters in the string constant and the -3 offset cause '\' and space to go to negative numbers, resulting in fractions when those characters are raised to the power of 10, allowing them to be eliminated by ⌊.

All we have to do now is multiply the powers-of-10 digits by the powers-of-60 place values and sum the lot up with +/.

• save a few bytes by avoiding the separate comparison with ' ': {+/(⌊10*⍵-3)×60*+\2=⍵}'\ T<'⍳⌽ – ngn Aug 26 '18 at 9:16

# Python 2, 62 bytes

lambda s:reduce(lambda x,y:x+[10,0,59*x,1]["<\ ".find(y)],s,0)


Try it online!

This uses the technique from Arnauld's answer.

# Canvas, 2017 16 bytes

Ｓ｛｛<≡Ａ×²T≡］∑］<ｃ┴


Try it here!

Explanation:

E{          ]     map over input split on spaces
{       ]         map over the characters
<≡A×               (x=="<") * 10
²T≡            x=="T"
∑        sum all of the results
<c┴  and encode from base (codepoint of "<") to 10


# APL(NARS ⎕io←0), 28 chars, 56 bytes

{60⊥{+/⍵⍳⍨10⍴'\T'}¨⍵⊂⍨⍵≠' '}


some test with type check:

  q←{60⊥{+/⍵⍳⍨10⍴'\T'}¨⍵⊂⍨⍵≠' '}

o←⎕fmt
o q '<< <TT'
1212
~~~~
o q '<<<TT \ TTTT'
115204
~~~~~~


Each type result is number.

# JavaScript (Node.js), 122114107106 83 bytes

a=>a.split .map(b=>[...b].map(c=>x+=c<'T'?10:c<'U',x=0)&&x).reduce((a,b)=>a*60+b)


Try it online!

I'm a little obsessed with "functional-style" array operations, uses ASCII input, as far as I can tell, JS isn't very good at getting charcodes golfily

I'm keeping this for posterity's sake, but this is a naive/dumb solution, I suggest you check out Arnauld's answer which is far more interesting an implementation of the challenge

• @Shaggy looks like it works to me! – Skidsdev Aug 13 '18 at 10:45
• c<'T' works in place of c=='<' – Mr. Xcoder Aug 13 '18 at 10:47
• Save 1 more by replacing && with |. – Shaggy Aug 13 '18 at 13:03
• @Shaggy and save a lot more by using for...of loops :P – ASCII-only Aug 13 '18 at 21:50

# Retina, 2926 23 bytes

<
10*T
+^(.*)¶
60*$1 T  Try it online! Uses newline separation, but link includes header to use spaces instead for convenience. Edit: Saved 3 bytes with help from @KevinCruijssen. Saved a further 3 bytes thanks to @FryAmTheEggman. Explanation: < 10*T  Replace each < with 10 Ts. +^(.*)¶ 60*$1


Take the first line, multiply it by 60, and add the next line. Then repeat until there is only one line left.

T


Count the Ts.

Faster 51-byte version:

%^(<*)(T*).*
$.(10*$1$2 +^(.+)¶(.+)$.($1*60*_$2*


Try it online! Uses newline separation, but link includes header to use spaces instead for convenience. Explanation:

%^(<*)(T*).*
$.(10*$1$2  Match each line individually, and count the number of Ts and 10 times the number of <s. This converts each line into its base-60 "digit" value. +^(.+)¶(.+)$.($1*60*_$2*


Base 60 conversion, running a line at a time. The computation is done in decimal for speed.

• I'm pretty sure the third line can be just < without the +, unless I'm not seeing some kind of edge case. – Kevin Cruijssen Aug 13 '18 at 13:33
• @KevinCruijssen Even better, as $& is now always one character, I can use the default character, saving a further two bytes! – Neil Aug 13 '18 at 14:02 • Ah nice! :) Didn't knew that could be done implicitly for single characters. – Kevin Cruijssen Aug 13 '18 at 14:05 • @KevinCruijssen Well, I don't care what the character is, as I'm only taking the length; in Retina 1 you get a _ while $* in earlier versions of Retina defaults to 1. – Neil Aug 13 '18 at 14:09
• Ah, I see. Your initial code was taking all < as single match and repeat them 10 times the length (the amount of < in the match), and my proposed change is repeating every < separately 10 times (which you've golfed by 2 bytes more using the implicit 1 with 10*). Now I better understand why the + was there initially. I don't know too much about the Retina builtins, only regexes in general, hence my proposed change because I already read it as repeat every > 10 times. ;) – Kevin Cruijssen Aug 13 '18 at 14:16

# Bash (with sed and dc), 50 bytes

sed 's/</A+/g
s/T/1+/g
s/ /60*/g
s/\\//g'|dc -ez?p


Takes space-delimited input from stdin, outputs to stdout

Try it online!

# Explanation

Uses sed to transform the input with a bunch of regular expression matches until, for example, the input <<<TT \ TTTT has been transformed to A+A+A+1+1+60*60*1+1+1+1+. Then this input is fed to dc with the explicit input execution command ?, preceded by z (pushes the stack length (0) to the stack so that we have somewhere to ground the addition) and followed by p (print).

# J, 34 30 bytes

60#.1#.^:2(10 1*'<T'=/])&>@cut


Try it online!

# Dyalog APL, 35 32 bytes

f←{⍵+('<T\ '⍳⍺)⌷10,1,0,59×⍵}/∘⌽0∘,


Try it online!

31 in dzaima/APL

# Noether, 55 bytes

I~sL(si/~c{"<"=}{k10+~k}c{"T"=}{!k}c{" "=}{k60*~k}!i)kP


Try it online!

Same approach as @Arnauld.

# Charcoal, 26 bytes

≔⁰θＦＳ«≡ι ≦×⁶⁰θ<≦⁺χθT≦⊕θ»Ｉθ


Try it online! Link is to verbose version of code. Explanation:

≔⁰θ


Clear the result.

ＦＳ«...»


Loop over the input characters. The ≡ command is wrapped in a block to prevent it from finding a "default" block.

≡ι


Switch over the current character...

 ≦×⁶⁰θ


if it's a space then multiply the result by 60...

<≦⁺χθ


if it's a < then add 10 to the result...

T≦⊕θ


if it's a T then increment the result.

Ｉθ


Print the result.

# R, 98 81 bytes

(u=sapply(scan(,""),function(x,y=utf8ToInt(x))y%%3%*%(y%%6)))%*%60^(sum(u|1):1-1)


Try it online!

Ridiculously long due to string parsing. Thanks Giusppe for shaving off 16 unnecessary bytes.

Define y the bytecode value of unicode input and R = y("T<\") = y("𒐕𒌋𒑊")

Observe that R%%3 = 1,2,0 and R%%6 = 1,5,0... so R%%3 * R%%6 = 1,10,0 !

The rest is easy: sum per column, then dot-product with decreasing powers of 60.

• Porting Arnauld's asnwer using Reduce is likely to be more golfy. – JayCe Aug 13 '18 at 17:13
• doesn't scan(,"") split on spaces automatically? – Giuseppe Aug 13 '18 at 17:43
• nice trick with the mods, though! I was trying to figure that out but couldn't find it...and /60 can be replaced by -1 in the exponent expression for another byte off, plus the <- can be replaced by = since it's all in parentheses. – Giuseppe Aug 13 '18 at 17:54
• @Giuseppe I tried %%3 and it was promising so I kept looking... also using a dot product just saved me one additional byte :) – JayCe Aug 13 '18 at 18:01

# Ruby, 50 46 bytes

->a{x=0;a.bytes{|c|x+=[59*x,10,0,1][c%9%5]};x}


Try it online!

A basic port of Arnauld's answer improved by G B for -4 bytes.

• 45 bytes -actually 47 if you use "bytes" instead of "map" – G B Aug 13 '18 at 15:36
• Thanks @GB, I'll probably stick with the longer version, since taking input as raw bytecodes feels a bit too liberal for a language that normally supports strings. – Kirill L. Aug 13 '18 at 16:33
• Another byte off: 46 bytes – G B Aug 14 '18 at 6:02

# C (gcc), 6564 63 bytes

f(s,o)char*s;{for(o=0;*s;s++)o+=*s>32?(93^*s)/9:o*59;return o;}


Try it online!

• Replacing return o with s=o saves another 5 bytes. – ErikF Aug 14 '18 at 7:06

# Java 8, 64 60 bytes

a->{int r=0;for(int c:a)r+=c<33?r*59:c<63?10:84/c;return r;}


-4 bytes thanks to @ceilingcat.

Try it online. Explanation:

a->{            // Method with character-array parameter and integer return-type
int r=0;      //  Result-integer, starting at 0
for(int c:a)  //  Loop over each character c of the input-array
r+=         //   Increase the result by:
c<33?    //    Is the current character c a space:
r*59    //     Increase it by 59 times itself
:c<63?   //    Else-if it's a '<':
10      //     Increase it by 10
:c<85?   //    Else (it's a 'T' or '\'):
84/c;   //     Increase it by 84 integer-divided by c,
//     (which is 1 for 'T' and 0 for '\')
return r;}    //  Return the result


# Perl -F// -E, 39 bytes

$w+=/</?10:/T/?1:/ /?59*$w:0for@F;say$w  This reads the to be converted number from STDIN. This is essential the same solution as given by @Arnauld using JavaScript. ## F#, 128 bytes let s(v:string)=Seq.mapFoldBack(fun r i->i*Seq.sumBy(fun c->match c with|'<'->10|'T'->1|_->0)r,i*60)(v.Split ' ')1|>fst|>Seq.sum  Try it online! Ungolfed it would look like this: let s (v:string) = Seq.mapFoldBack(fun r i -> i * Seq.sumBy(fun c -> match c with | '<' -> 10 | 'T' ->1 | _ -> 0 ) r, i * 60) (v.Split ' ') 1 |> fst |> Seq.sum  Seq.mapFoldBack combines Seq.map and Seq.foldBack. Seq.mapFoldBack iterates through the sequence backwards, and threads an accumulator value through the sequence (in this case, i). For each element in the sequence, the Babylonian number is computed (by Seq.sumBy, which maps each character to a number and totals the result) and then multiplied by i. i is then multiplied by 60, and this value is then passed to the next item in the sequence. The initial state for the accumulator is 1. For example, the order of calls and results in Seq.mapFoldBack for input <<<TT \ TTTT would be: (TTTT, 1) -> (4, 60) (\, 60) -> (0, 3600) (<<<TT, 3600) -> (115200, 216000)  The function will return a tuple of seq<int>, int. The fst function returns the first item in that tuple, and Seq.sum does the actual summing. ### Why not use Seq.mapi or similar? Seq.mapi maps each element in the sequence, and provides the index to the mapping function. From there you could do 60 ** index (where ** is the power operator in F#). But ** requires floats, not ints, which means that you need to either initialise or cast all the values in the function as float. The entire function will return a float, which (in my opinion) is a little messy. Using Seq.mapi it can be done like this for 139 bytes: let f(v:string)=v.Split ' '|>Seq.rev|>Seq.mapi(fun i r->Seq.sumBy(fun c->match c with|'<'->10.0|'T'->1.0|_->0.0)r*(60.0**float i))|>Seq.sum  # Tcl, 134 bytes proc B l {regsub {\\}$l 0 l
lmap c [lreverse $l] {incr s [expr 60**([incr i]-1)*([regexp -all <$c]*10+[regexp -all T $c])]} expr$s}


Try it online!

In the reversed list, I loop incrementing the result in counting < and T (with -all regexp option) and incrementing a natural as power of 60.

Correct version (see comment)

• It seems I failed this one, because of the \ in the last number... I should had a regsub {\\} \$l0 l before the foreach loop.... – david Dec 23 '18 at 19:06

# APL (Dyalog Extended), 18 bytesSBCS

Anonymous tacit prefix function.

60⊥10⊥¨≠'<T'∘⍧¨⍤⊆⊢


Try it online!

                  ⊢  the argument; "<<<TT \ TTTT"
≠             mask where different from space; [1,1,1,1,1,0,1,0,1,1,1,1]
⊆    enclose runs of 1; ["<<<TT","\","TTTT"]
⍤     on that
¨      for each one
⍧       Count the occurrences In it of the elements
∘        of the entire list
'<T'         ["<","T"]; [[3,2],[0,0],[0,4]]
¨              for each one
10⊥               evaluate as base-10 digits
60⊥                  evaluate as base-60 digits


# 05AB1E (legacy), 10 bytes

#Ç9%5BO60β


Try it online!

#               # split input on spaces
Ç              # convert each character to its codepoint
9%            # modulo 9 (maps 𒌋 to 5, 𒐕 to 1, 𒑊 to 0)
5B          # convert each to base 5 (5 becomes 10, 0 and 1 unchanged)
O         # sum each column
60β      # convert from base 60


## 05AB1E, 11 bytes

#Ç9%5B€O60β


Try it online!

Same algorithm, but in modern 05AB1E O doesn't work on lists of mixed ints and lists, so we need €O instead.