14
\$\begingroup\$

Leonardo of Pisa (ca. 1175 - ca. 1245) is better known as Fibonacci. But this is actually a short for the Latin "filius Bonacci" (the son of Bonacci) which was made up during the 18th century (according to Wikipedia).

In this challenge, you'll be given an ordinal number (in the literal sense) between 1st and 20th and you have to return the corresponding term in the Fibonacci sequence.

The twist is that the ordinal number will be given in Latin.

Example: "duodecimus" → \$89\$.

Full I/O table

 input              | meaning | output
--------------------+---------+--------
 "primus"           |   1st   |    0
 "secundus"         |   2nd   |    1
 "tertius"          |   3rd   |    1
 "quartus"          |   4th   |    2
 "quintus"          |   5th   |    3
 "sextus"           |   6th   |    5
 "septimus"         |   7th   |    8
 "octavus"          |   8th   |   13
 "nonus"            |   9th   |   21
 "decimus"          |  10th   |   34
 "undecimus"        |  11th   |   55
 "duodecimus"       |  12th   |   89
 "tertius decimus"  |  13th   |  144
 "quartus decimus"  |  14th   |  233
 "quintus decimus"  |  15th   |  377
 "sextus decimus"   |  16th   |  610
 "septimus decimus" |  17th   |  987
 "duodevicesimus"   |  18th   | 1597
 "undevicesimus"    |  19th   | 2584
 "vicesimus"        |  20th   | 4181

Rules

  • The input is guaranteed to be exactly one of the strings described above.
  • If that helps, you may take it in full uppercase instead. But it must be consistent for all entries. Mixed cases are not allowed.
  • Depending on your algorithm and language, hardcoding or computing the terms of the sequence may either win or lose bytes. Both approaches are explicitly allowed.
  • This is !
\$\endgroup\$

10 Answers 10

8
\$\begingroup\$

R, 91 86 bytes

Look up the index of the sum of bytes in a brute-forced UTF8 lookup table and use the magic Fibonacci generating function to give the answer.

function(x)round(1.618^match(sum(!x)%%93,!'%(-1!5+3JOSCW6')*.2765)
"!"=utf8ToInt

Try it online!

Edit: -2 bytes by improved numeric rounding

Edit: -3 bytes with a change to the lookup (thanks for the hint, @Giuseppe!)

\$\endgroup\$
  • \$\begingroup\$ Wanted to do something similar with UTF8 lookup. Had no clue you could Fibonnaci like that. probably shorter than what I wanted to do (chartr the UTF8 of the sum with the UTF8 of the fibonacci value, and then intToUtf8 the output of chartr. \$\endgroup\$ – JayCe Aug 16 '18 at 13:44
  • \$\begingroup\$ 90 bytes \$\endgroup\$ – Giuseppe Aug 16 '18 at 15:11
  • \$\begingroup\$ Seems to fail for "sextus decimus", Giuseppe. \$\endgroup\$ – J.Doe Aug 16 '18 at 17:01
  • 1
    \$\begingroup\$ You were onto the right thing @Giuseppe, turned out there were 3 magic 2-digit moduli for which the sum of bytes was unique, 69, 88 and 93, and 88 was the one which didn't need any constant added to make an intelligible string. \$\endgroup\$ – J.Doe Aug 16 '18 at 18:23
  • 9
    \$\begingroup\$ Sometimes I feel like half of codegolf is finding the right number use as the modulus... \$\endgroup\$ – Giuseppe Aug 16 '18 at 18:26
4
\$\begingroup\$

Ruby, 104 93 bytes

->x{[8,4181,3,144,21,13,0,1,233,5,987,0,377,55,0,89,1,1597,34,610,0,2,2584][x.sum%192%76%23]}

Try it online!

Simply takes the sum of the bytes, modulo 192 modulo 76 modulo 23, and indexes into a lookup table. (Magic numbers found by brute force.)

\$\endgroup\$
4
\$\begingroup\$

Clean, 87 bytes

All escapes except \n are treated as one byte, since the compiler's fine with the actual raw values. (TIO and SE have issues with it not being valid UTF-8 though, and so it's escaped here)

FryAmTheEggman made a nice demonstration / workaround: here

import StdEnv
$s=hd[i\\i<-k 1 0&c<-:"\340\152\060\065\071\354\172\045\223\n\255\362\132\137\143\026\244\051\344\270"|c==sum s]
k b a=[a:k(a+b)b]

Try it online!

Defines the function $ :: [Char] -> Int, which uses the uniqueness in the summation of the uppercase character values to determine which term in the sequence (generated by the helper function k) to return.

