12
\$\begingroup\$

The following puzzle was invented by Eric Angelini in September 2007.

As mentioned in A131744 :

the sequence is defined by the property that if one writes the English names for the entries, replaces each letter with its rank in the alphabet and calculates the absolute values of the differences, one recovers the sequence.

To be precise, the alphabet starts at 1, so a is 1, b is 2, etc. Also, 15 is supposed to be treated as fifteen and 21 as twentyone (not twenty-one).

Example :

Begin with 1 :

1 -> "one" -> 15,14,5 -> absolute(15-14),absolute(14-5) -> 1,9
1,9 -> "one,nine" -> 15,14,5,14,9,14,5 -> 1,9,9,5,5,9
1,9,9,5,5,9 -> "one,nine,nine,five,five,nine" -> 15,14,5,14,9,14,5,14,9,14,5,6,9,22,5,6,9,22,5,14,9,14,5 -> 1,9,9,5,5,9,9,5,5,9,1,3,13,17,1,3,13,17,9,5,5,9
1,9,9,5,5,9,9,5,5,9,1,3,13,17,1,3,13,17,9,5,5,9 -> ...

So the first 22 terms are : 1,9,9,5,5,9,9,5,5,9,1,3,13,17,1,3,13,17,9,5,5,9

You can find the 40000 first terms here : b131744

Challenge

Sequence I/O methods apply. You may use one of the following I/O methods:

  • Take no input and output the sequence indefinitely,
  • Take a (0- or 1-based) index i and output the i-th term,
  • Take a non-negative integer i and output the first i terms.

The shortest code in bytes wins.

\$\endgroup\$
3
  • 4
    \$\begingroup\$ Is 15 supposed to be treated as one five or fifteen? \$\endgroup\$
    – Arnauld
    Aug 6 at 17:04
  • 1
    \$\begingroup\$ And would 42 be forty-two, forty two, fortytwo, four two, or fourtwo? I assume it's either fortytwo or fourtwo. \$\endgroup\$
    – user
    Aug 6 at 17:19
  • \$\begingroup\$ 15 is fifteen and 42 is fortytwo. I will edit my post. \$\endgroup\$
    – Basto
    Aug 6 at 17:29
4
\$\begingroup\$

Python 3, 119 bytes

Outputs the sequence indefinitely.

from unicodedata import*
p,*a=b'5NE'
for x in a:
 if x>45:n=abs(p-x);a+=name(chr(13144+n))[38:print(n%24)].encode();p=x

Try it online!

Python's unicodedata.name allows us to access the name of a unicode character. It happens that the characters with codepoints in the range 0x3358..0x336D partially contain all of the required words (as can be seen in this list). The only nuance is at twentyone, of which name() gives us twenty-one instead. This is fixed with a simple if x>45, which ignores any existing -. This allows us to save over 70 bytes in total. Other than the sneaky unicodedata.name, it is essentially the same as the answer below.

Python 3, 196 bytes

p,*a=b'Wne'
for x in a:n=abs(x-p);print(n%22);p=x;a+=b'zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,four,fif,,seven,eigh,,,twentyone,,'.split(b',')[n]+b'teen'*(12<n<20)

Try it online!

Explanation

We start off with a = b'ne', which will keep track of all the English words. Note that ne are the last two letters of one (the first number in the sequence). In the following for loop, we iterate over a, and in each iteration we add a word to the sequence based on the value of abs(x-p), where x and p are the current and previous letters in a, respectively.

The illustration below, while not an exact model, roughly describes the algorithm I am using to construct the sequence:

'one',             n = abs(s[2]-s[1]) = abs('e'-'n') = 9 ->
'onenine',         n = abs(s[3]-s[2]) = abs('n'-'e') = 9 ->
'oneninenine',     n = abs(s[4]-s[3]) = abs('i'-'n') = 5 ->
'onenineninefive', n = abs(s[5]-s[4]) = abs('n'-'i') = 5 ->
...

One last thing to mention is the peculiar W in the initialization of a, or the strange %22 within the print statement. These are both needed to print the initial 1. We may get rid of them for 190 bytes, but the 1 at the beginning would be omitted:

p,*a=b'ne'
for x in a:n=abs(x-p);print(n);p=x;a+=b'zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,four,fif,,seven,eigh,,,twentyone'.split(b',')[n]+b'teen'*(12<n<20)

This is currently the shortest fix I could find for eliminating this edge case, though there's likely a shorter approach (I'll exclude an explanation for it as an exercise to the reader).

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

JavaScript (Node.js),  240  228 bytes

Thanks to @ovs for pointing out that 16, 19 and 20 are never used

A naive implementation. Returns the \$n\$th term, 0-indexed.

