13
\$\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, 2021 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, 2021 at 17:19
  • \$\begingroup\$ 15 is fifteen and 42 is fortytwo. I will edit my post. \$\endgroup\$
    – Basto
    Aug 6, 2021 at 17:29

6 Answers 6

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, 2021 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, 2021 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, 2021 at 20:59
  • \$\begingroup\$ Is twentyone too far along? I think so TIO \$\endgroup\$ Aug 6, 2021 at 21:01
  • 1
    \$\begingroup\$ This is right I think, and saves two in the process TIO \$\endgroup\$ Aug 6, 2021 at 21:04
  • \$\begingroup\$ (The first difference would be at the 1117th entry.) \$\endgroup\$ Aug 6, 2021 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\$
3
  • \$\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, 2021 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, 2021 at 3: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, 2021 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 and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.