\$\endgroup\$
4
\$\begingroup\$

6502 machine code (C64), 82 bytes

00 C0 20 9E AD 20 A3 B6 A8 88 A9 05 4A 90 02 49 B1 71 22 88 10 F6 29 1F C9 07
B0 02 69 0D A8 BE 32 C0 B9 1E C0 4C CD BD 00 00 00 00 03 00 0A 00 06 10 01 00
FF 00 02 00 00 00 00 00 08 00 15 0D DB 02 18 90 3D 55 79 05 FF E9 62 22 01 59
01 37 FF 03

This uses hashing (of course), but optimized for short implementation on the 6502, taking advantage of the carry flag set by shifting and used in addition. Magic numbers for hashing were found by brute forcing with a little C program; the FF bytes are unfortunate holes in the hash table ;)

Byte count: 2 bytes load address, 38 bytes code, 42 bytes hashtable for values.

Online demo

Usage: SYS49152"[ordinal]", for example SYS49152"DUODECIMUS". (note the letters appear upper case in the default C64 configuration).

Important: Before the first start, issue a NEW command. This is needed because the C64 BASIC LOAD command fiddles with some BASIC vectors, even when loading a machine program to some absolute address (like here $C000/49152).

Commented disassembly:

         00 C0                          ; load address
.C:c000  20 9E AD    JSR $AD9E          ; evaluate expression
.C:c003  20 A3 B6    JSR $B6A3          ; evaluate as string
.C:c006  A8          TAY                ; length to y register
.C:c007  88          DEY                ; decrement (start at last char)
.C:c008  A9 05       LDA #$05           ; start value for hash
.C:c00a   .hashloop:
.C:c00a  4A          LSR A              ; shift right
.C:c00b  90 02       BCC .skip          ; shifted bit zero? -> skip xor
.C:c00d  49 B1       EOR #$B1           ; xor "magic" value
.C:c00f   .skip:
.C:c00f  71 22       ADC ($22),Y        ; add current character (plus carry)
.C:c011  88          DEY                ; previous character
.C:c012  10 F6       BPL .hashloop      ; pos >= 0? -> repeat
.C:c014  29 1F       AND #$1F           ; mask lowest 5 bits
.C:c016  C9 07       CMP #$07           ; larger than 7 ?
.C:c018  B0 02       BCS .output        ; -> to output
.C:c01a  69 0D       ADC #$0D           ; add 13
.C:c01c   .output:
.C:c01c  A8          TAY                ; hash to y register
.C:c01d  BE 32 C0    LDX .lb-8,Y        ; load low byte from hashtable
.C:c020  B9 1E C0    LDA .hb-8,Y        ; load high byte from hashtable
.C:c023  4C CD BD    JMP $BDCD          ; to output of 16bit number
.C:c026   .hb:
.C:c026  00 00 00 00 .BYTE $00,$00,$00,$00
.C:c02a  03 00 0A 00 .BYTE $03,$00,$0A,$00
.C:c02e  06 10 01 00 .BYTE $06,$10,$01,$00
.C:c032  FF 00 02 00 .BYTE $FF,$00,$02,$00
.C:c036  00 00 00 00 .BYTE $00,$00,$00,$00
.C:c03a   .lb:
.C:c03a  08 00 15 0D .BYTE $08,$00,$15,$0D  ; second byte used in .hb as well
.C:c03e  DB 02 18 90 .BYTE $DB,$02,$18,$90
.C:c042  3D 55 79 05 .BYTE $3D,$55,$79,$05
.C:c046  FF E9 62 22 .BYTE $FF,$E9,$62,$22
.C:c04a  01 59 01 37 .BYTE $01,$59,$01,$37
.C:c04e  FF 03       .BYTE $FF,$03

C64 BASIC V2 test suite

(containing the machine program in DATA lines)

Online demo

