Working on my Knight moves Hexagonal chess describes a family of chess variants played on a board where the cells are hexagons instead of the traditional squares. There are many such variants; in this challenge we'll be focusing on Gliński's variant, which is the most common.

The board is composed of three colors (so that the same color doesn't share an edge), with the edges of the hexagons facing the players. The board has 11 files, marked by letters a through l (letter j is not used), and 11 ranks (which bend 60° at file f). Ranks 1 through 6 each contain 11 cells, rank 7 has 9 cells, rank 8 has 7, and so on. Rank 11 contains exactly one cell: f11. (If it helps, think of each rank as making a very wide "V" shape.)

Here is an example picture of the board, with the knight on the center cell. The cells marked with a dot are the legal moves of this particular knight. The knight moves in a similar fashion to "normal" chess, two-down-and-one-over. In hexagonal chess terms, it's an orthogonal move (across an edge), then a diagonal move in the same direction (the closest move to the same color). For example with the knight below, an orthogonal move "up" to the light brown is then accompanied by a diagonal move "up and right" or "up and left" to the nearest light brown.



From the public domain via https://commons.wikimedia.org/wiki/File:Glinski_Chess_Knight.svg

This knight is positioned at f6 and the legal moves are thus

c4, c5, d3, d7, e3, e8, g3, g8, h3, h7, i4, i5


Input

A single input giving the starting cell of our knight. This can be as a single string "b6", as two strings, "b", "6", etc., in any convenient format. The input letters can be uppercase or lowercase -- your choice.

Output

A list of the valid moves that a knight on that location can make. This can be as an array of strings, a single string with an unambiguous and consistent delimiter, separate strings by newlines, etc., whatever is most convenient. The output does not necessarily need to be in sorted order, and can be in either uppercase or lowercase -- your choice.

Rules


Assume no other pieces are on the board or interfere with the moves. We're focusing on just the knight.
Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
If possible, please include a link to an online testing environment so other people can try out your code!
Standard loopholes are forbidden.
This is code-golf so all usual golfing rules apply, and the shortest code (in bytes) wins.


Examples

b6
a3, c4, d5, d9, e7, e8

f6
c4, c5, d3, d7, e3, e8, g3, g8, h3, h7, i4, i5

f11
d8, e8, g8, h8

i1
f2, f3, g4, h4, l2, k3
JavaScript (ES6), 184 bytes

Takes the file F as a character and the rank R as an integer in currying syntax (F)(R). Returns an array of strings.

F=&gt;R=&gt;[...'100124566542'].map((X,i)=&gt;(X-=3-(x=(s='abcdefghikl').search(F)))-7&lt;(Y=('9641001469'[i]||10)-(A=Math.abs)(x-5)+17-2*R)&amp;X+Y&gt;3&amp;X+16&gt;Y&amp;X+Y&lt;27&amp;&amp;s[X]+(22-Y-A(X-5))/2).filter(n=&gt;n)


How?

Step #1: convert file/rank to Cartesian coordinates

We convert the hexagonal chess coordinates to Cartesian coordinates (x, y) with x in [0 .. 10] and y in [0 .. 20]:

      00 01 02 03 04 05 06 07 08 09 10
   +----------------------------------
00 |                f11                     F = file (letter)
01 |             e10   g10                  R = rank in [1 .. 11]
02 |          d09   f10   h09               
03 |       c08   e09   g09   i08            F | a b c d e f g h i k l
04 |    b07   d08   f09   h08   k07         --+-----------------------
05 | a06   c07   e08   g08   i07   l06      x | 0 1 2 3 4 5 6 7 8 9 10
06 |    b06   d07   f08   h07   k06         
07 | a05   c06   e07   g07   i06   l05      y = 22 - |x - 5| - 2R
08 |    b05   d06   f07   h06   k05   
09 | a04   c05   e06   g06   i05   l04
10 |    b04   d05   f06   h05   k04   
11 | a03   c04   e05   g05   i04   l03
12 |    b03   d04   f05   h04   k03   
13 | a02   c03   e04   g04   i03   l02
14 |    b02   d03   f04   h03   k02   
15 | a01   c02   e03   g03   i02   l01
16 |    b01   d02   f03   h02   k01   
17 |       c01   e02   g02   i01      
18 |          d01   f02   h01         
19 |             e01   g01            
20 |                f01               


Step #2: apply the move vectors

Below is the list of the move vectors in the Cartesian system:

(-2, +4), (-1, -5), (+3, +1),
(-3, +1), (+1, -5), (+2, +4),
(-3, -1), (+2, -4), (+1, +5),
(-2, -4), (+3, -1), (-1, +5)


We apply each of them to the source coordinates (x, y) and get a list of target coordinates (X, Y).

Step #3: test the target coordinates

We now need to check which target coordinates are actually located inside the board. This is done by testing X + Y and X - Y:



The coordinates are valid if all the following comparisons are true:


X + Y > 3
X + Y &lt; 27
X - Y &lt; 7
X - Y > -17


We should also verify that X is in [0 .. 10]. This is not done explicitly because s[X] is undefined if it's not, which eventually results in a falsy value that gets filtered out.

Step #4: convert back to hexagonal chess coordinates

Finally the valid target coordinates are converted back to hexagonal chess coordinates, using the inverse of the formulas described at step #1.

Test cases



let f =

F=&gt;R=&gt;[...'100124566542'].map((X,i)=&gt;(X-=3-(x=(s='abcdefghikl').search(F)))-7&lt;(Y=('9641001469'[i]||10)-(A=Math.abs)(x-5)+17-2*R)&amp;X+Y&gt;3&amp;X+16&gt;Y&amp;X+Y&lt;27&amp;&amp;s[X]+(22-Y-A(X-5))/2).filter(n=&gt;n)

console.log(JSON.stringify(f('b')(6)))
console.log(JSON.stringify(f('f')(6)))
console.log(JSON.stringify(f('f')(11)))
console.log(JSON.stringify(f('i')(1)))