Find the Infinity Words!

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

-7 bytes thanks to fireflame241 (0ị=1ị$->=ṚḢ and use of IIA⁼2,2 to test for the 4 rotations)

-1 Thanks to Kevin Cruijssen (use of previously unavailable nilad Ø2 which yields [2,2])

=ṚḢȧOIṠIIA⁼Ø2

TryItOnline
Or all test cases (plus "RULES")

How?

An infinity word has:

  1. the same first and last letter;
  2. length 5;
  3. no equal letters next to each other;
  4. sum of its four alphabet deltas equal to zero;
  5. sum of its four alphabet deltas signs equal to zero;
  6. two positive alphabet deltas or two negative alphabet deltas in a row.

All but (1) and (equivalently) (4) may be boiled down to a condition that the alphabet delta signs are some rotation of [1,1,-1,-1] (where the sign of 0 is 0)

fireflame241 noted that this is then equivalent to the deltas of the deltas of the alphabet delta signs being in [[2,2],[2,-2],[-2,2],[-2,-2]] which may be tested by the absolute values being equal to [2,2]!

How?

=ṚḢȧOIṠIIA⁼Ø2 - Main link: word
 Ṛ            - reverse word
=             - equals? (vectorises)
  Ḣ           - head (is the first character equal to the last?)
   ȧ          - and
    O         - cast word to ordinals
     I        - increments - the alphabet deltas (or just [] if 1st != last)
      Ṡ       - sign (vectorises)
       I      - increments - deltas of those signs
        I     - increments - deltas of those
         A    - absolute value (vectorises)
           Ø2 - literal [2,2]
          ⁼   - equals? (non-vectorising version)

Java 8, 231 193 185 122 103 78 bytes

s->s.length==5&&(s[1]-s[0])*(s[3]-s[2])<0&(s[2]-s[1])*(s[4]-s[3])<0&s[4]==s[0]

Try it here.

-38 bytes thanks to @dpa97 for reminding me to use char[] instead of String.
-63 bytes thanks to @KarlNapf's derived formula.
-25 bytes by converting it from Java 7 to Java 8 (and now returning a boolean instead of integer).

193 bytes answer:

int c(char[]s){if(s.length!=5)return 0;int a=s[0],b=s[1],c=s[2],d=s[3],e=s[4],z=b-a,y=c-b,x=d-c,w=e-d;return e!=a?0:(z>0&y>0&x<0&w<0)|(z<0&y>0&x>0&w<0)|(z>0&y<0&x<0&w>0)|(z<0&y<0&x>0&w>0)?1:0;}

Explanation:

  • If the length of the string isn't 5, we return false
  • If the first character doesn't equal the last character, we return false
  • Then we check the four valid cases one by one (let's indicate the five characters as 1 through 5), and return true if it complies to any of them (and false otherwise):
    1. If the five characters are distributed like: 1<2<3>4>5 (i.e. ALPHA)
    2. If the five characters are distributed like: 1>2<3<4>5 (i.e. EAGLE, HARSH, NINON, PINUP)
    3. If the five characters are distributed like: 1<2>3>4<5 (i.e. RULER)
    4. If the five characters are distributed like: 1>2>3<4<5 (i.e. THEFT, WIDOW)

These four rules can be simplified to 1*3<0 and 2*4<0 (thanks to @KarlNapf's Python 2 answer).


JavaScript (ES6), 91 89 87 bytes

Saved 2 bytes thanks to Ismael Miguel

s=>(k=0,[...s].reduce((p,c,i)=>(k+=p>c?1<<i:0/(p<c),c)),k?!(k%3)&&!s[5]&&s[0]==s[4]:!1)

How it works

We build a 4-bit bitmask k representing the 4 transitions between the 5 characters of the string:

k += p > c ? 1<<i : 0 / (p < c)
  • if the previous character is higher than the next one, the bit is set
  • if the previous character is lower then the next one, the bit is not set
  • if the previous character is identical to the next one, the whole bitmask is forced to NaN so that the word is rejected (to comply with rule #6)

The valid bitmasks are the ones that have exactly two consecutive 1 transitions (the first and the last bits being considered as consecutive as well):

Binary | Decimal
-------+--------
0011   | 3
0110   | 6
1100   | 12
1001   | 9

In other words, these are the combinations which are:

  • k? : greater than 0
  • !(k%3) : congruent to 0 modulo 3
  • lower than 15

The other conditions are:

  • !s[5] : there's no more than 5 characters
  • s[0]==s[4] : the 1st and the 5th characters are identical

NB: We don't explicitly check k != 15 because any word following such a pattern will be rejected by this last condition.

Test cases

let f =

s=>(k=0,[...s].reduce((p,c,i)=>(k+=p>c?1<<i:0/(p<c),c)),k?!(k%3)&&!s[5]&&s[0]==s[4]:!1)

console.log("Testing truthy words...");
console.log(f("ALPHA"));
console.log(f("EAGLE"));
console.log(f("HARSH"));
console.log(f("NINON"));
console.log(f("PINUP"));
console.log(f("RULER"));
console.log(f("THEFT"));
console.log(f("WIDOW"));

console.log("Testing falsy words...");
console.log(f("CUBIC"));
console.log(f("ERASE"));
console.log(f("FLUFF"));
console.log(f("LABEL"));
console.log(f("MODEM"));
console.log(f("RADAR"));
console.log(f("RIVER"));
console.log(f("SWISS"));
console.log(f("TRUST"));
console.log(f("KNEES"));
console.log(f("QUEEN"));
console.log(f("ORTHO"));
console.log(f("GROOVE"));
console.log(f("ONLY"));
console.log(f("CHARACTER"));
console.log(f("OFF"));
console.log(f("IT"));
console.log(f("ORTHO"));

Initial version

For the record, my initial version was 63 bytes. It's passing all test cases successfully but fails to detect consecutive identical characters.

([a,b,c,d,e,f])=>!f&&a==e&&!(((a>b)+2*(b>c)+4*(c>d)+8*(d>e))%3)

Below is a 53-byte version suggested by Neil in the comments, which works (and fails) equally well:

([a,b,c,d,e,f])=>!f&&a==e&&!((a>b)-(b>c)+(c>d)-(d>e))

Edit: See Neil's answer for the fixed/completed version of the above code.