0fOa=49152to49231:rEb:pOa,b:nE
1?"primus",:sY49152"primus":?
2?"secundus",:sY49152"secundus":?
3?"tertius",:sY49152"tertius":?
4?"quartus",:sY49152"quartus":?
5?"quintus",:sY49152"quintus":?
6?"sextus",:sY49152"sextus":?
7?"septimus",:sY49152"septimus":?
8?"octavus",:sY49152"octavus":?
9?"nonus",:sY49152"nonus":?
10?"decimus",:sY49152"decimus":?
11?"undecimus",:sY49152"undecimus":?
12?"duodecimus",:sY49152"duodecimus":?
13?"tertius decimus",:sY49152"tertius decimus":?
14?"quartus decimus",:sY49152"quartus decimus":?
15?"quintus decimus",:sY49152"quintus decimus":?
16?"sextus decimus",:sY49152"sextus decimus":?
17?"septimus decimus",:sY49152"septimus decimus":?
18?"duodevicesimus",:sY49152"duodevicesimus":?
19?"undevicesimus",:sY49152"undevicesimus":?
20?"vicesimus",:sY49152"vicesimus":?
21dA32,158,173,32,163,182,168,136,169,5,74,144,2,73,177,113,34,136,16,246,41,31
22dA201,7,176,2,105,13,168,190,50,192,185,30,192,76,205,189,0,0,0,0,3,0,10,0,6
23dA16,1,0,255,0,2,0,0,0,0,0,8,0,21,13,219,2,24,144,61,85,121,5,255,233,98,34,1
24dA89,1,55,255,3
\$\endgroup\$
3
\$\begingroup\$

Perl 6, 62 bytes

{(0,1,*+*...*)[index '%(-1!5+3JOSCW6',chr .ords.sum%93]}

Try it online!

Uses a lookup table in a string, as well as a short fibonacci sequence generator.

\$\endgroup\$
3
\$\begingroup\$

C (gcc), 135 129 bytes

6 bytes down by suggestion of ceilingcat and Logern

f;i;b;o;n(char*a){for(f=i=b=o=0;*a;o+=21*b+++*a++-70);for(b=1,o="TACIHAAJQFSAAARCAMGKDANPEAOAAL"[o%30];--o>65;f=b,b=i)i=f+b;a=i;}

Try it online!

Explanation:

f; i; b; o; // Variables

n (char *a)
{
     // Calculate a silly hash of incoming string
     for (f = i = b = o = 0; *a; o += 21 * b++ + *a++ - 70);

     // Use the hash to index into the array of number values
     // and calculate the corresponding Fibonacci sequence element
     for
     (
         b = 1, 
         o = "TACIHAAJQFSAAARCAMGKDANPEAOAAL"[o % 30]; 

         --o > 65; 
         f = b, b = i
     )
         i = f + b;

     // implicit return
     a = i;
}
\$\endgroup\$
  • \$\begingroup\$ You can replace return i; with a=i; \$\endgroup\$ – Logern Sep 28 '18 at 13:07
2
\$\begingroup\$

Pyth, 54 bytes

L?>b1+ytbyttbbyxc."axnÛ±r†XVW‹(„WîµÏ£"2+hQ@Q618

Test suite

Notice: as the code makes use of some unprintable characters, it may not display correctly on Stack Exchange. The link provided leads to a working and copy-pastable source.

Long story short, Q[0]+Q[618%len(Q)] gives unique results for all accepted inputs Q.

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

Python 2, 292 bytes

f=lambda x:x>1and f(x-1)+f(x-2)or x
def g(t):
	for i,c in zip("pr secun ter qua qui sex sep oc no ec".split(),range(1,11))+zip("un duo es ev".split(),(1,2,20,"-")):t=t.replace(i,str(c))
	return f(abs(eval("+".join("".join((" ",c)[c in"0123456789-"]for c in t).split()).replace("+-+","-")))-1)

Try it online!

Fibonacci generator shamelessly stolen from this answer.

Breaks each word down into its meaningful component parts and discards the rest (in "duodevicesimus", for example, we only care about "duo ev es "-> "2 - 20 " - > abs("2-20") -> 18).

Passes the calculated value (minus 1 to 0-offset) to the Fibonacci generator function.

Ungolfed Explanation:

# Fibonacci function
f=lambda x:x>1and f(x-1)+f(x-2)or x

def g(t):
    # generates a list of key, value pairs like [("pr", 1, ..., ("ec", 10)] +
    values = zip("pr secun ter qua qui sex sep oc no ec".split(), range(1,11))

    # adds values to existing list
    values += zip("un duo es ev".split(),(1,2,20,"-"))

    # replace the matching values in the string with the appropriate number/sign.
    # ORDER MATTERS - if "un" is searched for before "secun", this generates incorrect values.
    for i,c in values:
        t = t.replace(i,str(c))

    # replace each non-digit, non-minus character in string with "c"
    t = [(" ",c)[c in"0123456789-"]for c in t]

    # convert space-replaced array back to a string
    # then split it on spaces, creating an array of values
    t = "".join(t).split()

    # turn the array back into a string, with each individual item separated by "+"
    # this will cause "-" to become "+-+" (since "-" is ALWAYS between two numbers), so prelace that sequence with "-"
    t = "+".join(t).replace("+-+","-")

    # evaluate the string as an expression, and take the absolute value for when - occurs
    t = abs(eval(t))

    # pass the value, minus 1 for 0-offset, to the Fibonacci function.
    return f(t-1)
