# Find the Infinity Words!

(Note: This is a spin-off of my previous challenge Find the Swirling Words!)

### Definition of Infinity Word:

1. If you connect with curves all the characters of an Infinity Word on the alphabet (A-Z) you obtain the infinity symbol ∞ like in the diagrams below.
2. All the even connection must be down, all the odd connections must be up.
3. You can ignore upper/lowercase or consider/convert all to upper case or all to lower case.
4. The input words are only characters in the alphabet range of A-Z, no spaces, no punctuation, or symbols.
5. Each word must be exactly 5 characters. Words > 5 or < 5 are not valid.
6. If a word has double consecutive characters, the word is not valid, like "FLOOD" or "QUEEN".
7. All the Infinity Words start and end with the same character.

Here there are some examples:

Write a full program or function that will take a word from standard input and will output if is an Infinity Word or not. The output can be true/false, 1/0, 1/Null, etc.

Test cases:

Infinity Words:
ALPHA, EAGLE, HARSH, NINON, PINUP, RULER, THEFT, WIDOW

NOT Infinity Words:
CUBIC, ERASE, FLUFF, LABEL, MODEM, RADAR, RIVER, SWISS, TRUST,
KNEES, QUEEN, GROOVE, ONLY, CHARACTER, OFF, IT, ORTHO

### Rules:

1. Shortest code wins.

Find, as a list, as many Infinity Words as you can in an English dictionary. You can take for example as reference the complete list of English words here.

• Can we assume the input is always of length 5? You have defined rule 5: "Each word must be exactly 5 characters. Words > 5 or < 5 are not valid.", but no NOT Infinity Words containing less or more than 5 characters. – Kevin Cruijssen Oct 17 '16 at 13:48
• Pretty funny that ALPHA makes that pattern – Fatalize Oct 17 '16 at 13:49
• @KevinCruijssen You must check that the word respect the definition, I updated the false cases. – Mario Oct 17 '16 at 13:56
• @Arnauld five "A"'s connects to themselves (or doesen't move at all) creating a single point, it doesen't draw the infinity symbol, so I don't think it's a positive case. – Mario Oct 17 '16 at 16:25
• I have decided to tackle the Optional Task: "Find, as a list, as many Infinity Words as you can in an English dictionary..." I used this source and Kevin Cruijssen's answer, to produce this list of 278 Infinity Words. – Thomas Quinn Kelly Oct 18 '16 at 22:16

# Jelly, 43 41 40 25 24 23 22 21 14 13 bytes

## Python 2, 71 bytes

lambda s:map(cmp,s,s[1:]+s[0])in[[m,n,-m,-n,0]for m in-1,1for n in-1,1]

Takes the string s with characters abcde, rotates it to bcdea, and does an elementwise comparison of corresponding characters.

a  b   cmp(a,b)
b  c   cmp(b,c)
c  d   cmp(c,d)
d  e   cmp(d,e)
e  a   cmp(e,a)

The result is a list of -1, 0, 1. Then, checks if the result is one of the valid sequences of up and downs:

[-1, -1, 1, 1, 0]
[-1, 1, 1, -1, 0]
[1, -1, -1, 1, 0]
[1, 1, -1, -1, 0]

as generated from the template [m,n,-m,-n,0] with m,n=±1. The last 0 checks that the first and last letter were equal, and the length ensures that the input string had length 5.

An alternative 71. Checks the conditions on comparisons while ensuring the right length.

def f(s):a,b,c,d,e=map(cmp,s,s[1:]+s*9)[:5];print a*c<0==e>b*d>len(s)-7

## R, 144 bytes

The answer is based off the logic of @Jonathan Allan. It could probably be golfed though.

s=strsplit(scan(,""),"")[[1]];d=diff(match(s,LETTERS));s[1]==tail(s,1)&length(s)==5&all(!rle(s)$l-1)&!sum(d)&!sum(sign(d))&any(rle(sign(d))$l>1)

R-fiddle test cases (vectorized example but same logic)

• Since you already have a check that length(s)==5, you can replace s[1]==tail(s,1) with s[1]==s[5]. A one-byte shorter method to check the length is is.na(s[6]). Together these two changes return TRUE for s of length 5 exactly and FALSE otherwise, as TRUE&NA is NA but FALSE&NA is FALSE. You can also save a few bytes by replacing !sum(sign(d))&any(rle(sign(d))$l>1) with !sum(a<-sign(d))&any(rle(a)$l>1). – rturnbull Nov 16 '16 at 16:32