f=(n,a=[1])=>1/a[n]?a[n]:f(n,[...Buffer(a.map(x=>`ZeroOneTwoThreeFourFiveSixSevenEightNineTenElevenTwelveThirteenFourteenFifteenXSeventeenEighteenXXTwentyone`.match(/.[a-z]*/g)[x]).join``)].map(x=>Math.abs(a-(a=x&31))).slice(1))

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ According to the OEIS entry 16, 19 and 20 never appear in the sequence. That should help to save some bytes \$\endgroup\$
    – ovs
    Aug 6 at 18:05
  • \$\begingroup\$ Scratch that, @Arnauld; I was going by the sequence as it appears in the spec and on OEIS - checked the full list since and see I was wrong. \$\endgroup\$
    – Shaggy
    Aug 6 at 18:24
3
\$\begingroup\$

Jelly, 69 64 bytes

ị“£3ṃ×ʋƁṘFqœ<ɦẎĠ_NɗṾDæ¢$⁽ċ¶Ọɦµ⁽ƭẈġȥ⁶J§GaĊƙ-ƬėƓjḢƥ4¶;»Ḳ¤FOạƝ
1Ç¡ḣ

Try it online!

A pair of links that is called as a monad with an integer input \$n\$ and returns the first \$n\$ terms. Slow for larger n (since it actually generates far more terms than needed before truncating the list). At a cost of a byte, this is much more efficient.

Thanks to @JonathanAllan for saving 5 bytes!

Explanation

ị                | Index into:
 “£…;»Ḳ¤         | - "one two three four … twentyone zero", split on spaces
        F        | Flatten
         ØaiⱮ    | Index of each character in the lowercase alphabet
             ạƝ  | Absolute differences of neighbouring pairs
1                | Starting with 1:
 Ç¡              | Call the helper link n times
   ḣ             | First n values
\$\endgroup\$
4
  • 2
    \$\begingroup\$ ØaiⱮ can just be O since the differences will still be the same. \$\endgroup\$ Aug 6 at 20:59
  • \$\begingroup\$ Is twentyone too far along? I think so TIO \$\endgroup\$ Aug 6 at 21:01
  • 1
    \$\begingroup\$ This is right I think, and saves two in the process TIO \$\endgroup\$ Aug 6 at 21:04
  • \$\begingroup\$ (The first difference would be at the 1117th entry.) \$\endgroup\$ Aug 6 at 21:14
2
\$\begingroup\$

Wolfram Language (Mathematica), 117 bytes

outputs the first i terms

(s=#;NestWhile[Abs@Differences@Flatten[LetterNumber[Characters@IntegerName@#/."-"->""]&/@#]&,{1},Tr[1^#]<s&][[;;s]])&

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Mind adding an explanation? I'm learning Wolfram and while I understand most of this, a few parts are still foreign. \$\endgroup\$
    – Jonah
    Aug 7 at 3:06
  • 1
    \$\begingroup\$ In case you're interested, there's a 90-byte implementation by Giorgos Kalogeropoulos (Nest[Abs@Differences@Flatten[LetterNumber[Characters[IntegerName@#]/."-"->""]&/@#]&,{1},4]) on the linked OEIS page (oeis.org/A131744). \$\endgroup\$
    – theorist
    Aug 7 at 3:20
  • 1
    \$\begingroup\$ @theorist The code of my friend Giorgos produces chunks of 2,6,22,104,524,2712... terms.So, the only problem is the output. Theoritically you can use this 95 bytes code but it is extremely inefficient for terms >8. (in order to get the 8th term this code calculates 72672 terms!). But this is code-golf and an answer like this is also accepted. \$\endgroup\$
    – ZaMoC
    Aug 7 at 7:20
  • \$\begingroup\$ @Jonah This simply produces nested chunks of terms until the desired number of terms is reached and then takes only the first i terms. \$\endgroup\$
    – ZaMoC
    Aug 7 at 7:42
2
\$\begingroup\$

Vyxal, 83 bytes

1 9"£{`λḭ ƛ» ∧ḭ ⟇¯ ײ ß• ⌐≤ ƈḞ ∵‹ ¢Ṗ Ẇ„ ⟨ǐ t¥ẏ⟑⌈ ⟇¯⟑⌈ Ṡ□ ⌐≤⟑⌈ e⋏ṫ⟑⌈ ←⊍λḭ`⌈¥‹İṅC¯ȧ…£

Try it Online!

Outputs the values infinitely

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

Factor + math.text.english, 109 98 bytes

[ { 1 } [ [ number>text R/ \sand|,|-| / ""re-replace >array ] map-flat differences vabs ] repeat ]

Try it online!

Takes a 0-based index and outputs the i-th term.

  • { 1 } [ ... ] repeat Call a quotation a given number of times, transforming our starting sequence { 1 } that many times.
  • [ ... ] map-flat Apply a quotation to each element of a sequence, collecting each result into a flat sequence.
  • number>text Convert a number to a string, like 2222 -> "two thousand, two hundred and twenty-two".
  • R/ \sand|,|-| / ""re-replace Since number>text produces commas, spaces, hyphens and " and", strip them out with a regular expression.
  • >array Convert the string to an array (e.g. "hi" -> { 104 105 }). This is necessary for differences to work properly.
  • differences Take the first-order forward difference.
  • vabs Take the absolute value of a sequence. (Like [ abs ] map, but shorter).
\$\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.