\$\endgroup\$
1
\$\begingroup\$

Python 2, 97 79 bytes

lambda s:int(1.618**('RV3NJ^[KDP=Z62AWeG<C'.find(chr(hash(s)%69+48)))*.4474+.5)

Try it online!

First, we want to convert from latin to a number n; this is accomplished by replicating the input string enough times to ensure that there are at least 11 characters total; and then the 3rd and 10th characters (zero indexed) form a unique pair taking the hash mod 69 and turning that into a printable char.

Now we have n. To find the nth Fibonacci number, we can use the rounding method, using only as many digits of precision as we need up to Fib(20).

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

JavaScript (Node.js), 100 97 95 92 91 bytes

x=>1.618**(p=parseInt)("1 jgf7  ei 490dbch62385a"[p(x.length+x,32)%12789%24],36)*.4474+.5|0

Try it online!

Warning: WORKS BECAUSE OF FLOATING POINT INACCURACY

JavaScript has neither a built-in hash function, nor a short enough character-to-ASCII function (String.charCodeAt is the shortest already), so I need to define a simple hash function by myself.

Used the same rounding method as Chas Brown did after calculating the hash.

After a whole day of brute-forcing a better is found:

b32_to_dec(x.length + x) % 12789 % 24 (*floating point inaccuracy)

b32_to_dec(x.length + x) % 353 % 27 (*floating point inaccuracy)

b36_to_dec(x.length + x[2]) % 158 % 29 - 4

b36_to_dec(x[2] + x.length) % 741 % 30

b36_to_dec(x[0] + x[2] + x.length) % 4190 % 27

parseInt(x.length + x, 32) result

primus 7310236636
secundus 9773632960476
tertius 272155724764
quartus 269453490140
quintus 269461747676
sextus 7054
septimus 9774067964892
octavus 266721394652
nonus 192700380
decimus 254959770588
undecimus 350449413217244
duodecimus 36520018280274912 **NOT PRECISE**
tertius decimus 1302947875804
quartus decimus 1300245641180
quintus decimus 1300253898716
sextus decimus 37774
septimus decimus 42759416798172
duodevicesimus 43016381192006637977600 **NOT PRECISE**
undevicesimus 1326703556626028691456 **NOT PRECISE**
vicesimus 351376069188572

Version without exploitation of floating point inaccuracy: 95 bytes

x=>1.618**(p=parseInt)("52d7i 6  he 8309jafc 41bg"[p(x.length+x[2],36)%158%29-4],36)*.4474+.5|0

Try it online!

b36_to_dec(x.length + x[2]) % 158 % 29 - 4

Hash Table

 Latin word           | Length | 3rd | Hash | Decimal | %158 | %29-4
----------------------+--------+-----+------+---------+------+-------
 primus               |      6 | i   | 6i   |     234 |   76 |    14
 secundus             |      8 | c   | 8c   |     300 |  142 |    22
 tertius              |      7 | r   | 7r   |     279 |  121 |     1
 quartus              |      7 | a   | 7a   |     262 |  104 |    13
 quintus              |      7 | i   | 7i   |     270 |  112 |    21
 sextus               |      6 | x   | 6x   |     249 |   91 |     0
 septimus             |      8 | p   | 8p   |     313 |  155 |     6
 octavus              |      7 | t   | 7t   |     281 |  123 |     3
 nonus                |      5 | n   | 5n   |     203 |   45 |    12
 decimus              |      7 | c   | 7c   |     264 |  106 |    15
 undecimus            |      9 | d   | 9d   |     337 |   21 |    17
 duodecimus           |     10 | o   | 10o  |    1320 |   56 |    23
 tertius decimus      |     15 | r   | 15r  |    1503 |   81 |    19
 quartus decimus      |     15 | a   | 15a  |    1486 |   64 |     2
 quintus decimus      |     15 | i   | 15i  |    1494 |   72 |    10
 sextus decimus       |     14 | x   | 14x  |    1473 |   51 |    18
 septimus decimus     |     16 | p   | 16p  |    1537 |  115 |    24
 duodevicesimus       |     14 | o   | 14o  |    1464 |   42 |     9
 undevicesimus        |     13 | d   | 13d  |    1417 |  153 |     4
 vicesimus            |      9 | c   | 9c   |     336 |   20 |    16
\$\endgroup\$

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.