# GNU Prolog, 47 bytes

i([A,B,C,D,A]):-A>B,B>C,C<D,D<A;i([B,C,D,A,B]).

Defines a predicate i which succeeds (infinitely many times, in fact) for an infinity word, thus outputting "yes" when run from the interpreter (as is usual for Prolog); fails for a candidate word whose first and last letters don't match, or isn't 5 letters long, thus outputting "no" when run from the interpreter; and crashes with a stack overflow if given a candidate word that isn't an infinity word, but which is five letters with the first and last two matching. (I'm not sure why it crashes; the recursive call should be treatable as a tailcall. Apparently GNU Prolog's optimizer isn't very good.) Succeeding is Prolog's equivalent of truthy, and failing the equivalent of falsey; a crash is definitely more falsey than truthy, and fixing it would make the solution substantially longer, so I hope this counts as a valid solution.

The algorithm is fairly simple (and indeed, the program is fairly readable); check whether the letters form one of the four patterns that make an infinity word, and if not, cyclicly permute and try again. We don't need to explicitly check for double letters as the < and > operators let us implicitly check that at the same time that we check that the deltas match.

# Actually, 38 27 bytes

This answer was largely inspired by Jonathan Allan's excellent Jelly answer. There are probably several places where this can be golfed, so golfing suggestions welcome! Try it online!

O;\♀-dY@♂s4R0~;11({kMíub*

Ungolfing

Implicit input s.
O    Push the ordinals of s. Call this ords.
;    Duplicate ords.
\    Rotate one duplicate of ords left by 1.
♀-   Vectorized subtraction. This effectively gets the first differences of ords.
d    Pop ord_diff[-1] onto the stack. This is ords[0] - ords[-1].
Y    Logical negate ord_diff[-1], which returns 1 if s[0] == s[-1], else 0.
@    Swap (s[0] == s[-1]) with the rest of ord_diff.

♂s       Vectorized sgn() of ord_diff. This gets the signs of the first differences.
4R       Push the range [1..4] onto the stack.
...M   Map the following function over the range [1..4]. Variable x.
0~;      Push -1 onto the stack twice.
11       Push 1 onto the stack twice.
(        Rotate x to TOS.
{        Rotate the stack x times, effectively rotating the list [1, 1, -1, -1].
k        Wrap it all up in a list.

Stack: list of rotations of [1, 1, -1, -1], sgn(*ord_diff)
í    Get the 0-based index of sgn(*ord_diff) from the list of rotations. -1 if not found.
ub   This returns 1 only if sgn(*ord_diff) was found, else 0.
This checks if the word loops like an infinity word.

*    Multiply the result of checking if the word s loops and the result of s[0] == s[-1].
Implicit return.

0=16|3⊥×2-/⎕a⍳⍞

Try it online!

# TI-BASIC, 81 bytes

String to pass into the program is in Ans. Returns (and implicitly displays) 1 if the entered word is an Infinity Word, and 0 (or exits with an error message) if it isn't.

seq(inString("ABCDEFGHIJKLMNOPQRSTUVWXYZ",sub(Ans,A,1)),A,1,length(Ans
min(Ans(1)=Ans(5) and {2,2}=abs(deltaList(deltaList(deltaList(Ans)/abs(deltaList(Ans

Errors on any repeated characters, or non-5-letter-words.

# 05AB1E, 16 bytes

Ç¥DO_s.±¥¥Ä2DиQ*

Explanation:

Ç             # Convert the (implicit) input string to a list of unicode values
#  i.e. "RULES" → [82,85,76,69,82]
¥            # Take the deltas
#  i.e. [82,85,76,69,82] → [3,-9,-7,13]
DO          # Duplicate and take the sum
#  i.e. [3,-9,-7,13] → 0
_         # Check if that sum is exactly 0
# (which means the first and last characters are equal)
#  i.e. 0 and 0 → 1 (truthy)
s            # Swap so the deltas are at the top of the stack again
.±          # Get the sign of each
#  i.e. [3,-9,-7,13] → [1,-1,-1,1]
¥         # Get the deltas of those signs
#  i.e. [1,-1,-1,1] → [-2,0,2]
¥        # And then get the deltas of those
#  i.e. [-2,0,2] → [2,2]
Ä       # Convert them to their absolute values
2Dи    # Repeat the 2 two times as list: [2,2]
Q   # Check if they are equal
#  i.e. [2,2] and [2,2] → 1 (truthy)
*            # Check if both are truthy (and output implicitly)
#  i.e. 1 and 1 → 1 (truthy)