Is My Swipe Pattern Legal? Most Android smartphones allow the user to use a swipe pattern to open their phone:



Certain patterns are legitimate, and others are impossible. Given an input swipe pattern, return a truthy or falsy indicating if the given input pattern is legal or not. 

Input

The grid is labelled row-wise 1 through 9:  

1 2 3   
4 5 6   
7 8 9


The input is a number comprised of the nodes visited from first to last. For example, the swipe pattern above is 12357.

Input can be a decimal number, string or list of numbers. It will not contain 0 because there is no node 0.

Amendment: indexing 0-8 is allowed since a lot of languages index from 0. If you use 0-8, it'll be necessary to indicate as such at the beginning of your answer and adjust the test cases accordingly.

Rules


Every node starts as unvisited initially and may only be visited once. Any pattern which visits a node more than once is falsy.
A truthy pattern must contain at least one swipe, so a minimum of 2 nodes.
It's not possible to skip over an unvisited node directly in line with another.
For example, 13 is falsy because 2 is unvisited and directly in line. 
It is only possible to skip over a visited node. 42631 is an example of this. 
Lines may cross otherwise. For example, 1524 is truthy. 
Assume node widths are insignificant and ignore practical issues (finger thickness, etc). So 16 is truthy even though it may be slightly harder to achieve in reality.


Test Cases

1 -&gt; false     
12 -&gt; true   
13 -&gt; false   
16 -&gt; true  
31 -&gt; false   
33 -&gt; false  
137 -&gt; false   
582 -&gt; true  
519 -&gt; true  
1541 -&gt; false  
12357 -&gt; true    
15782 -&gt; true   
19735 -&gt; false  
42631 -&gt; true   
157842 -&gt; true  
167294385 -&gt; true   
297381645 -&gt; false   
294381675 -&gt; true


This is code-golf, so the fewest number of bytes wins.
JavaScript (ES6), 64 bytes

Takes input as an array of numbers. Falsy values are 0 or NaN. Truthy values are strictly positive integers.

a=&gt;a[p=1]*a.every(n=&gt;a[p=a[n&amp;p&amp;p*n%5&lt;0|~(p-=n)==9&amp;&amp;p/2]&amp;&amp;-n]^=p)


Test cases



let f =

a=&gt;a[p=1]*a.every(n=&gt;a[p=a[n&amp;p&amp;p*n%5&lt;0|~(p-=n)==9&amp;&amp;p/2]&amp;&amp;-n]^=p)

console.log('[Truthy]')
console.log([
  [1,2],
  [1,6],
  [5,8,2],
  [5,1,9],
  [1,2,3,5,7],
  [1,5,7,8,2],
  [1,6,7,2,9,4,3,8,5],
  [4,2,6,3,1],
  [1,5,7,8,4,2],
  [2,9,4,3,8,1,6,7,5]
]
.map(f).join(' '))

console.log('[Falsy]')
console.log([
  [1],
  [1,3],
  [3,1],
  [3,3],
  [1,3,7],
  [1,5,4,1],
  [1,9,7,3,5],
  [2,9,7,3,8,1,6,4,5]
]
.map(f).join(' '))




How?

Preamble

Two digits are vertically, horizontally or diagonally opposed if:


they are both odd, different from each other and different from 5 (figure 1)
OR they are both even and their sum is 10 (figure 2)




Besides, the digit standing between two opposed digits n and p is equal to (n + p) / 2.

Formatted source code

a =&gt;
  // force a falsy result if a[1] is undefined
  a[p = 1] *
  // walk through all values n in a[]
  a.every(n =&gt;
    // access either a[-n] or a[undefined]
    a[
      // set p to either -n or undefined
      p =
        // read either a[0] or a[in_between_digit]
        a[
          n &amp; p &amp; p * n % 5 &lt; 0 | ~(p -= n) == 9
          &amp;&amp; p / 2
        ]
        &amp;&amp; -n
    ]
    // toggle the flag
    ^= p
  )


Keeping track of previous digits

Flags for visited digits are stored at negative indices in the input array a, so that they don't collide with its original elements.


If p is set to -n:

If the current digit n was not previously selected, a[-n] ^= -n will set the flag and let the every() loop go on with the next iteration. Otherwise, it will clear the flag and force the loop to fail immediately.
If p is set to undefined:

a[undefined] ^= undefined results in 0, which also forces the loop to fail.


Detecting opposed digits

The following expression is used to test whether the current digit n and the previous digit -p are opposed digits, as defined in the preamble:

n &amp; p &amp; ((p * n) % 5 &lt; 0) | ~(p -= n) == 9


which is equivalent to:

n &amp; p &amp; ((p * n) % 5 &lt; 0) | (p -= n) == -10


Note: In JS, the result of the modulo has the same sign as the dividend.

It can be interpreted as:

(n is odd AND -p is odd AND (neither -p or n is equal to 5)) OR (n + -p = 10)


Therefore, this expression returns 1 if and only if n and -p are opposed digits or they are the same odd digit. Because a digit can't be selected twice, this latter case is correctly taken care of anyway.

If this expression returns 1, we test a[p / 2] (where p is now equal to the negated sum of the digits) in order to know whether the 'in-between digit' was previously visited. Otherwise, we test a[0] which is guaranteed to be truthy.

About the first iteration

The first iteration is a special case, in that there is no previous digit and we want it to be unconditionally successful.

We achieve that by initializing p to 1, because for any n in [1 .. 9]:


(1 * n) % 5 can't be negative
~(1 - n) can't be equal to 9




Original answer, 90 bytes

Removed from this post so that it doesn't get too verbose. You can see it here.