Conta come un babilonese


41

Sfida

Data una rappresentazione ASCII di un numero babilonese come input, genera il numero in numeri arabi occidentali.

Sistema numerico babilonese

Come contavano i babilonesi? È interessante notare che hanno usato un sistema Base 60 con un elemento di un sistema Base 10. Consideriamo innanzitutto la colonna unitaria del sistema:

I babilonesi avevano solo tre simboli: T(o, se puoi renderlo:) 𒐕che rappresentava 1, e <(o, se puoi renderlo:) 𒌋che rappresentava 10 e \(o, se lo rendi:) 𒑊che rappresentava zero.

Nota: tecnicamente, \(o 𒑊) non è zero (perché i babilonesi non avevano una nozione di "zero"). 'Zero' è stato inventato in seguito, quindi è \stato aggiunto un simbolo segnaposto in seguito per evitare ambiguità. Tuttavia, ai fini di questa sfida, è sufficiente considerare \zero

Quindi, in ogni colonna basta aggiungere il valore dei simboli, ad esempio:

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

Non ci saranno mai più di cinque <o più di nove Tin ogni colonna. \apparirà sempre solo nella colonna.

Ora, dobbiamo estenderlo per aggiungere più colonne. Funziona esattamente come qualsiasi altra base sessanta, dove moltiplichi il valore della colonna più a destra per 600 , quello a sinistra per 601 , quello a sinistra per 602 e così via. Quindi aggiungi il valore di ciascuno per ottenere il valore del numero.

Le colonne saranno separate da spazi per evitare ambiguità.

Qualche esempio:

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

Regole

  • Sei libero di accettare input ASCII ( T<\) o input Unicode ( 𒐕𒌋𒑊)
  • Il numero immesso sarà sempre inferiore a 107
  • La <s sarà sempre alla sinistra della Ts in ogni colonna
  • \ apparirà sempre solo in una colonna

vincente

Vince il codice più breve in byte.


2
@TaylorScott Sì, puoi
Decadimento beta

2
Nel caso in cui aiuti: Max che deve essere gestito è di 4 colonne:<<<<TTTTTT <TTTTTTT <<<<TTTTTT <<<<
Wernisch

1
Le colonne sono sempre separate esattamente da uno spazio ciascuna ? Noto risposte basandosi su di esso.
KRyan,

4
I tipi stranieri con le pipe del narghilè dicono Ay oh whey oh, ay oh whey oh - Conta come un babilonese. Grande. Ora è bloccato nella mia testa.
Cobaltduck,

5
"How did the Babylonians count? Interestingly, they used a Base 60 system with an element of a Base 10 system."Che è ancora in uso oggi; il sistema numerico babilonese è esattamente quello che usiamo per gli orologi. Due cifre decimali ciascuna per secondi, minuti e ore, 60 secondi al minuto, 60 minuti all'ora.
Ray

Risposte:


39

JavaScript (ES6), 44 byte

Accetta input come una matrice di caratteri ASCII.

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

Provalo online!

Come?

Il sistema numerico babilonese può essere visto come un linguaggio di 4 istruzioni che lavora con un unico registro: chiamiamolo accumulatore.

A partire da , ogni carattere c nella matrice di input a modifica l'accumulatore k come segue:k=0cak

  • space: moltiplica per 60 (implementato come: aggiungi 59 k a k )k6059kk
  • <: aggiungi a k10k
  • T: incremento k
  • \: fare niente; questa è l' NOPistruzione di questa lingua (implementata come: aggiungi da a k )0k


11

Perl 6 , 39 byte

-3 byte grazie a nwellnhof

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

Provalo online!

Usa i caratteri cuneiformi.

Spiegazione:

{                                     }   # 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

Mi hai battuto per un paio di minuti. Ecco cosa mi è venuto in mente: {:60[.words>>.&{sum (.ords X%151)X%27}]}(40 byte)
nwellnhof

@nwellnhof Molto ben fatto! Come hai trovato i valori mod?
Jo King,

2
Semplicemente con la forza bruta.
nwellnhof,

11

Gelatina ,  13  12 byte

ḲO%7C%13§ḅ60

Un collegamento monadico che accetta un elenco di caratteri che produce un numero intero.

Provalo online!

Come?

Ḳ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],[92],[84,84,84,84]]
  %7         - modulo by seven (vectorises)    [[4,4,4,0,0],[1],[0,0,0,0]]
    C        - compliment (1-X)                [[-3,-3,-3,1,1],[0],[1,1,1,1]]
     %13     - modulo by thirteen              [[10,10,10,1,1],[0],[1,1,1,1]]
        §    - sum each                        [32,0,4]
         ḅ60 - convert from base sixty         115204

Un'altra 12: ḲO⁽¡€%:5§ḅ60( ⁽¡€è 1013, quindi questo modulos 1013dai Ovalori rdinal ottenere 53, 5e 1per <, T, \rispettivamente quindi esegue divisione intera, :da 5ottenere 10, 1e 0)


Lol, ho eliminato la mia risposta proprio per questo, poiché mi sono ricordato che avrei potuto usare la conversione di base ma ero letteralmente troppo pigro per scoprire come. +1
Mr. Xcoder

6

05AB1E , 13 byte

8740|Ç%4/O60β

Provalo online!

Per compensare quanto sono stato pigro con la mia risposta Jelly, ecco una presentazione in 05AB1E xD.


Aiuta 05AB1E-là fuori, non c'era un modo per comprimere numeri come 8740?
Mr. Xcoder,

2
codegolf.stackexchange.com/a/166851/52210 Sfortunatamente non sarebbe più corto: •Yη•(4 byte)
Kevin Cruijssen

2
@KevinCruijssen Grazie! Questa risposta è molto utile, la userò totalmente in futuro
Mr. Xcoder il

1
Sono contento che la punta sia utile. :) Ho capito queste cose dopo aver visto alcune risposte usandole. La parte del dizionario è stata spiegata qui . E la compressione di altre stringhe o interi di grandi dimensioni mi sono resa conto dopo aver visto l'esempio collegato risposte per "oca" e 246060 .
Kevin Cruijssen,

1|Ç7%-13%O60βè anche 13 - è golfabile?
Jonathan Allan,


4

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
                    ''   add count of T's
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

4

Dyalog APL, 33 30 bytes

{+/(⌊10*⍵-360*+\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


3

Canvas, 20 17 16 bytes

S{{<≡AײT≡]∑]<c┴

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

3

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.


2

JavaScript (Node.js), 122 114 107 106 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

c<'T' works in place of c=='<'
Mr. Xcoder

Save 1 more by replacing && with |.
Shaggy

@Shaggy and save a lot more by using for...of loops :P
ASCII-only

2

Retina, 29 26 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

1
@KevinCruijssen Even better, as $& is now always one character, I can use the default character, saving a further two bytes!
Neil

Ah nice! :) Didn't knew that could be done implicitly for single characters.
Kevin Cruijssen

@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

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

2

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).





1

Charcoal, 26 bytes

≔⁰θFS«≡ι ≦×⁶⁰θ<≦⁺χθT≦⊕θ»Iθ

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

≔⁰θ

Clear the result.

FS«...»

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.

Iθ

Print the result.


1

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

doesn't scan(,"") split on spaces automatically?
Giuseppe

1
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

@Giuseppe I tried %%3 and it was promising so I kept looking... also using a dot product just saved me one additional byte :)
JayCe

1

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.


1
45 bytes -actually 47 if you use "bytes" instead of "map"
G B

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.

1
Another byte off: 46 bytes
G B


1

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

0

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.


0

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

0

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

0

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

0

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.