[Question]
  [
Inspired by a discussion from the [Esolangs.org unofficial Discord Server.](https://discord.gg/3UXSK5p)
## Instructions
A chess cycle is an arrangement of a chess board where each piece *must* attack one other piece, and *only* one other piece, and each piece is attacked exactly once.
The effective idea to to "connect" pieces with each other, forming a single cyclic chain. Here is a board example:
[![enter image description here](https://i.stack.imgur.com/rkhKX.png)](https://i.stack.imgur.com/rkhKX.png)
**You will only be given boards with Knights, Rooks and Bishops.**
Your submission must take a chess board in any valid format(string, list of strings, 2D array, list of piece positions, FEN, ...) and output a truthy or falsy value for whether the board represents a valid cycle or not.
## Testcases
To create your own testcases, create your board [here](https://lichess.org/editor/), copy the FEN box contents, and use as input [here.](https://staxlang.xyz/#c=%27%2F%22%601%22R%22%5Cd%22%7Be%27+*%7DR%27+%27.R&i=1R4B1%2F3N4%2F3N4%2F3N1B2%2F8%2F2B2N2%2F4R1BB%2FR1N5)
FEN: `8/2B5/8/1N6/5N2/3B4/8/8`, [lichess](https://lichess.org/editor/8/2B5/8/1N6/5N2/3B4/8/8_w_-_-_0_1)
Board:
```
........
..B.....
........
.N......
.....N..
...B....
........
........
```
Output: `True` (In the illustration)
---
FEN: `8/8/8/3R4/8/8/8/8`, [lichess](https://lichess.org/editor/8/8/8/3R4/8/8/8/8_w_-_-_0_1)
Board:
```
........
........
........
...R....
........
........
........
........
```
Output: `False` (Rook cannot attack self)
---
FEN: `1R4B1/3N4/3N4/3N1B2/8/2B2N2/4R1BB/R1N5`, [lichess](https://lichess.org/editor/1R4B1/3N4/3N4/3N1B2/8/2B2N2/4R1BB/R1N5_w_-_-_0_1)
Board:
```
.R....B.
...N....
...N....
...N.B..
........
..B..N..
....R.BB
R.N.....
```
Output: `True`
---
FEN: `6B1/4N2N/5B2/8/8/6B1/4N2N/5B2`, [lichess](https://lichess.org/editor/6B1/4N2N/5B2/8/8/6B1/4N2N/5B2_w_-_-_0_1)
Board:
```
......B.
....N..N
.....B..
........
........
......B.
....N..N
.....B..
```
Output: `False` (Multiple Cycles)
---
FEN: `8/6R1/8/5R1N/3N4/8/5BB1/7N`, [lichess](https://lichess.org/editor/8/6R1/8/5R1N/3N4/8/5BB1/7N_w_-_-_0_1)
Board:
```
........
......R.
........
.....R.N
...N....
........
.....BB.
.......N
```
Output: `False` (Rook on f5 attacks two pieces)
---
FEN: `8/8/8/8/8/8/8/8`, [lichess(tsh)](https://lichess.org/editor/8/8/8/2R2R2/8/8/8/8_w_-_-_0_1)
Board:
```
........
........
........
........
........
........
........
........
```
Output: `False` (No pieces for a cycle)
---
FEN: `8/8/8/2R2R2/8/8/8/8`, [lichess(tsh)](https://lichess.org/editor/8/8/8/2R2R2/8/8/8/8_w_-_-_0_1)
Board:
```
........
........
........
..R..R..
........
........
........
........
```
Output: `True` (Two connected rooks, single cycle)
---
FEN: `8/8/8/1R3B2/8/3R2N1/8/8`, [lichess(Robin Ryder)](https://lichess.org/editor/8/8/8/1R3B2/8/3R2N1/8/8_w_-_-_0_1)
Board:
```
........
........
........
.R...B..
........
...R..N.
........
........
```
Output: `False`
## Other Info
* You may represent the pieces and empty squares as any number or character, as long as it is consistent.
* Given boards will always be 8x8 and valid i.e. not containing any invalid characters.
  
[Answer]
# [Wolfram Language](https://www.wolfram.com/language/), 259 bytes
```
o=DirectedEdges->True
i|->RelationGraph[(d=Abs[#1[[2]]-#2[[2]]];#1!=#2&&NoneTrue[i,RegionMember[Line[p={#1[[2]],#2[[2]]}]~RegionDifference~Point@p]@*Last]&&Switch[#1[[1]],r,Times@@d==0,b,Equal@@d,n,Sort@d=={1,2}])&,i,o]~IsomorphicGraphQ~CycleGraph[Length@i,o]
```
[Try it online!](https://tio.run/##xVDdbpswGL3nKVij0TZyxMxPgjRRMdZqmpShlvYO@YLAl2At2JkxiyZEHqJvsCfcI2QYUNqo95ssy8f2d853zlemsoAylTRLj0fu31IBmYT8Lt9ANbt5EjVo9M/z7xi2XQ1nX0S6K5Kr3P@0qpIJThKLkNnE6k/ycYLf@RPLMCLOQFETimLYdLRvUK5AJEvKINn5zUhEI7Elh6Hslq7XIIBlcLjnlMlgR4LpMq0kMYzHPZVZ0ffEHVWgJ1pCFQS5739AK3T3o0633Q0x9MiFVM8NRlZLrg1EESeHrxUvudgVNOszPBw@/8q2MORZAtvIIlB1x7X/Xr@a5hwqdin1PRffdcp0WdBKB/aTCs5KYBLpq1rqVOoZr7e5DtsK9kVnfXqtrf3/N7BkR/75xDRNuxeq94VnWqFreiaO5qYbWaYdOt3Nu5jdrJOmYaixkNu2qFmhxkaLETnIVqj7nSOnbVtCXuTUsuNe5JWQUCT3rBTHTohNO3LGjUPLVG6szoUT4zA0Yxy5L3yVc2iPByO9OWdE9gk5A@ptzkc0f2W4f@v0Fqdgi1OwBfLGXw/hkeEprvL9UFOQwVlQ7zzmm0FYcbfejgIP4j3yevHjXw "Wolfram Language (Mathematica) – Try It Online")
(uses [\[Function]](http://reference.wolfram.com/language/ref/character/Function.html) rather than `|->`, as TIO doesn't have the most recent version of the language)
Defines a function that takes in a list of piece positions as input, each in the form `{piece, {row, column}}` where piece is one of `r`, `b`, or `n`.
Un-golfed explanation:
```
i|->
IsomorphicGraphQ[                (*check if the following graphs are equivalent*)
  CycleGraph[Length[i], DirectedEdges -> True],
                                 (*cyclic graph with length of input*)
  RelationGraph[                 (*graph defined by a functional relation*)
    (d = Abs[#1[[2]] - #2[[2]]]; (*set `d` to absolute difference in coordinates*)
    #1 != #2 &&                  (*no pieces attack themselves*)
    NoneTrue[i,                  (*no other pieces are...*)
      RegionMember[RegionDifference[Line[p = {#1[[2]], #2[[2]]}], Point[p]]] @* Last
    ] &&                         (*between these two pieces*)
    Switch[First @ #1,           (*switch by attacking piece*)
      r, Times @@ d == 0,        (*rooks attack when one coordinate offset is zero*)
      b, Equal @@ d,             (*bishops attack when both offsets are equal*)
      n, Sort[d] == {1, 2}]      (*knights attack when one offset is 1 and the other is 2*)
    )&, i, DirectedEdges->True], (*apply to list of pieces*)
]&
```
[Answer]
# JavaScript (ES6), 241 bytes
Expects a list of triplets `(x,y,p)`, where \$(x,y)\$ are the coordinates of the piece and \$p\$ is its type (\$0\$, \$1\$ or \$2\$ for bishop, knight or rook respectively).
Returns \$0\$ or \$1\$.
```
a=>(g=(i,n,k)=>i>=0?m^(m|=1<<i)?a.map(([X,Y],j)=>(h=([x,y,t]=a[i],X-=x)*X)|(v=(Y-=y)*Y)&&![h-v,h+v-5,h*v][t]&a.every(([p,q])=>(S=Math.sign)(p-=x)-S(X)|S(q-=y)-S(Y)|(p*=p)+(q*=q)<1|[p-q,1][t]|p>=h&q>=v)?k=1/k?-1:j:0)|g(k,-~n):!i&!a[n]:0)(m=0)
```
[Try it online!](https://tio.run/##pZBNb9pAEIbv/hULB2eGrBc49EJZI1lKbnUl0wPIcaWVWfCC8TcWVmn/OrX5SICQKlItSzvzzjvPzs5SlCL3M5UURhTP5H7O94KbsOCgaERXyE1l8t5o/RPWO94fDhWOBFuLBMCd0KlHl7UDAg7ulla08LhwlUcnBt9iZ4I7KDlMDV5hZ4q63nIDo6TBY2l8oUGn9NzC0wWTpcyqGpfQ1GtgY/5NFAHL1SJCSBqSMYaaNYa0IdXJtAYnHZ7gI6QdnuKwv3MTI6X9hrhLTB7oqclLHK14v7saGf3BctDD3QJW1PgT4aCl9JZwI68WYc17uM9kulGZhId5/oAsk2L2rEI5riIfesiKeFxkKloAsjwJVQHtl@glaiObx9mT8APICTfJL42QUBZEEE5c72ud5W/2CzNklFTYdLiMscx7K/iUbA8Fn7Q4abM20XUiWLLJg2a9pKKkbdlOm6loJrff5@Cjh4jNVX4c5XEoWRgvYA6iEX@jpnW75GmbSL@opx@QH9lGUvIswrw@rpLr46K0Z6dPY8w6B2fFZheKfQysG885uCNdBs7HpXegg9c6SPa5dhFY123W62h1o2Vpzmns80RHUCPa2kn4@P675luTc9vmHN32HaJlvSq29qn3f25H/zI5h///Qc6dZTnNM9@b/wI "JavaScript (Node.js) – Try It Online")
## How?
### Algorithm
We recursively walk through the input list of \$N\$ entries by going from a piece \$A\$ to a piece \$B\$ attacked by \$A\$. We test whether we eventually go back to the starting piece in \$N\$ iterations.
Furthermore, we force the search to stop and the test to fail if:
* we reach a piece that was already visited and is not the starting one (e.g. a mutual attack between 2 rooks which would result in an infinite loop)
* we detect than any piece attacks more than one piece
### Attacks
Given two pieces \$A\$ and \$B\$ at positions \$(x\_A,y\_A)\$ and \$(x\_B,y\_B)\$, we compute \$dx=x\_A-x\_B\$ and \$dy=y\_A-y\_B\$.
As illustrated below, the piece \$A\$ attacks \$B\$ if:
* \$A\$ is a rook and we have either \$dx^2=0,\:dy^2>0\$ or \$dx^2>0,\:dy^2=0\$
* \$A\$ is a bishop and \$dx^2=dy^2\$
* \$A\$ is a knight and \$dx^2+dy^2=5\$
[![attacks](https://i.stack.imgur.com/8bTEO.png)](https://i.stack.imgur.com/8bTEO.png)
For rooks and bishops, we also have to make sure that there is no piece in between on the same ray. This is the weak point in this piece-oriented approach, as the corresponding code (the `a.every()`) is pretty long.
## Commented
```
a => (                         // a[] = list of pieces
  g = (i, n, k) =>             // g is a recursive function taking an index i and
                               // a number of moves n
  i >= 0 ?                     // if i is a non-negative number:
    m ^ (m |= 1 << i) ?        //   set the i-th bit in m; if it was not already set:
      a.map(([X, Y], j) =>     //     for each piece (X, Y) at position j in a[]:
        ( h = (                //       load the position (x, y) and the type t
            [x, y, t] = a[i],  //       of the i-th piece
            X -= x             //       set: X = X - x, h = X²
          ) * X                //            Y = Y - y, v = Y²
        ) | (v = (Y -= y) * Y) //       abort if both h and v are equal to 0
        && ![ h - v,           //       bishop: we must have h = v
              h + v - 5,       //       knight: we must have h + v = 5
              h * v            //       rook  : we must have either h = 0 or v = 0
        ][t] &                 //
        a.every(([p, q]) =>    //       make sure that there is no closer piece (p, q)
          (S = Math.sign)      //       that blocks the capture, which is not the case:
          (p -= x) - S(X)      //         if it's not in the same direction
          | S(q -= y) - S(Y)   //         
          | (p *= p) +         //         or it's the capturing piece itself
            (q *= q) < 1       //         
          | [p - q, 1][t]      //         or the capture types do not match
          | p >= h & q >= v    //         or it's not blocking because it's further
        ) ?                    //       end of every(); if all tests pass:
          k = 1 / k ? -1 : j   //         update k to j, or -1 if it's already set
        :                      //       else:
          0                    //         do nothing
      ) |                      //     end of map()
      g(k, -~n)                //     do a recursive call with i = k and n + 1
    :                          //   else:
      !i & !a[n]               //     this is a full cycle if i = 0 and n = a.length
  :                            // else:
    0                          //   abort
)(m = 0)                       // initial call to g with i = m = 0
```
[Answer]
# [Python 3](https://docs.python.org/3/), ~~343~~ ~~335~~ ~~334~~ 327 bytes
-8 thanks to [@ovs](https://codegolf.stackexchange.com/users/64121/ovs)
A function that takes two inputs: a list of piece types and a list of piece coordinates.
Piece types:
* Rook: `1`
* Bishop: `2`
* Knight: `3`
Coordinates are given in the format:
`21 + y * 10 + x`
Coordinate format inspired by [sunfish](https://github.com/thomasahle/sunfish).
Returns `True` for true and `None` or `False` for false.
I haven't heavily tested it yet, please let me know if it fails on a test case.
```
m={1:[1,10],2:[11,9],3:[19,21,12,8]}
def f(p,c):
 x=0
 for y in c:
  q=p[x];w=m[q]+[-i for i in m[q]];a=[]
  for d in w:
   for i in range(1,9):
    z=c[x]+i*d
    if z<20|z>99|z%10%9<1|z in c:a+={*c}&{z};break
  if q>2:a=[x+i for i in w if x+i in c]
  if len(a)-1|0**x&y-c[0]:return
  x=c.index(a[0])
 return len(p)>x<1
```
[Try it online!](https://tio.run/##TZDLboMwEEX3fMVsEtlgKuxIVXiYH7G8cHm0VhsHEBUGmm@ntrNodzPn3jszmmGdP@7mchw3vtNCUEIzSZgrKMklubgiJ8xRRq7yEbVdDz0aSIOLCCzPIujvE6ygDTSOwMgHYWW58JsYZSJSHXTtdU9kqbiQzudp6@niU3@mSZn3DrnVOHDYeOPmJTpuQ6t7UGZFYqtYRrY6z8l2otkpryjZwg0SFyrhe9w8zvv2KN@mTn1GITfWrHDLbfLvpMULnoTo0/fVGaRwSn@yOLbnNW1EJoupm78n4wyWNy/atJ1FynEcwVMJqQHXtqLHMGkzox65VwKVBAR7JcCuEuPjFw)
## Explanation
A crucial observation is that if each piece attacks one other and after n moves we are back on the original piece, then there exists a cycle.
```
# A list of move directions for each piece. +-10 is vertical and +-1 is horizontal
# Only positive numbers, to save bytes
m={1:[1,10],2:[11,9],3:[19,21,12,8]}
def f(p,c):
    # A variable representing the current piece index
    x=0
    # It is a cycle if and only if after n moves, we arrive back at the original piece. (n is number of pieces)
    for y in c:
        # Values used multiple times
        q=p[x]
        w=m[q]+[-i for i in m[q]]
        # List of attacks of current piece
        a=[]
        # Movement of bishops and rooks: keep going in each direction
        for d in w:
            for i in range(1,9):
                z=c[x]+i*d
                # Check for out of bounds or landing on another piece
                if any([z<20,z>99,z%10%9<1,z in c]):a+={*c}&{z};break
        # Knight moves
        if q>2:a=[x+i in c for i in w if x+i in c]
        # Does it only attack one piece? Does it end up at the start too early?
        if len(a)-1|0**x&y-c[0]:return
        # Move to next piece
        x=c.index(a[0])
    return len(p)>x<1
```
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~55~~ 54 bytes
```
_þ`;"JṖẸ$ƇAṖṢJƑƲƇṭ¬Ẹ$Ƈ,ṖAEƊƇƊƊƲ€ị@"ṠAṂṪƊƙ$€µF0ịƬL’=L×Ẹ
```
[Try it online!](https://tio.run/##XU7LSsNAFN3nK0rJsnIzk4eB4KMDZlHKLGYhuNJNF0o/QHehm0Bc6UItKIoKQombotCx0EWD8x@TH4l3YogPZu7Mueece2ZORuPxWVUdFqujqDvQ8kp/LGyV9g2SjwN1oeYq1fJ1nX8LPRT6eypTKVam5uUk18vz3a6WDzgz0XKG7NRGev0eOyipfFgm061hcY0B1eelljdRmdx2NrY7ZXIXFS9gafmEEPadU5WhJBjH9tgehULLlUl6tnfwwh1jmYhZL9aLe8d8oUitP3mppZdvRYrGg6oKgTIfQiA8AJ9TcJmHXWiF5gRX1F3NEOExAi73miKMgpmmOOUJwhgIwn0rQJPHKQe/1kP4TWBsIAiSPnrrHIQMDZu8ebFdTU8Frn8cEW6d7QrKScv/OFv0BQ "Jelly – Try It Online")
A dyadic link taking two arguments. The left argument is a list of co-ordinates of the pieces. The right argument is a list of the piece types corresponding to those co-ordinates, with 1=rook, 2=bishop, 3=knight. The result is 1 for true and 0 for false.
The TIO link includes a footer that starts with newline-separated FEN notation and for each one, converts them to the desired input format and then calls the main program.
Rewritten to work using co-ordinate arithmetic for bishops and rooks rather than splitting rows, columns and diagonals, and saving 11 bytes in the process.
---
## Original version:
# [Jelly](https://github.com/DennisMitchell/jelly), ~~75~~ 66 bytes
```
fƇ⁹ḟ0ṣṪḢƭ€ʋ€Fḟ0
ŒṬFÄṁ×Ʋ;Z,ŒD;ŒdƊƲçþJ
ạṢ⁼Ø½ʋþ`T€ṭ"Ç0F?Ʋị@"µF0ịƬL’=L
```
[Try it online!](https://tio.run/##XU49SwNBEO33V4SQMjK3e3fx4NDIIldI2GIRQSsLIyj5AdolIhwkXRojKGIUAiFpgkLWaIos2SL/Yu@PnHNHiB8MMzvz5s3bd1lvNK7T9NzESUvZ6ZNj1YtVQzvtm3FyM1p1sEQZTpZdq0aRvrWqpe/MJDwpL7v74bJ7Ztpmogd6fkDsx7NV/aT1qXuLr1VHz08P8dyqcVHHTlQ1Ezvr7BUX75GDjRnVkub9Ti3NhHth0nwobO0WkuZjqAdA0Aa2cORcmTauJBc4XpTqgbRqjqKL11IVn8wdZiYxLOc@0U1bx@SPXkzs7E3HSDxO0wAY9yEAKirgCwYu93AKSJBVcGU@5QiVHqfgCm@dlDPIrhleeZJyDpIKn1SQ5AkmwM/3AfwGULYiKYI@cnMdbDkStsX6x02sZyYx/mFUurm2K5mgG/yHuem@AQ "Jelly – Try It Online")
## Explanation
### Link 1
* takes a list of lists as its left argument x
* takes an integer as its right argument y
* returns a list of the integers found to the left and right of y in members of x containing y, filtering out zeros
```
 Ƈ              | Keep those lists which:
f ⁹             | - contain y
          ʋ€    | For each of these:
   ḟ0           | - Exclude zeros
     ṣ          | - Split at y
      ṪḢƭ€      | - Take the tail of the first part and head of the second (note will return 0 if nothing there)
            F   | Flatten
             ḟ0 | Exclude zeros
```
## Link 2
* takes a list of lists of co-ordinates as its only argument
* returns a list of lists of the attacked pieces for each, first assuming each piece is a rook and then assuming each is a bishop
```
ŒṬ                   | Multidimensional untruthy (recreate the board as 1s and 0s)
      Ʋ              | Following as a monad with argument z:
  F                  | - Flatten
   Ä                 | - Cumulative sum
    ṁ                | - Mould like z
     ×               | - Multiply by z (restoring zeros)
                Ʋ    | Following as a monad with argument w:
       ;             |   - w concatenated to:
        Z            |   - Transpose of w
         ,     Ɗ     | - Paired with following as a monad:
          ŒD         |   - Diagonals of w
            ;        |   - Concatenated to
             Œd      |   - Antidiagonals of w
                 çþJ | Call link 1 for each member of this list using each of a sequence of integers from 1 to the length of the original argument of link 2
```
### Main link
* takes a list of the coordinates of pieces on the board as its left argument x
* takes a list of piece types as its right argument y
* returns 1 if there is a chess cycle and 0 if not
```
                Ʋ             | Following as a monad:
     ʋþ`                      | - Following as a dyad for each possible pairing of co-ordinates:
ạ                             |   - Absolute difference
 Ṣ                            |   - Sort
  ⁼Ø½                         |   - Equals [1,2] (i.e. a knight’s move)
        T€                    | - Truthy indices of each
          ṭ"                  | - Tag each onto the corresponding list in the following:
              F?              |   - If the original list of coordinates is not empty when flattened:
            Ç                 |     - Then call link 2 using the original co-ordinate list as its argument
             0                |     - Else a literal 0
                              | By this point we have a list of length-3 lists, one for each original set of co-ordinates. The first member corresponds to attacked pieces as a bishop, the second as a rook and the third as a knight
                 ị@"          | Index into each list using the type of piece
                    µ         | Start a new link as a monad
                     F        |   - Flatten
                      0ịƬ     |   - Starting with the last member, index into the list of attacks until we reach a piece we’ve seen before, preserving all of the intermediate steps
                         L    |   - Length of this
                          ’   | Subtract 1
                           =L | Is equal to the number of pieces
```
]